Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.19.0"
".": "0.20.0"
}
87 changes: 87 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,92 @@
# Changelog

## [0.20.0](https://github.com/coder/openstorage/compare/v0.19.0...v0.20.0) (2026-11-09)


### ⚠ BREAKING CHANGES

* **api:** `archive` answers 422 for a repository that holds a symlink whose target is longer than 4,095 bytes, before any response byte, and the body names the symlink. Before, a target of 4,096 bytes up to about 1 MiB was in the archive, and a longer one cut the stream after its headers. To get the archive, pass the symlink in `exclude_globs`, or fetch the target with git.
* **api:** `diff-commit` answers 400 `invalid` for a patch that gives a file a directory mode (`new file mode 040000`, or a mode change to `040000`). Before, such a patch answered 412 `no changes to commit`, 409 `conflict`, or 200 with a commit that lacked the file.
* **api:** `diff-commit` answers 400 `invalid` instead of 409 `conflict` for a patch that only git refuses (`.git./x`, `git~1/x`, a `.gitmodules` symlink, `new mode 100664`, a submodule patch without a commit or with a null commit). It answers 500 instead of 409 when `git apply --cached` fails for any other reason (a held index lock, a full disk, an unreadable index), and 500 instead of 400 when git fails while it parses the patch. A file name with a newline and a `fatal:` line makes git's message look like a server fault, so the client's own 400 or 409 then answers 500. A patch that makes git abort and a header without a file name answer 400 instead of 500.
* **api:** the REST API answers a token that fails verification (malformed, bad signature, expired or unknown issuer) with 403 `forbidden` instead of 401 `unauthorized`. SDK 0.1.0 raises `PermissionDeniedError` instead of `AuthenticationError` for such a token. SDK 1.17.1 reports status 403 instead of 401, for example `ApiError.status` in TypeScript. A request without a Bearer token still gets 401.
* **api:** a key store failure during REST token verification answers 403 `authentication_unavailable` instead of 401 (or instead of 403 `forbidden` for a fork source token; the Git and LFS transports keep 401; during a key store outage a caller with any well-formed token sees this 403 instead of 401), and unmatched `/api/` paths answer problem bodies (404 `route_not_found`, or 405 `method_not_allowed` with `Allow`) instead of ServeMux's plain text.
* **api:** merge failures no longer carry the `result` envelope. File conflicts answer 409 with upstream's `MergeConflict` body (`error`, `conflict_type`, `conflict_paths`, `merge_base_sha`), and every other merge failure answers the plain problem body. A non-fast-forward `ff_only` merge and a merge of unrelated histories answer 412 `precondition_failed` instead of 409. Note-write failures answer the plain problem body instead of the note envelope, except the 409 guard body. SDK 1.17.1 Go reads the note envelope only for `application/json` (`util.go:154`), so it now reports these note-write failures as a generic `APIError` instead of a `RefUpdateError`. I did not check the 1.17.1 TypeScript and Python clients.
* **api:** commit-pack, diff-commit and restore-commit answer the failures for which upstream documents ProblemDetails with the plain problem body instead of the result envelope: 403 (ref policy, quota), 404, 429 and 500 on all three, and 400 and 409 on restore-commit. Merge's repository-not-found 404 and its 500 also answer the plain problem body. The 404s carry `repository_not_found`, `branch_not_found` or `ref_not_found`. SDK 1.17.1 Go reports these restore-commit failures as `RefUpdateError` with status `404` (or the HTTP status) and a generic message, and builds the commit-pack and diff-commit `RefUpdateError` with status `failed`. I did not check the 1.17.1 TypeScript and Python clients.
* **api:** write routes (commit-pack, diff-commit, restore-commit, merge, notes, branches, tags) answer auth failures (401, 403), the REST rate limiter's 429 and the path-style alias 404 with the plain problem body instead of the result envelope, and so do the path-id git-credentials routes for every failure. SDK 1.17.1 Go builds the commit-pack, diff-commit and restore-commit `RefUpdateError` from that body with `Status` `failed` instead of `unauthorized`, `forbidden`, `not_found` or `unavailable`. I did not check the 1.17.1 TypeScript and Python clients.
* **api:** a stale `expected_target_sha` or `expected_head_sha` on `commit-pack`, `diff-commit` and `restore-commit`, and a stale `expected_notes_ref_sha` or `expected_ref_sha` on `POST .../notes` and the `DELETE .../notes` body, now answer `409` with `code: ref_guard_failed`, `guard`, `current_sha` and `result.status: conflict`, instead of `412` `precondition_failed`. Go SDK 1.17.1 (`code-storage-go`) callers now get a `RefUpdateError` with status `conflict` on the three commit routes. On a note create they get an `APIError` with status 409 whose message is the raw body, because that SDK reads note bodies only for `application/json`. Go SDK 0.1.0 (`github.com/pierrecomputer/sdk/go`) callers get a `RefGuardError` on every form.
* **api:** error bodies with problem members (`code`, `detail`, ...) are now sent as `Content-Type: application/problem+json`, as upstream documents. SDK 1.17.1 Go and TypeScript clients parse error JSON only for `application/json`, so their error message becomes the raw body text and the parsed body becomes a string. SDK 0.1.0 and the 1.17.1 Python client are not affected.

