From 1eff3cf0b2c93f9ce97b287635e261ca0b6ce661 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 9 Nov 2026 15:55:00 +0000 Subject: [PATCH] chore(main): release 0.20.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 87 +++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 19ee807a..71e95baf 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.19.0" + ".": "0.20.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c7ce8b2..1439af5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)