Repository navigation
v0.16.0
⚠ Upgrade notes: breaking and behavior changes since 0.15.0
Read this section before you upgrade. The generated changelog follows below.
Caution
If your organization uses RSA signing keys under 2048 bits, rotate them on 0.15.x before you upgrade. 0.16.0 rejects weak RSA keys at startup and on every request, so tokens signed with them stop working (item 7).
Wire and API changes
- Outbound webhooks are renamed. Outbound push-upstream runs now send
repo.push_upstream.started,repo.push_upstream.succeededandrepo.push_upstream.failedinstead ofrepo.sync.*withdirection: "push". The body is the same apart fromtype. Receivers that filteredrepo.sync.*ondirection == "push"must handle the new types. During a rolling upgrade, replicas that are not yet upgraded and deliveries queued before the upgrade keep the old names. (#358, webhooks reference) next_cursoris omitted on the last page. The repos, branches, commits, files, files/metadata, notes/refs and tags list responses sendnext_cursoronly whenhas_moreistrue. Exhausted pages no longer send"next_cursor": "". Clients must stop paging onhas_more: false, not on an empty cursor.grepis unchanged. (#377)POST /api/v1/reposreturns 201 on create. A new repository (plain, sync, copy or fork) returns201instead of200, with the messageRepository '<name>' created. A name that a deleted repository still holds returns404instead of409, and nothing is restored. Every live taken name still returns409. The Go and TypeScript SDKs accept any 2xx. (#390)Commit.dateis the author date.GET /repos/commits,GET /repos/commitand their path-style aliases now send the author date indateand the committer date in the newcommitter_datefield. Before,datecarried the committer date, so rebased and cherry-picked commits now show a differentdate. (#401)- Ref-policy-restricted tokens cannot create sync repos.
POST /reposwithupstreamor abase_reposync now returns403when the token's ref policies carry any op. The server refuses before it creates the repository, the credential or the first sync. Plain creates are unchanged. (#395)
Sync credentials
-
Per-host default git usernames and a credential helper. When a stored git credential has no username, the sync worker now sends the upstream provider's default on the pull fetch and the upstream push. A stored username always wins. (#398, #402)
- Bitbucket:
x-token-authwith the token as the password (wasgitbefore #398). - GitLab:
oauth2with the token as the password (wasgit). - Gitea, Forgejo, Codeberg: the token as the username with an empty password (was
git:<token>). - GitHub and every other provider:
gitwith the token as the password (unchanged).
The worker now gives git its credentials through a static credential helper that reads them from the environment, and it resets any other configured credential helper for these runs. A stored username or password that contains CR, LF or NUL now fails the sync as a configuration error. The error does not echo the value.
- Bitbucket:
Authentication
-
RSA organization keys must be at least 2048 bits. The server enforces this at key ingestion and on every request, including keys already stored. A key set that mixes strong and weak RSA keys fails closed at startup and at verification. CAUTION: if you use RSA keys under 2048 bits, rotate them on the old fleet before you upgrade, or every token signed with them stops working. (#253, rotation steps)
-
JWTs must use canonical, unpadded base64url. The verifier now rejects padded, standard-alphabet or otherwise non-canonical spellings in the header, payload and signature segments with
401. Tokens minted by the SDKs and byopenstorage mintalready use the canonical form. Custom token minters must emit canonical unpadded base64url. (#323)
Read-side limits and request parsing
- Read-side git work is bounded. The
git:readendpoints now answer422when a request hits the memory, output or file-size limit,503withRetry-Afterwhen capacity is busy, and503when the 30 s git time budget (archive: 10 min) runs out. Write endpoints are unchanged. (#324) - Strict JSON bodies reject duplicate member names with
400. Uppercase full SHAs, including guard SHAs, are now accepted instead of rejected. (#384, #386)
Go module path and installation
- The Go module path is now
github.com/coder/openstorage(wasgithub.com/coder/open-storage). Updatego installcommands,go.modrequirements and imports that use the old path.go install github.com/coder/openstorage/cmd/openstorage@v0.16.0now works for users with access to this repository. The repository is not public, so proxy.golang.org cannot serve it: setGOPRIVATE=github.com/coder/openstorageand give git your GitHub credentials. The release archives below need no Go toolchain, andmise use github:coder/openstorage@0.16.0installs the same binary whenGITHUB_TOKENis set. The binary name (openstorage), theOPENSTORAGE_*configuration prefix and persistent data locations are unchanged. (#225, migration guide)
Configuration
- The
CODESTORAGE_*fallback still works in 0.16.0. The docs said this fallback lasts for 0.15.x only. 0.16.0 still resolves each unsetOPENSTORAGE_*variable from itsCODESTORAGE_*name and logs a boot-time deprecation warning for each one. Do not rely on it: migrate every setting toOPENSTORAGE_*now. A later release removes the fallback; that version is not decided yet. (migration guide)
Fixes missing from the generated changelog: fork create (POST /api/v1/repos with a base_repo fork, and the copy form) no longer returns 500 when $TMPDIR and the data dir are on different filesystems (#362). The JWT change in item 8 (#323) is also missing below.
Additive changes worth knowing: error bodies gain RFC 9457 problem-details fields next to error (#351). Webhooks also send org, type and repository.repo_name (#368). An opt-in Prometheus listener ships behind OPENSTORAGE_METRICS_LISTEN, off by default (#327).
This release ships binaries only. No container image is published for 0.16.0.
0.16.0 (2026-10-09)
⚠ BREAKING CHANGES
- api: Commit.date now means the author date. Read the new committer_date field for the committer date.
- api: POST /api/v1/repos returns 201 instead of 200 for a new repository, the success message text changes, and a create of a deleted repo's name returns 404 instead of 409. The Go and TypeScript SDKs accept any 2xx.
- webhooks: send outbound push-upstream runs as repo.push_upstream.* events (#358)
Features
- api: accept optional repo_name in POST /repos (#299) (3a68bc9)
- api: accept restore-commit base_ref with the spec's 412 preconditions (#383) (b0ddce7)
- api: accept upstream on repo create and expose it on repo GET (#361) (f6a6d33)
- api: add organization metadata endpoint (#286) (536e096)
- api: add RFC 9457 problem-details fields to the error envelope (#351) (1f392ac)
- api: add topological order rank to files/metadata commits (#337) (516ee3d)
- api: allocate omitted branch targets (#239) (3663fae)
- api: answer POST /repos 201 on create and 404 for a deleted name (#390) (127be7d)
- api: bound memory, time and concurrency of read-side git subprocesses (#324) (0fec21e)
- api: serve the path-style notes/append, upstream/pull and DELETE upstream routes (#382) (718d3a5)
- cli: add fail-closed keygen bootstrap mode (e32d58f)
- compose: add a local-build Docker-only quickstart (#256) (e374aad)
- deploy: add Terraform AWS EC2 reference (#254) (d94125f)
- githttp: bounded push-publication wait primitive (#332) (474791e)
- githttp: commit-graph refreshes join the shared git chokepoint; outcome log contract and metric (#338) (cb8b33a)
- meta: add CreateLinkedRepo, an atomic repo + upstream (+ credential) create (#389) (c3af22a)
- meta: record a per-repository create state (#391) (f677626)
- meta: SQLite local schedule state and transitions (#336) (549d37c)
- metrics: add opt-in Prometheus metrics listener (#327) (372a4b3)
- sync: schedule a sync create's first sync with its create mark (#392) (0c6c2c2)
- sync: SQLite git-surface pushes schedule sync and forwarding (#345) (897ccd1)
- sync: SQLite local worker and schedule sweep (#341) (edb0eeb)
- webhooks: send org, type and repository.repo_name (#368) (05f083a)
- webhooks: send outbound push-upstream runs as repo.push_upstream.* events (#358) (c69bcc7)
Bug Fixes
- api: accept current upstream field names and DELETE query params (#379) (a26fcc3)
- api: accept uppercase full SHAs and reject duplicate strict-JSON members (#384) (87b06ec)
- api: accept uppercase guard SHAs and walk strict request types (#386) (9efd9d7)
- api: deny sync repo creates for ref-policy-restricted tokens (#395) (db465a2)
- api: omit exhausted pagination cursors and refresh upstream spec (#377) (6851ff9)
- api: report the author date as Commit.date and add committer_date (#401) (cf05eff)
- api: resolve a relative cache dir once at startup and in api.New (#366) (b590932)
- auth: require 2048-bit RSA organization public keys (5b17f02)
- ci: make the legacy MinIO qualification lane opt-in (#308) (c01ad82)
- ci: restore the legacy MinIO fixture source (#251) (5f172c5)
- deps: update x/crypto to address SSH advisories (#233) (de71d60)
- githttp: serialize cold cache initialization (#252) (915d4be)
- gitread: pin git's message locale so heap-cap failures classify as 422 (#340) (870a647)
- jobs: keep River sync runs uncounted across serve shutdown (#347) (b224898)
- s3wal: name missing lease holder in corruption diagnostics (#302) (6bf383a)
- s3wal: preserve evidence in lease refusal diagnostics (#270) (84101df)
- sync: keep in-flight local runs' requests across serve shutdown (#344) (bba1986)
- sync: send upstream's default username when none is stored (#402) (ed1b409)
- sync: send x-token-auth for Bitbucket credentials without a username (#398) (6cb11d3)
- test: accept trailing slash on fake S3 bucket requests (#330) (347f59d)
- use the canonical openstorage repository and Go module (#225) (c877535)