Fetch Alpine.js at build time under a verified hash (closes #145)
All checks were successful
check / check (push) Successful in 3m29s
All checks were successful
check / check (push) Successful in 3m29s
static/js/alpine.min.js was a committed minified bundle: unreviewable, referenced by no hash, and forbidden by REPO_POLICIES.md on both counts. It is now fetched by script/fetch-assets from a pinned npm registry tarball, with the tarball sha256 and the extracted file's sha256 both hardcoded and checked before anything is installed. The hash of every installed asset lives in static/vendor.sha256, and static/vendor_test.go re-hashes the bytes go:embed actually put in the binary against that manifest, so the pin is enforced on what ships rather than merely recorded. .gitignore keeps the artifact out of the repo and .dockerignore keeps a host copy out of the build context, so the image can only get it by fetching and verifying it. Alpine 3.14.9 is byte-identical to the blob that was committed (3ed1eed252488921df65e363d6715deb04d7f92aaedb9e52199fdf73cb1e0ad3), so the served asset does not change; internal/server/static_assets_test.go fetches every /s/ script base.html loads through the real router to prove the page still gets it.
This commit is contained in:
24
README.md
24
README.md
@@ -40,6 +40,7 @@ make docker
|
||||
```bash
|
||||
make bootstrap # Install all dependencies (idempotent)
|
||||
make setup # Bootstrap + install git pre-commit hook
|
||||
make assets # Fetch + verify third-party browser assets
|
||||
make fmt # Format code (gofmt + goimports)
|
||||
make lint # Run golangci-lint
|
||||
make test # Run tests with race detection
|
||||
@@ -247,6 +248,8 @@ them. We provide:
|
||||
- `script/setup` — make a fresh clone ready for development
|
||||
(bootstrap, then install-precommit)
|
||||
- `script/projectname` — output the project name ("webhooker")
|
||||
- `script/fetch-assets` — download the third-party browser assets into
|
||||
`static/`, verifying each against its pinned sha256
|
||||
- `script/test` — run the test suite
|
||||
- `script/lint` — run golangci-lint
|
||||
- `script/fmt` — format all code (writes)
|
||||
@@ -260,6 +263,27 @@ them. We provide:
|
||||
- `script/install-precommit` — install the git pre-commit hook that
|
||||
runs `script/precommit`
|
||||
|
||||
## Third-party browser assets
|
||||
|
||||
The web UI serves one third-party script, Alpine.js. It is **not** committed:
|
||||
a minified bundle in the tree is unreviewable, and `REPO_POLICIES.md` bars
|
||||
both committed build artifacts and unpinned external references.
|
||||
|
||||
Instead `script/fetch-assets` downloads it from a pinned URL, checks the
|
||||
download against a hardcoded sha256, and installs it under `static/`. The
|
||||
sha256 of every installed asset is recorded in `static/vendor.sha256`, and
|
||||
`static/vendor_test.go` re-hashes the bytes `go:embed` put in the binary
|
||||
against that manifest — so the pin is enforced on what actually ships, not
|
||||
merely written down. Any mismatch fails the build.
|
||||
|
||||
`make bootstrap` runs the fetch for local development, and the Dockerfile
|
||||
runs it in the build stage; `.gitignore` and `.dockerignore` keep the
|
||||
artifact out of both the repo and the build context.
|
||||
|
||||
To move to a new version: update the version, URL, and tarball sha256 in
|
||||
`script/fetch-assets` and the asset sha256 in `static/vendor.sha256`, then
|
||||
run `make assets && make check`.
|
||||
|
||||
## Rationale
|
||||
|
||||
Webhook integrations between services are inherently fragile. The
|
||||
|
||||
Reference in New Issue
Block a user