0003-owner-scoped-access.patch changes authorization, applied after the de-brand and dark-theme patches: - a bucket's ACL and policy may name only the owner's keys (accounts on the owner's UserID), whoever writes them, root included; - public access is read-only: all-users READ, and "*" allowed only s3:GetObject and s3:ListBucket; - the bucket policy never denies the owner's key; - DeleteBucket, PutBucketVersioning, PutObjectLockConfiguration and PutBucketOwnershipControls are reserved to root and admins; - an ACL with the all-users READ grant can be written back unchanged. docs/owner-scoped-access.md has the rules, what v1.11.0 already did, and the leil-rig proof procedure with its 2026-11-10 result: 63 of 63 on the patched build, 29 of 63 failing on stock v1.11.0. tests/owner-scope/ holds the proof script and a stdlib-only SigV4 request helper. README and the pipeline doc list the patch and how to re-verify it after a rebase. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7.0 KiB
Multi-version build pipeline
How s3-gateway turns an upstream versitygw release into a de-branded build, and how to keep it tracking new upstream versions. This mirrors the scoutfs-build / scoutfs-notify model, collapsed into one repo because the patch set is small.
CI builds one version per run — triggered by a tag push or a manual dispatch, never on a schedule.
The flow
Each build is four steps, run for a single upstream tag:
-
ci/clone-source.sh— shallow-clones upstream versitygw at a tag intosrc/. Tag selection priority:VGW_TAG(the dispatch input, or a manual run),- the pushed tag (
GITHUB_REF=refs/tags/...), - the latest remote
vX.Y.Ztag. The checkout forcescore.autocrlf=falseso the tree is byte-for- byte upstream (LF) and the LF patches apply on any host.
-
ci/apply-patches.sh— resolves the patch directory for the tag fromci/support-matrix.yaml(patches:field, default = tag name) and appliespatches/<dir>/*.patchwithgit am --whitespace=nowarn --3way, in filename order. The--3wayfallback is what lets a series rebase across minor upstream drift. A tag the matrix does not list is refused (exit 1), as is a patch directory that turns out to be empty — either would otherwise publish an un-de-branded or superseded build. -
ci/build.sh— runsgoreleaser release --clean --skip=validate,publishinsrc/, producing binaries + deb/rpm insrc/dist/. Because the patch commits sit on top of the tag, HEAD is no longer exactly the tag, so we setGORELEASER_CURRENT_TAGto pin the stamped version and--skip=validateto bypass the dirty/tag checks. Upstream's.goreleaser.yamlis used unmodified — artifact names stayversitygw. -
ci/publish-release.sh— creates (or reuses) a Gitea release for the tag in this repo and uploadssrc/dist/*as assets. Idempotent: re-running for the same tag replaces existing assets.
Patch registry: ci/support-matrix.yaml
versitygw:
- tag: v1.11.0
patches: v1.11.0
tag— upstream git tag.patches— directory underpatches/to apply (defaults totag). Point several tags at one directory if the same series applies to a range of upstream releases.
apply-patches.sh consults this to find the patch directory for the tag
being built; with the default patches/<tag>/ naming it doubles as a
human-readable record of which versions are maintained.
It is also an allowlist, which is the mechanism that keeps
superseded versions from being rebuilt: a tag absent from the matrix
makes apply-patches.sh exit 1. Only PATCH_DIR bypasses it, and only
explicitly — that is how an archived series is rebuilt on purpose.
The matrix is read with yq when it is installed and with a small
awk parse otherwise, so the allowlist still applies in the stock
golang CI container, which has no yq.
Adding a new upstream version
When upstream releases vX.Y.Z:
-
Rebase the patch series onto the new tag in a throwaway clone:
git clone https://github.com/versity/versitygw vgw && cd vgw git -c core.autocrlf=false checkout -b debrand vX.Y.Z git config user.email you@example.com && git config user.name you git am --3way /path/to/s3-gateway/patches/<previous-tag>/*.patch # If a hunk conflicts: fix files, `git add -A`, `git am --continue`. mkdir -p /path/to/s3-gateway/patches/vX.Y.Z git format-patch --binary vX.Y.Z..HEAD \ -o /path/to/s3-gateway/patches/vX.Y.Z--binaryis required because the series deletes PNG logo assets. -
Register it in
ci/support-matrix.yaml:versitygw: - tag: vX.Y.Z patches: vX.Y.ZLeave the previous entry in place only if you still want builds of it. If the new release supersedes it — a security fix, say — retire the old one at the same time (see Retiring a version below).
-
Commit and push
ci/support-matrix.yaml+patches/vX.Y.Z/. -
Build it — either push a
vX.Y.Ztag to this repo, or run the build workflow manually and entervX.Y.Z. CI builds that one version and publishes it.
Sanity-check a series before committing
VGW_REPO_URL="/path/to/local/versitygw" VGW_TAG=vX.Y.Z bash ci/run.sh
A clean git am plus a populated src/dist/ means the web UI patches
are good. 0003-owner-scoped-access.patch changes Go code in auth/, so
a clean apply is not enough for it: run its unit tests in the patched
tree, on Linux (on Windows several upstream packages fail regardless),
go test ./auth/ ./s3api/...
and its proof test on leil-rig — see
owner-scoped-access.md.
If upstream has reworked auth/access-control.go or auth/acl.go,
re-read that document's rules against the new code rather than only
resolving the conflict.
src/ may hold someone's local work tree; ci/clone-source.sh deletes
it. Point VGW_SRC_DIR somewhere fresh (any *-src/ name is
gitignored) when in doubt.
Retiring a version
Drop its ci/support-matrix.yaml entry — that alone stops it being
built, since the matrix is the allowlist — and git mv its directory
into patches/archive/<tag>/ rather than deleting it, so the series
stays available for a deliberate rebuild:
git mv patches/v1.8.0 patches/archive/v1.8.0
# then remove the v1.8.0 entry from ci/support-matrix.yaml
Update the table in patches/archive/README.md
and the supported-versions table in the top-level README to match.
Releases already published in this repo are not affected: retiring the patches stops future builds but leaves existing release assets downloadable until you delete them by hand in Gitea.
To rebuild an archived version deliberately, pass PATCH_DIR instead
of re-adding it to the matrix:
PATCH_DIR=patches/archive/v1.8.0 VGW_TAG=v1.8.0 bash ci/apply-patches.sh
CI configuration
- Triggers: a
v*tag push (builds that tag) or manual dispatch with a tag input (one-shot). No cron. - Runner: any Linux runner —
runs-on: ubuntu-latest. The Go toolchain comes from thegolang:latestcontainer, so the runner only needs Docker; nothing version-specific to install. - Container:
golang:latest— pure-Go build, GoReleaser's bundled nfpm makes deb/rpm without rpmbuild/dpkg. - Secret
TOKEN_GITEA: Gitea PAT with write:repository. Used both to clone this repo (the workflow does a manual token-rewritten clone, since a stock container has no Node foractions/checkout) and to publish releases. - Variable
VGW_REPO_URL(optional): override the upstream URL.
Release tagging
Releases are created in this repo with the upstream tag name
(v1.11.0). If you need to ship a rebuild of the same upstream version
(e.g. a patch fix), set RELEASE_TAG in ci/publish-release.sh's
environment to something like v1.11.0-acg2 to avoid clobbering.