### Features

* **api:** base64 siblings for non-UTF-8 paths in files, diff, blame and grep responses ([#721](https://github.com/coder/openstorage/issues/721)) ([ccdd961](https://github.com/coder/openstorage/commit/ccdd961d5f4c563230342fe9a2a7527cd24f63e6))
* **api:** filter GET /repos by prefix (upstream spec 34ac6de1) ([#652](https://github.com/coder/openstorage/issues/652)) ([86e6fe7](https://github.com/coder/openstorage/commit/86e6fe7fe290287b5facaf146c781db53d09a9c0))
* **api:** send application/problem+json on problem bodies ([#660](https://github.com/coder/openstorage/issues/660)) ([3c6bfde](https://github.com/coder/openstorage/commit/3c6bfde36e3261aef45578985f732fc127914404))
* **api:** send problem bodies and MergeConflict for merge and note-write failures ([#670](https://github.com/coder/openstorage/issues/670)) ([3c4b2b5](https://github.com/coder/openstorage/commit/3c4b2b575e6cb281136d5ef8216e6ae6da6fad8b))
* **api:** send problem bodies for commit-write failures upstream documents as ProblemDetails ([#669](https://github.com/coder/openstorage/issues/669)) ([74c9684](https://github.com/coder/openstorage/commit/74c9684799fdbf9b9a86ecfe2e42c9df83c29f41))
* **api:** send problem bodies for write-route auth, rate-limit and alias failures ([#663](https://github.com/coder/openstorage/issues/663)) ([e0a48fb](https://github.com/coder/openstorage/commit/e0a48fbe4e2d4ce5a9e71fd63616b56c3ee8dabb))
* **api:** send route_not_found and authentication_unavailable ([#672](https://github.com/coder/openstorage/issues/672)) ([8638fa9](https://github.com/coder/openstorage/commit/8638fa95603bd5fb9f09853143b94a3ee56bd6f4))
* **api:** serve GET/POST /api/repos and the tag-in-path delete that SDK 0.1.0 calls ([#662](https://github.com/coder/openstorage/issues/662)) ([2176fc1](https://github.com/coder/openstorage/commit/2176fc1459ebe47871b317b92ee9e3d4d0097668))
* **ref:** write a scan-state row only when its generation is the expected one ([#698](https://github.com/coder/openstorage/issues/698)) ([1815795](https://github.com/coder/openstorage/commit/1815795056e5e9dc1cc2426aa360266f21ac7221))


### Bug Fixes

* **api:** answer 404 or 400 for a git check only when git says no ([#760](https://github.com/coder/openstorage/issues/760)) ([b3add73](https://github.com/coder/openstorage/commit/b3add73a8c70ef2316a137b58c44a2c42f72355a))
* **api:** answer a git-credentials repo_id of "org" with 404 instead of an assertion ([#667](https://github.com/coder/openstorage/issues/667)) ([8ebc5ee](https://github.com/coder/openstorage/commit/8ebc5ee4272fb76408d19a9656671f81b78f006e))
* **api:** answer a token that fails verification with 403 forbidden ([#674](https://github.com/coder/openstorage/issues/674)) ([4e30915](https://github.com/coder/openstorage/commit/4e30915ceb0fe663f80cb0730721fdf28152c1a6))
* **api:** answer stale commit and notes guards with 409 ref_guard_failed ([#661](https://github.com/coder/openstorage/issues/661)) ([29688af](https://github.com/coder/openstorage/commit/29688af92328606dece78eb5a2bfad4cd26d0f4b))
* **api:** cap diff-commit's patch, and read git apply's stderr as it streams ([#778](https://github.com/coder/openstorage/issues/778)) ([797dcd5](https://github.com/coder/openstorage/commit/797dcd55013a475e6514105c11904dd56a377871))
* **api:** clip long client values in git error names and log lines ([#757](https://github.com/coder/openstorage/issues/757)) ([44df4a4](https://github.com/coder/openstorage/commit/44df4a40ad7a8fe9ad9f647cc0dfc8ec616c1c88))
* **api:** preview merge conflicts at paths longer than one git argument ([#739](https://github.com/coder/openstorage/issues/739)) ([a8b0e34](https://github.com/coder/openstorage/commit/a8b0e34d45d5a4e88e1b88c08a90974360b352cd))
* **api:** put three rare diff-commit patch failures in the right status ([#686](https://github.com/coder/openstorage/issues/686)) ([a439727](https://github.com/coder/openstorage/commit/a439727489af6cb8394470b073ae7953ae7e1cf6))
* **api:** refuse a diff-commit patch that gives a file a directory mode ([#722](https://github.com/coder/openstorage/issues/722)) ([c94f17a](https://github.com/coder/openstorage/commit/c94f17a7529b060106b003c95ff198c80a2772ff))
* **api:** refuse an archive that holds a symlink target over 4095 bytes ([#756](https://github.com/coder/openstorage/issues/756)) ([77efbe3](https://github.com/coder/openstorage/commit/77efbe3ac195b21698d0267f827a1c23c9f7c324))
* **api:** restore only a commit, and answer 500 for one git cannot read ([#771](https://github.com/coder/openstorage/issues/771)) ([94f4341](https://github.com/coder/openstorage/commit/94f43418582b88244e671a28a328593b66d0cf42))
* **api:** send target_branch and every RefUpdateResult member in commit-write results ([#668](https://github.com/coder/openstorage/issues/668)) ([50b4071](https://github.com/coder/openstorage/commit/50b4071e157ccaa0a2bc5ccc4aaaa4bc4a903118))
* **auth:** accept any non-empty sub and treat a token without repo as org-wide ([#666](https://github.com/coder/openstorage/issues/666)) ([137ba2c](https://github.com/coder/openstorage/commit/137ba2cc4eff12dc4a700ff1887b8012efa6cca6))
* **blob:** list file-store keys in key order and add ListPagesAfter ([#697](https://github.com/coder/openstorage/issues/697)) ([093c231](https://github.com/coder/openstorage/commit/093c2317bef3006d1f064141f5543cc69a0df36e))
* **deps:** bump github.com/jackc/pgx/v5 to v5.12.0 ([#710](https://github.com/coder/openstorage/issues/710)) ([caa296e](https://github.com/coder/openstorage/commit/caa296e617b917972fc2d9cbb9404e3ee5f6c04d))
* **deps:** bump River to v0.51.1 ([#720](https://github.com/coder/openstorage/issues/720)) ([59cf665](https://github.com/coder/openstorage/commit/59cf6659fea79dd81721c15d16620955aeb7a4a7))
* **githttp:** keep the hook's store errors off the pusher's screen and give them to the operator ([#742](https://github.com/coder/openstorage/issues/742)) ([9cdb2fa](https://github.com/coder/openstorage/commit/9cdb2fab4f5a90a4e5f7a9a87db0f0fe8aa4f881))
* **githttp:** report a signature check that ends without a verdict as a failure ([#765](https://github.com/coder/openstorage/issues/765)) ([9c7aa98](https://github.com/coder/openstorage/commit/9c7aa98ab3ff7d14405867ddca49f3073023ba21))
* **githttp:** show the pusher only refusals from a hook ([#755](https://github.com/coder/openstorage/issues/755)) ([d9095f3](https://github.com/coder/openstorage/commit/d9095f3aef90b1e706576fbdd30b4d30d35d9c39))
* **gitlimit:** keep only the tail of git's stderr in git errors ([#759](https://github.com/coder/openstorage/issues/759)) ([6d4b1bb](https://github.com/coder/openstorage/commit/6d4b1bb7c9a80761f113146b51a8be75ac3afb55))
* **gitlimit:** signal only process groups whose leader is unreaped ([#696](https://github.com/coder/openstorage/issues/696)) ([50f97fd](https://github.com/coder/openstorage/commit/50f97fd30bae26c8eb4626d8b9ce49f2fcbb276e))
* **gitread:** answer a diff with a type change ([#784](https://github.com/coder/openstorage/issues/784)) ([4a505d0](https://github.com/coder/openstorage/commit/4a505d085b9ac5eff7dd45c26ab1836e562cfd9e))
* **gitread:** decline a tree walk whose cat-file ended before the request ([#774](https://github.com/coder/openstorage/issues/774)) ([3c4337d](https://github.com/coder/openstorage/commit/3c4337d6c9f54be5bb352f14f6e1eda9824e97e5))
* **gitread:** report a failed git call in ResolveRef, never a missing ref ([#749](https://github.com/coder/openstorage/issues/749)) ([c4ce89f](https://github.com/coder/openstorage/commit/c4ce89faf3d4bfe0593f24e31a4dcf42ba5a717f))
* **gitread:** run blame and grep without the repository's attributes ([#781](https://github.com/coder/openstorage/issues/781)) ([5326d70](https://github.com/coder/openstorage/commit/5326d70db35d97a58b00df5e277a5ff37db8c29b))
* **image:** bump alpine runtime base to 3.24.4 (apk-tools 3.0.9 security fix) ([#711](https://github.com/coder/openstorage/issues/711)) ([2b8f86b](https://github.com/coder/openstorage/commit/2b8f86be9e1c680ed590565ca533c8e5d6f52335))
* **jobs:** give the orphan sweep and LFS reclaim their own River queues ([#691](https://github.com/coder/openstorage/issues/691)) ([5279b5b](https://github.com/coder/openstorage/commit/5279b5b5aa5fdee7fc5435053f86f61ca04001d6))
* **jobs:** give the repository purge its own budget in a sweep job ([#692](https://github.com/coder/openstorage/issues/692)) ([96a88ad](https://github.com/coder/openstorage/commit/96a88ad3d60c6e6c6b0b584d3c6f145d5212fbf7))
* **jobs:** never complete a sync job while its sync claim is held ([#716](https://github.com/coder/openstorage/issues/716)) ([d42b6c7](https://github.com/coder/openstorage/commit/d42b6c79b7c87c4fc3f337948ca37cc733fbbc94))
* **jobs:** requeue PostgreSQL lanes whose durable work has no River job ([#726](https://github.com/coder/openstorage/issues/726)) ([2c1c74f](https://github.com/coder/openstorage/commit/2c1c74fe20c44122607101527e0b1eb60b05d270))
* **jobs:** return the sweep job shortly after its context ends ([#730](https://github.com/coder/openstorage/issues/730)) ([bcb2444](https://github.com/coder/openstorage/commit/bcb2444df17dedb2b1417053353092a0a315698d))
* **jobs:** run each quarantine heal entry under its own deadline ([#693](https://github.com/coder/openstorage/issues/693)) ([570f2ae](https://github.com/coder/openstorage/commit/570f2ae5a42925894b8f01720b8136b4fb89652c))
* **jobs:** warn when a reclaim run is skipped and pin the guard's reset and order ([#731](https://github.com/coder/openstorage/issues/731)) ([cb51ae2](https://github.com/coder/openstorage/commit/cb51ae28db29507c91e9f0be2ca5f4067ff98942))
* keep only the tail of git's stderr in every git runner's error ([#776](https://github.com/coder/openstorage/issues/776)) ([50df23a](https://github.com/coder/openstorage/commit/50df23a2d2020b2e66e2a662938a1ade75572716))
* list repos for a q or prefix of any length, and refuse NUL and invalid UTF-8 ([#783](https://github.com/coder/openstorage/issues/783)) ([e6be273](https://github.com/coder/openstorage/commit/e6be2732f8aa577043f46a494ff3f6514c7bbeec))
* **ref:** make ReplacePacks honor the purge fence ([#704](https://github.com/coder/openstorage/issues/704)) ([d7896ef](https://github.com/coder/openstorage/commit/d7896ef4488ced6c2238f100f4ecea38cfb0a687))
* refuse read paths outside the repository, and read blame and grep failures right ([#772](https://github.com/coder/openstorage/issues/772)) ([85b7d83](https://github.com/coder/openstorage/commit/85b7d836eb9b65879c4faa681b924e850ae21362))
* run every git child without replacement objects ([#777](https://github.com/coder/openstorage/issues/777)) ([f6a8329](https://github.com/coder/openstorage/commit/f6a83290bbfe0cf0559f97b00a53cfd204d38405))
* **s3wal:** log the quarantine cause once and tighten the meta.json fuzz harness ([#682](https://github.com/coder/openstorage/issues/682)) ([1a93067](https://github.com/coder/openstorage/commit/1a93067ba8465a8f37001a5d937b48ada51a9739))
* **scripts:** keep tab stops when a Markdown container prefix is dropped ([#751](https://github.com/coder/openstorage/issues/751)) ([2c07fca](https://github.com/coder/openstorage/commit/2c07fca2e420c4e7c4423084318ed030db1f1ca7))
* **scripts:** lex JavaScript in the citation checker and stop where it is unsure ([#723](https://github.com/coder/openstorage/issues/723)) ([aa48d35](https://github.com/coder/openstorage/commit/aa48d3583594a16d1e80f8d7f1e26a986d437c1e))
* **scripts:** read line ends, index flags and list items as their tools do ([#738](https://github.com/coder/openstorage/issues/738)) ([0b3a1e2](https://github.com/coder/openstorage/commit/0b3a1e2003594a6a27736fe228ee5db6dfd28d06))
* **serve:** refuse an intent-recording ref update when the hook cannot wire its eventing ([#724](https://github.com/coder/openstorage/issues/724)) ([03cc9f2](https://github.com/coder/openstorage/commit/03cc9f236c96780532cfd79b5a670e66ae452d7d))
* **sync:** hold the ref and record forward intent before a REST write's CAS ([#737](https://github.com/coder/openstorage/issues/737)) ([dc0dcfe](https://github.com/coder/openstorage/commit/dc0dcfe68dc67afddfd3c3f2e854da4826e2b6a0))
* **sync:** never lose a PostgreSQL forward between the ref CAS and its push run ([#679](https://github.com/coder/openstorage/issues/679)) ([faea6e1](https://github.com/coder/openstorage/commit/faea6e1b5f1637895970679875447f17f2c8882d))
* **sync:** record git forward intent before the CAS and refuse stale held snapshots ([#678](https://github.com/coder/openstorage/issues/678)) ([1996cc3](https://github.com/coder/openstorage/commit/1996cc32f37800afe260e2b20e6d856c67643cf4))
* **sync:** refuse stale held snapshots on PostgreSQL and restore River push runs ([#762](https://github.com/coder/openstorage/issues/762)) ([a0635de](https://github.com/coder/openstorage/commit/a0635de0a9c3dbc1f46ede8f1832e867f921f1fe))
* **sync:** run the worker's git without replacement objects ([#779](https://github.com/coder/openstorage/issues/779)) ([ffd0e9f](https://github.com/coder/openstorage/commit/ffd0e9f46922e1a90c7d007f06de038503ebeb28))


### Performance Improvements

* **api:** resume a recursive files page at its cursor ([#715](https://github.com/coder/openstorage/issues/715)) ([3ad97da](https://github.com/coder/openstorage/commit/3ad97da3ee5e152425391c1b2327e667c9479b04))
* **gitread:** join a git call's output once ([#750](https://github.com/coder/openstorage/issues/750)) ([df18c1b](https://github.com/coder/openstorage/commit/df18c1b9e9f5d12de90624700b9eeac6aabc2fc9))
* **meta:** lower a repo list filter once per query on PostgreSQL ([#785](https://github.com/coder/openstorage/issues/785)) ([3ceb600](https://github.com/coder/openstorage/commit/3ceb600e83b8a91d7d0e13a4aa90d66d423a552c))

## [0.19.0](https://github.com/coder/openstorage/compare/v0.18.0...v0.19.0) (2026-10-30)


Expand Down