Repository navigation
Releases: Nettechnologys/plombir-git
Release list
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.