Verified bundle download with a pre-GA fallback on master - #158
Merged
Conversation
The image build fetched the app bundle with a bare `curl -sL .../public/bundles/simplerisk-<version>.tgz | tar xz`. Two problems. 1. public/bundles/ is the GA path, written only by propagate_release_bundle at the testing -> master cut. But bump_downstream_versions opens the docker update-<version> PR at the TESTING cut, from base master -- so the version it pins has no prod bundle yet and container-validation fails on every release. Observed on update-20260709-001, update-20260811-001 and update-20260820-001. 2. Without --fail, curl streams the S3 error document into tar, so the failure surfaces as a tar exit code rather than an HTTP status. The real cause is invisible in the log, which is how this got misread as expected behaviour. The fix already exists on the testing branch and is ported here. PR #146 attempted this in July and was correctly closed: it added the ARG, the COPY and the generator changes but never added the script itself, so it would have failed at COPY. common/download_and_verify_bundle.sh (identical in both build contexts, taken verbatim from testing) downloads the prod bundle, resolves its published sha256 (md5 fallback) from the prod updates feed, and verifies before extracting. Fail-closed by default: a missing bundle, a missing feed hash or a mismatch aborts the build, so a swapped S3 object cannot be baked into a published image. PREGA_BUNDLE_FALLBACK=true -- set ONLY by container-validation -- allows a pre-GA build to fall back to bundles-test without verification, warning loudly, because a release has no published hash before GA. Ported surgically rather than copied. The testing branch's versions of these files also carry a PHP default bump (8.4 -> 8.5), a new source_mode generator parameter, an added php85 validation job and a trigger change -- all unrelated, none included here. Verified after patching: php_version is still 8.4, there are no source_mode references, and the container-validation diff is exactly four build_args lines. Patched the GENERATORS and re-ran them rather than editing the Dockerfiles: the Dockerfiles are generated, and make update_version regenerates them on every version bump, so a hand-edit would be silently overwritten. Also fixed the SQL fetch in the full-stack image, which had the same missing --fail: `curl -sL ... > /simplerisk.sql` writes a 404 body to disk, so the image would ship an HTML error page as its database schema. Verified by running the script in the real alpine/curl:8.12.1 downloader image across all three paths: fail-closed on a pre-GA version without the flag (exit 1), pre-GA fallback to bundles-test with the flag (exit 0, warned, extracted), and the verified-prod path against a GA version that exists. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
container-validationfails on every release-bump PR, and has since at leastupdate-20260709-001. This is the fix, ported from thetestingbranch where it already works.Why it fails
The image build fetched the app bundle with a bare pipe:
public/bundles/is the GA path — written only bypropagate_release_bundleat thetesting → mastercut. Butbump_downstream_versionsopens the dockerupdate-<version>PR at the testing cut, from basemaster. So the version it pins has no prod bundle yet, and validation fails until GA.Confirmed across three releases:
update-20260709-001,update-20260811-001,update-20260820-001— all red, while unrelated PRs from the same weeks passed because they build against an already-published GA bundle.Second, subtler problem:
curl -sLhas no--fail, so the S3 error document is streamed intotarand the failure surfaces as a tar exit code rather than an HTTP status. The real cause never appears in the log. That is precisely how this got misdiagnosed as expected-at-RC behaviour rather than a bug.The fix
common/download_and_verify_bundle.sh(identical in both build contexts, taken verbatim fromtesting) downloads the prod bundle, resolves its publishedsha256—md5fallback — from the prod updates feed, and verifies it before extracting.Fail-closed by default. A missing prod bundle, a missing feed hash, or a hash mismatch aborts the build. A swapped S3 object therefore cannot be baked into a published image, and the bundle and its hash come from independent sources (S3 object vs. served feed).
PREGA_BUNDLE_FALLBACK=true— set only bycontainer-validation, never for a released image — lets a pre-GA build fall back tobundles-testwithout verification, warning loudly. That path exists because a release genuinely has no published hash before GA.On PR #146
#146 attempted this in July and was correctly closed. Its diff adds the
ARG, theCOPYand the generator changes but never adds the script, so it would have failed atCOPY common/download_and_verify_bundle.sh. The complete implementation later landed ontestingonly — which is why the bug persisted onmaster, the branch the bump PRs are actually cut from.Ported surgically, not copied
testing's versions of these files also carry changes unrelated to this bug, none of which are included here:testing8.4→8.5source_modegenerator parameter (context|download)php85validation job,php83/php84job renamesbranches: [master]→[master, testing]Verified after patching:
php_versionis still8.4, there are zerosource_modereferences, and thecontainer-validation.ymldiff is exactly the fourbuild_argslines.Generators, not Dockerfiles
The Dockerfiles are generated (
# Dockerfile generated by script) andmake update_versionre-runsgenerate_dockerfile.shon every version bump. So I patched the generators and re-ran them to produce the Dockerfiles. Editing the Dockerfiles directly would have been silently overwritten by the next bump.One more defect found while in there
The full-stack image's SQL fetch had the same missing
--fail:Without
--fail, a 404 body is written to/simplerisk.sqland the image ships an HTML error page as its database schema. Now-fsSL.Validation
Ran the script in the real
alpine/curl:8.12.1downloader image across all three paths:PREGA_BUNDLE_FALLBACK=false, pre-GA versionrefusing to build a release from unverified bytesPREGA_BUNDLE_FALLBACK=true, pre-GA versionbundles-testExtracted bundle to /var/www.PREGA_BUNDLE_FALLBACK=false, GA version present20260519-001, the current GA)So the security property holds in both directions: a released image can only be built from the hash-verified prod bundle, and unverified bytes require the explicit CI-only flag.
Also confirmed the surrounding facts rather than assuming them: GA is currently
20260519-001(agreed acrosscode-developmentmaster, the prod feed,public/bundles/, and this repo's pinned version), so20260811-001and20260820-001are RC-only and their absence frompublic/bundles/is correct.container-validationon this PR is the live test — it builds all four images with the fallback enabled against amasterstill pinned to the current GA release, so it should exercise the verified prod path, not the fallback.Follow-up (not in this PR)
After this merges,
bump_downstream_versionsshould be re-dispatched soupdate-20260820-001is regenerated from the fixedmaster. The existing branch was cut before this change and will keep failing until it is.