Repository navigation
Releases
Plombir Git v0.4.2
Plombir Git v0.4.2
This security maintenance release strengthens credential-change transactions,
Git HTTP authorization after uploads, private-fork pull requests and automated
merging. It also restricts draft-release visibility and includes push-mirror
credentials in encryption-key checks and rotation.
Dependencies include rustix 1.1.6, fixing
RUSTSEC-2026-0486,
and the matching xattr 1.7.0 update to preserve extended-attribute reads.
Before upgrading
Back up the database, repository storage, configuration and encryption key.
Upgrade frontend and backend together using the release bundle or a build from
the release tag. There are no new database migrations relative to v0.4.1.
Installations upgrading from an older release must also follow the
v0.4.1 notes and, when applicable, the
v0.4.0 notes; an intermediate deployment is not required.
Previous encryption-key rotations: if you rotated the key on v0.4.1 or
earlier and use push mirrors, retain the original key. Earlier versions could
leave push-mirror passwords encrypted with it. Stop every server process and
follow the recovery procedure using the
fixed binary, the original key as --old and the current configured key as
--new. Inspect --dry-run before applying: push_mirrors.password_encrypted
must be listed, and values already encrypted with the current key are counted
as already_new and left unchanged. Without the original key, re-enter the
affected mirror credentials; ciphertext alone cannot recover them.
Accounts and authentication
- Deactivating an account revokes existing sessions and pending address-change
links. Reactivation does not restore them. PATs, SSH keys and passkeys remain
suspended while inactive and can be used again after reactivation. - Password changes/resets and operator factor resets cancel pending
account-email changes atomically. Address changes consume their link in the
same transaction and invalidate reset links for the previous address;
in-flight issuance cannot recreate a link from stale account state. - Operator factor resets revoke sessions, TOTP material, unused backup codes,
passkeys and pending address changes together with their notifications.
A passkey ceremony already in flight cannot finish against the new account
generation. - Password-only verification does not clear second-factor failures. Successful
reauthentication clears counters only while the completed proof still
matches the account, credentials and lockout state. - Session revocation, account-standing and identity-conflict checks apply to
every supported Authorization format, including Cargo's raw credential form.
The fresh-proof requirements introduced in v0.4.1 remain in force.
Repository access and pull requests
Positive repository permission decisions are no longer cached. Subsequent
checks observe revocation across database pools and server processes, at the
cost of fresh indexed grant queries. Repeated refusals are cached for at most
five seconds, so a grant made through another pool may take that long to appear.
Git HTTP fetch and push recheck the credential, account, repository identity
and access after receiving the request body. Push also reloads branch/tag,
mirror and token restrictions. Work admitted after that check can still finish
if access is revoked later; this is not an atomic barrier around running Git
processes. LFS, SSH and registry upload lifetimes are separate contracts.
The author of a PR from a private fork must retain write access to that source.
Revocation, a downgrade to reader, deactivation or removal of the source freezes
updates and blocks CI and merging. Existing PRs opened with read-only source
access also freeze after upgrading. Previously fetched snapshots remain
readable while their objects are retained, with a source-unavailable notice;
missing snapshots return 409 head_source_unavailable. Already copied objects
are not erased. Public-fork and same-repository PRs keep their existing source
access behavior.
Merge-queue and auto-merge operations require explicit approval of the current
fork head by an active human with write access to the base repository, even
without a CI workflow. Enqueueing is not approval. A new head or revoked
approver requires fresh approval; a previous successful pipeline does not
replace the check. Failed queue entries must be approved and enqueued again.
Auto-merge waits for approval, and cancellation cannot be undone by a late
background recovery. See fork CI behavior and the
precise access boundaries.
Visibility and namespace changes
Draft releases, notes, assets and attestations are visible only to repository
writers. Other readers receive the same 404 as for missing resources, and
lists and totals omit drafts. A CI job token alone does not grant draft access;
workflows reading drafts need an authorized writer credential. All release
reads, including published public downloads, now use private, no-store.
Configured webhooks remain trusted integrations and still receive existing
release.created metadata for drafts.
Organization visibility accepts only public or private; an invalid PATCH
changes no fields. Historical unknown values are member-only and produce a
startup warning so owners can correct them. Creating organizations or bots
reserves usernames present in enabled LDAP directories, including members who
have never signed in. An unavailable configured directory makes creation fail
closed with 502, rather than claim a potentially reserved name.
Known dependency risk: SQLite
This release still carries libsqlite3-sys 0.30.1 (bundled SQLite 3.46), affected
by RUSTSEC-2026-0459.
A fixed libsqlite3-sys release exists (>= 0.39), but the released SQLx dependency
chain assessed for this release does not admit it. The narrowly scoped scanner
exception records acceptance of the remaining risk; it does not fix SQLite.
PostgreSQL and MySQL deployments do not use this SQLite code path.
Exploitation requires opening an attacker-written database and WAL pair. The
server does not accept untrusted SQLite uploads, and its database path is
operator-controlled. Keep the database directory writable only by the service
account and trusted operators, and restore only trusted backups. Restore
handling of pre-existing WAL/SHM sidecars is a separate hardening follow-up;
do not treat an arbitrary database file or leftover sidecars as a trusted
backup. Revisit this exception when SQLx supports patched libsqlite3-sys, or
before changing the database/restore trust boundary.
Manual smoke checklist
-
/readyzsucceeds and/api/v1/instanceidentifies the release commit;
the server, runner and MCP binaries reportv0.4.2. - Ordinary Git clone/push, issues, PRs and authorized CI still work.
- A session used before account deactivation stays revoked after
reactivation; a new authorized login works. - Password/factor changes invalidate pending address-change links;
completing an address change invalidates old reset links. - A draft release is visible to its writer but absent from reader lists,
direct links, assets and attestations. Published releases remain readable. - A fork head without current approval cannot run merge-group CI or merge
automatically. Current approval allows the intended work; a new push needs
approval again. - Revoking a private-source author's write access freezes updates and
blocks merging; any retained diff is clearly marked as a previous snapshot. - LDAP-reserved organization/bot names are refused, and a directory outage
gives an explicit failure without creating the owner name. - If an older rekey affected push mirrors, the offline recovery report
includes their encrypted passwords before the old key is retired.
Keep the previous image and matching data/configuration backup for rollback.
Rolling back removes these security protections. Stop the server and restore a
consistent backup/image pair rather than switching a running deployment blindly.
Plombir Git v0.4.1
Plombir Git v0.4.1
This release conceals inaccessible repositories, strengthens access and security
administration, and adds durable notices for those changes. It also fixes the
first-login password replacement screen.
Before upgrading
Back up the database, repository storage, configuration and encryption key.
Upgrade the frontend and backend together using the release bundle or a build
from the release tag. There are no new database migrations relative to v0.4.0.
An installation upgrading from an older version must also follow the
v0.4.0 upgrade notes; an intermediate v0.4.0 deployment is not required.
Keep the existing encryption key and stop every server before a separate rekey.
Authentication changes for administrators and API clients
Repository collaborators, organization members and teams, visibility changes,
transfers/deletions, webhook/mirror configuration, branch/tag protections,
CI secrets/environments and destructive account/bot administration now require a
login session with fresh proof. With MFA enabled, that proof must match the
current factor; password alone is insufficient. Existing user-verified passkeys
can also supply proof. Confirmation remains valid for ten minutes, so a second
operation within that window need not show another prompt.
Compatibility change: personal access tokens, including tokens with repo
or admin scope, cannot perform these protected administrative mutations.
They receive 403; adding scopes does not bypass the requirement. Clients using
login sessions must handle 403 sudo_required through fresh authentication.
Revoked sessions still receive 401 session_revoked.
Ordinary Git/CI execution, repository descriptions and CI variable automation
keep their existing authorization. Emergency token/key revocation remains
available without a new confirmation. See the precise boundaries in
features and API documentation.
Removing an organization member now removes their team memberships in the same
transaction. Inviting them back does not restore old team administrator rights.
Non-members cannot be preassigned to teams; old dormant rows are excluded from
team expansion and cleared on admission.
Notifications
Eight new categories bring the total to 44: repository/organization access,
repository/organization security, webhooks, mirrors, CI security and instance
administration. Owners and affected accounts receive appropriate copies. Queuing
and the underlying mutation commit together. Messages contain no integration
credentials or CI values, and another authenticated actor's IP/device is omitted.
Login/reset/confirmation events are attributed to their own proof, even if the
browser carries another account's cookie.
New categories default to email on. If Telegram is configured and confirmed,
missing new choices inherit the saved Telegram choice for notification-settings
changes. Explicit choices always win. Review the new switches after upgrading;
use each category's test button to verify your selected destinations.
Transfers retain repository-bound collaborators, keys, hooks, mirrors and CI
settings/secrets. Prior principals' notices use the old namespace. This release
does not introduce transfer acceptance or destroy existing private forks/local
clones when source access is revoked. See notification behavior.
Manual smoke checklist
-
/readyzsucceeds;/api/v1/instancereports the release source commit. - Signed-out and unauthorized accounts see the same full-page 404 for a
private repository and a made-up name, without tabs or clone controls. - REST API requests with no access have the same 404 for hidden/missing
names. Git/LFS may challenge for credentials in both cases before authentication. - First login with an administrator-set password asks for a new password
without a misleading "Login failed" banner. - After the ten-minute proof window expires, adding/changing/removing a
collaborator asks for fresh authentication; cancelling leaves access unchanged. - With MFA enabled, password alone cannot authorize the change. After valid
proof the intended change succeeds and the owner receives its enabled notice. - A
repo/adminPAT cannot bypass the new sensitive-action guards. - Removing and re-inviting an organization member leaves old team privileges
removed until explicitly granted again. - The eight new notification categories appear; email/Telegram tests succeed
for the channels enabled on the account. - Git clone/push, ordinary issues/PRs and CI still work with their usual rights.
Keep the previous image and matching data/configuration backup for rollback.
Rolling back removes these security protections; stop the server and restore a
consistent backup/image pair rather than switching a running deployment blindly.
Plombir Git v0.4.0
Plombir Git v0.4.0
This release adds personal Telegram delivery alongside email, security alerts,
Russian localization and remembered browser sessions. It strengthens MFA for
sensitive account changes and fixes session recovery, security settings and
repository navigation. Optional bot agent profiles and a configurable advertised
SSH clone port are also included since v0.3.0.
CHANGELOG.md describes the changes.
Before you upgrade
- Back up the database, repository storage and configuration, including the
encryption key. Stop all instances using a file-backed SQLite database before
migrating it. Upgrade the frontend and backend together; follow the offline
procedure in the deployment guide. - Apply the two migrations listed below. A server already running the accepted
notification candidate has these tables; migrations are not repeated. - Keep the existing encryption key. Agent model keys, Telegram bot tokens and
queued warnings use it. A separate key rotation requires all servers using
that database to be stopped, then restarted with the new key. A dispatcher
left running with the old key can permanently discard a pending warning. - Telegram requires direct outbound HTTPS to
api.telegram.org. Its client
deliberately ignores HTTP(S) proxy environment variables and follows no
redirects. SMTP remains optional; no new instance TOML section is required. - For a reverse proxy exposing SSH on a different port, set
[server].ssh_clone_portto the external port. Keepssh_portas the actual listener
port. Existing configuration remains valid when no mapping is needed.
Account and client behavior
- With MFA enabled, disabling or replacing the authenticator, regenerating
backup codes, changing password/email and other protected credential actions
require fresh proof of the current factor. Confirmation lasts ten minutes.
Existing MFA sessions will confirm once after upgrading; password alone cannot
disable MFA. An existing passkey with user verification also supplies proof. - Enabling MFA does not revoke other ordinary sessions. Sign out to revoke all
browser sessions if compromise is suspected. Automation and emergency key or
token revocation retain their existing permission checks. - A live cookie and explicit signed session credential naming different accounts
produceidentity_conflict; the browser rechecks its account without replaying
the rejected action. Cookie-only tabs still follow the browser's current
account. Use separate browser profiles for simultaneous accounts. - Remembered sessions renew on navigation for up to 30 days of inactivity, with
a 90-day absolute lifetime. Renewal does not extend sudo. Clients omitting
remember_meretain the previous policy. The UI/API must share an origin for
cookie renewal. - Personal notification settings, including the legacy email-only endpoint,
now require a login session; PAT automation cannot change or test them.
Notifications
There are 36 activity and security events. Each has independent email and
Telegram switches and a test action. The language at save time is used for
messages. Connecting Telegram copies the email selections; replacing an already
configured destination preserves custom choices. Select all / Deselect all
operate on one block and channel at a time.
Changing the Telegram destination or reducing delivery requires fresh
confirmation; with MFA enabled it must prove the current factor. A confirmed
previous destination receives a minimal warning even when delivery was disabled.
Existing email preferences are preserved. New security email events default on;
Telegram is off until connected.
The first completed login from each browser/account after upgrade can trigger a
new-device alert: existing sessions do not seed the known-browser list. Each
full login without a browser witness also alerts; API/CLI login clients should
retain cookies if they want browser recognition. PAT access is not a new login.
Activity email now uses per-event durable delivery rather than the old digest.
Old pending email without a captured destination remains visible in-app but is
not sent after upgrade. Delivery retries are bounded to six attempts and 24
hours. See notification operations and API behavior.
Database migrations
| Migration | Backends | Purpose |
|---|---|---|
m20261026_000001_agent_profiles |
all | Agent profiles, encrypted model keys and allowed repositories. |
m20261105_000001_notification_channels |
all | Notification profiles, encrypted delivery outbox and known browsers. |
Verification and rollback
After migration, check /readyz, /api/v1/instance and the binary version.
Verify sign-in, a protected MFA action, repository access and a notification test
for each configured channel. The first new-device message after upgrade is
expected.
Keep the old image digest and matching pre-upgrade data/configuration backup.
Rolling back to v0.3.0 means restoring that backup while stopped and starting its
matching image; do not run the old server against an upgraded database. The
moving latest tag is not a rollback reference. Linux amd64/arm64 binaries, the
multi-architecture image, deploy bundle, checksums and attestations are published
by the Release workflow for this tag.
Plombir Git v0.3.0
Plombir Git v0.3.0
A typical .github/workflows now runs here as written: steps in their own
processes, outputs, matrices decided at run time, services:, composite and
JavaScript actions such as actions/setup-node, on: schedule, vars.* and
permissions:. Imports from Gitea and Forgejo bring the whole project, as
imports from GitHub and GitLab do, and every import answers with a receipt of
what came over. plombir-git trial starts a throwaway instance with one
docker run, and merges name the people who wrote and merged the work.
CHANGELOG.md lists every change. This
page lists what to do about them.
Before you upgrade
Work through this list on the running v0.2.0 instance, before the new image
starts.
- Back up the database and repository storage. Twelve migrations run on
the first start, and v0.2.0 does not know the tables and columns they add.
File-backed SQLite migrations run while the server is stopped; follow the
offline migration procedure indeploy/README.md. - Drain and upgrade external runners. The runner protocol is at 6, and a
v0.2.0plombir-git-runnersends none: it is never handed an Actions job
again (the poll answers426, naming the job) and keeps taking only native
.plombir-git-ci.ymljobs. Let running jobs finish, stop the runners,
upgrade the server, then start the runners on the v0.3.0 binary. - Some workflows start running. Check which repositories carry them
before the upgrade:.github/workflows/*.ymlnow runs when a commit has no
.gitea/workflows, and.forgejo/workflowsruns first of the three.
A repository imported from GitHub or Forgejo whose CI never ran here
starts a pipeline on its next push.on: scheduleworkflows run on the default branch, at most every
[ci] schedule_min_interval_minutes(5) per- cron:entry.
- Secrets reach only the steps that name them. An Actions job is given
the secrets its workflow names, and each step only those the step, the job
or the workflow names inenv:or${{ secrets.NAME }}. A script that
reads$DEPLOY_KEYfrom its environment without the workflow naming it
gets nothing: addenv: { DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }} }to the
step. Native jobs keep every secret. - Workload identity needs
permissions: id-token: write. A workflow
that declares nopermissions:getscontents: readandpackages: read
and no workload identity, and/api/v1/ci/oidc/tokenrefuses its token.
Anywriteother thanid-token: write(contents: write,write-all)
is refused when the workflow is read: push or release with a deploy key or
a token kept in a secret. Native jobs keep their workload identity. - Actions from github.com are off by default.
uses: owner/repo@ref
loads from this instance's public repositories and the workflow's own
unless[ci] actions_sourcesalso lists"upstream", which fetches from
actions_upstream_url(https://github.com). A workflow that uses
actions/setup-nodeor any other action from GitHub is refused by the
source's name until then.actions/checkout,actions/cacheand
actions/upload-artifactstay built in. Allow"upstream"only for a
forge whose actions you would paste into a workflow yourself; consider
actions_require_full_sha = true. - Steps are processes of their own. A variable a step
exports, a
directory itcds into and a shell option it sets end with the step; use
$GITHUB_ENVand$GITHUB_PATH, as on GitHub. A step withoutshell:
runs underbash -e.::set-outputis refused; write to
$GITHUB_OUTPUT. In expressions&&and||give back an operand rather
thanfalse, and a job whose needed job was skipped is skipped too. - Merges are signed by people. The committer of a merge, squash or
rebase is the account that merged it, a squash is authored by the pull
request's author, and its message is<title> (#N)with the description.
Hooks or reports that look forPlombir Git <noreply@plombir-git.local>
find it only on the merge queue's rehearsal commits, which never reach a
branch. - A stopped runner stays registered.
SIGTERMmarks it offline instead
of deleting it. Revoke a runner withDELETE /admin/runners/{id}; one you
expected the stop to remove is still listed. - Webhook
ci.statussendsrepository: "<owner>/<name>"where it sent
repository: "repo#<id>".repository_idis unchanged.
What changes for clients
- Runner protocol. A runner sends
x-plombir-git-runner-protocol; steps
need 2,services:3, scoped secrets 4, JavaScript actions 5 and composite
actions' files 6. A job needing more than a runner sends is never handed to
it. - Job token.
CI_JOB_TOKENcarries the job'spermissions:;
CI_OIDC_TOKEN_URLis set only for a job that may use it. - Rootless Docker. On a rootless daemon a job container runs as the
container's root, which the daemon maps to its own user on the host and the
workspace's owner. A rootful daemon runs jobs as before. - Pipelines API.
GET /pipelinesandGET /pipelines/{id}add
commit_messageandrun_name; jobs adddisplay_nameand their steps,
each step's log at…/jobs/{job_id}/steps/{number}/log. - Imported rows carry
original_author,original_author_idand
original_service(github,gitlab, orgithub:<host>/
gitlab:<host>/gitea:<host>for another server).
Database migrations
| Migration | Backends | What it does |
|---|---|---|
m20261020_000001_ci_schedules |
all | Creates ci_schedule_ticks; adds pipelines.schedule_workflow and schedule_cron. |
m20261020_000002_pipeline_job_steps |
all | Creates pipeline_job_steps; adds pipeline_jobs.steps. |
m20261020_000003_pipeline_job_outputs |
all | Adds pipeline_jobs.job_context and outputs. |
m20261020_000004_pipeline_job_matrix |
all | Adds pipeline_jobs.matrix_group, matrix_fail_fast, matrix_max_parallel and deferred_matrix. |
m20261021_000001_ci_variables |
all | Creates ci_variables and org_ci_variables. |
m20261021_000002_pipeline_job_deferred_condition |
all | Adds pipeline_jobs.deferred_condition. |
m20261021_000003_pipeline_head_branch |
all | Adds pipelines.head_branch. |
m20261021_000004_pipeline_job_display_name |
all | Adds pipeline_jobs.display_name. |
m20261021_000005_pull_request_base_sha |
all | Adds pull_requests.base_sha. |
m20261022_000001_imported_original_author |
all | Adds original_author, original_author_id and original_service to issues, issue_comments, pull_requests, pr_reviews and releases. |
m20261022_000002_pipeline_run_name |
all | Adds pipelines.run_name. |
m20261022_000003_imported_assignments |
all | Creates imported_assignments. |
Every one adds tables or nullable columns and none refuses on existing data.
Rows written before the upgrade read as before: pipelines and jobs without
steps, names or outputs, pull requests without base_sha (a merged one is
then diffed against its merge commit's first parent), imported rows without a
byline.
Rollback
Test a restore before relying on rollback. Rolling back means restoring the
pre-upgrade database and repository backup and starting the v0.2.0 image
pinned by digest, with runners back on the v0.2.0 binary: v0.2.0 does not
know the tables and columns above. The moving latest tag is not a rollback
reference.
Plombir Git v0.2.0
Plombir Git v0.2.0
Push mirrors, Git LFS over SSH, shallow clones for older clients, organization
and instance webhooks with Slack, Discord and Matrix formats, code, pull
request and user search, blame, a first-administrator setup token, opt-in
storage quotas and CI secrets scoped to environments. The release also closes
a set of security issues in authentication, organization rights, mirrors, CI
and the Git protocol, and changes defaults in ways an existing instance has to
check before it upgrades.
CHANGELOG.md lists every change. This
page lists what to do about them.
Before you upgrade
Work through this list on the running v0.1.1 instance, before the new image
starts.
-
Back up the database and repository storage. Fifteen migrations run on
the first start, and an older binary may not understand a database the new
one migrated. File-backed SQLite migrations run while the server is
stopped; follow the offline migration procedure indeploy/README.md. -
Stop or drain external runners. A job an external runner picked up
before the upgrade has no encrypted snapshot of the secrets it was issued,
and the new server answers every log upload of such a job with500. Let
running jobs finish, stopplombir-git-runner, migrate, then start the
runners on the v0.2.0 binary: theimage:check, the--separator, the
environment allow-list and--initlive in the runner. Runner hosts need
Docker 20.10 or newer (docker run --pull never). -
docker-compose.hostdir.ymlmounts the root filesystem read-only.
Everything the server writes has to be under/data. Check that the
mountedplombir-git.tomlsets[server].host_key = "/data/ssh_host_key"
(the template does). Without it the server falls back to$HOME/.ssh,
cannot write the SSH host key or the at-rest key beside it, and does not
start. A[logging].fileor any other writable path outside/datafails
the same way. -
Registration is closed unless the config says otherwise. An instance
that sets neither[auth].registrationnorPLOMBIR_GIT_REGISTRATION
refuses new sign-ups once it has an account. Set it explicitly to the
behaviour you want. -
jwt_secretmust be at least 16 characters, or the server refuses to
start. -
Webhooks. Find hooks whose
content_typethe new server refuses:SELECT id, content_type FROM webhooks WHERE content_type NOT IN ('json', 'form', 'slack', 'discord', 'matrix');
Each row returned fails every delivery after the upgrade until the hook is
edited. Receivers offormhooks now getpayload=<url-encoded JSON>and
must decode it. -
CI OIDC trust policies. The
subclaim is now
repo:<owner>/<name>:ref:<ref>(or:environment:<env>). Rewrite cloud
trust policies that match the oldrepo:<id>:*before the upgrade, or the
token exchange fails. Seedocs/ci.md#oidc-tokens. -
Admin automation.
POST /admin/users,
POST /admin/users/{id}/password-reset,PATCH /admin/users/{id},
POST /admin/sso/providersandPATCH /admin/sso/providers/{id}refuse a
personal access token and need a session in sudo mode. So does creating
any key, token, passkey, SSO link or runner token. -
Browser origin. Cookie-authenticated writes from a foreign
Origin
are refused with403. Make sure[server].external_urlis the address
people browse, and list a separate frontend origin in
PLOMBIR_GIT_CORS_ORIGINS. -
New limits that are on by default.
[mirror].max_clone_size_mband
[imports].max_clone_size_mbstop a mirror or import that would write
more than 10 GiB (Git and LFS together); raise them first if you mirror
larger repositories. AnonymousGET /api/v1/searchis limited to 60
requests a minute per client; behind a reverse proxy set
[rate_limit].trusted_proxies, or every anonymous visitor shares one
budget. -
OCI garbage collection starts on its own within an hour of the
upgrade and cannot be switched off: blobs no manifest references and
stored objects with no database row are deleted once they are 24 hours
old. Take a storage backup first if any of those bytes matter. -
Reverse proxy. Re-copy
deploy/Caddyfile.exampleor
deploy/nginx.conf.example, or add a rule that answers404for
/metrics, unless[observability].metrics_tokenis set. -
OIDC over plain HTTP. A provider whose authorization endpoint is
plain HTTP on a remote host must be listed in
[auth].allow_insecure_oidc_origins, or sign-in fails. -
[logging].max_size_mb. A config that sets it now gets size rotation
of[logging].file(<file>.1,.2, …) instead of daily files, and0
refuses to start. Old daily archives are not cleaned up.
What changes for clients
- Commit statuses need the full 40-character
sha; an abbreviated one is
400. - Pull mirrors need repository administration. Collaborators with write
access lose the mirror settings and Sync. A mirror URL changed to another
host needs its credential again (or an emptypassword). - MySQL: a repository address resolves only as its rows spell the owner
and the name; another spelling is404everywhere except the container
registry. Fix remotes and links that use another case. - Case-insensitive names. Owner names and repository names (per owner)
are unique regardless of case. Pairs that already exist are kept, and
startup logs a warning naming them; rename one of each pair. - CI job variables with a name that is not a valid environment variable
name refuse the pipeline at trigger time.AWS_*,CLOUDSDK_*and
GOOGLE_APPLICATION_CREDENTIALSnow reach the job container, and a job's
private image is pulled with the runner operator's Docker credentials, never
with credentials the job sets. ?state=on issue, pull request and milestone listings:alllists
everything, an unknown value is400instead of an empty list.- Field lengths: titles over 255 characters, bodies over 65 536 and
similar values are400on every backend. - TLS: outbound connections use rustls, which speaks TLS 1.2 and 1.3
only. A webhook receiver, mirror source or LDAP server limited to TLS 1.1 or
older can no longer be reached. - Swagger UI is gone from
/api-docs. The OpenAPI document stays at
/api-docs/openapi.json. - Anonymous search (
type=users) lists active accounts by username and
display name.
Database migrations
| Migration | Backends | What it does |
|---|---|---|
m20261011_000001_runner_job_mask_snapshot |
all | Adds pipeline_jobs.mask_secrets_encrypted. |
m20261011_000002_ci_secrets_mysql_longtext |
MySQL | ci_secrets.encrypted_value becomes LONGTEXT. |
m20261011_000003_webhook_scopes |
all | Adds webhooks.scope_kind and scope_id, backfilled for repository hooks. |
m20261012_000001_webhook_delivery_mysql_longtext |
MySQL | Delivery request and response bodies become LONGTEXT. Rebuilds the table, which takes a while on a large delivery journal. |
m20261012_000002_webhook_secret_mysql_longtext |
MySQL | webhooks.secret_encrypted becomes LONGTEXT. |
m20261012_000003_webhook_url_events_mysql_text |
MySQL | webhooks.url and events become TEXT. |
m20261012_000004_sso_secret_columns_text |
MySQL, PostgreSQL | SSO client secret and LDAP bind password columns become TEXT. |
m20261012_000005_remote_addresses_mysql_text |
MySQL | Mirror and import URLs and the mirror username become TEXT. |
m20261014_000001_owner_names_fold_case |
all | Adds a case-folded key and a unique index for owner names. Existing case collisions are kept: one holder gets the key, startup warns about the others. |
m20261014_000002_ci_secret_environments |
all | Adds ci_secrets.environment_id; existing secrets stay repository-wide. On SQLite the table is rebuilt in one transaction, and up refuses while a leftover ci_secrets_pre_environment_scope table exists. down refuses while an environment-scoped secret exists. |
m20261014_000003_org_owner_role_backfill |
all | Gives every organization without an owner-role member that role for its owner_id account, with an org.owner_role_backfill audit entry. |
m20261014_000004_repositories_name_fold_case |
all | Adds a case-folded repository name key and a unique index per owner. The younger repository of each existing case pair is exempted and named at startup. |
m20261015_000001_create_push_mirrors |
all | Creates push_mirrors. |
m20261016_000001_free_text_columns_mysql |
MySQL | Widens bodies, logs, scripts and list columns to MEDIUMTEXT or TEXT. Rebuilds each table, which takes a while on large pipeline_jobs and issues tables and holds metadata locks. |
m20261016_000002_pipeline_job_image_mysql_text |
MySQL | pipeline_jobs.image becomes TEXT. |
None of them refuses on existing data, apart from the leftover staging table
named above. The column widenings have a no-op down, so a rollback keeps the
wider columns. On MySQL, objects in the container registry stored under
another spelling of a repository's owner move to the row's spelling at
startup; a failed move is logged and retried at the next start.
Image and runtime
- The image's entrypoint is
tini --.docker run <image> plombir-git …and
composecommand:work as before. A deployment that replaces the
entrypoint (composeentrypoint:,docker run --entrypoint, a Kubernetes
command:) runs without tini; on Kubernetes useargs:to keep it. - CI job containers start with
docker run --init, which needs the
docker-initbinary Docker Engine ships. Their names gain a random suffix:
plombir-git-job-<job>-<random>andplombir-git-runner-job-<job>-<random>. - Every smart-HTTP and LFS request writes a...
Plombir Git v0.1.1
Plombir Git v0.1.1
First published release of the server, runner, and MCP stdio binary. The
v0.1.0 tag did not produce a GitHub release because its publication workflow
failed after building the architecture images. This release fixes that workflow
and includes Linux x86_64 and aarch64 binary archives with the built web UI,
an SPDX JSON image SBOM for each architecture, a source dependency SBOM (which
also includes build and dev dependencies), and a multi-architecture image in
GHCR. The image and binary archives have GitHub build provenance attestations.
Upgrade and rollback
Back up the database and repository storage before upgrading. File-backed
SQLite migrations run while the server is stopped; see the offline migration
procedure in deploy/README.md. Check the migration path before switching the
image, and test a restore before relying on rollback: an older binary may not
understand a database migrated by a newer one. Pin the image by digest for a
repeatable deployment; the moving latest tag is not a rollback reference.
The standalone binaries are linked against the Debian bookworm runtime used by
the image. For a host with different system libraries, run the published image.