Container package bootstrap flow
Overview
A manually dispatched GitHub Actions run creates missing GHCR packages using harmless marker images. GitHub creates new marker packages as private; bootstrap does not change visibility or access grants. Existing public or private packages can pass bootstrap when their package identity and explicit repository linkage match. Before Enterprise source images or the chart can publish, an operator must make every selected package public. Bootstrap ends after package metadata and marker digests verify. Enterprise publication and recovery each need their own dispatch; recovery reuses retained archives after an interrupted publication.
Entry Points
.github/workflows/container-bootstrap.yml:jobs.bootstrap: manual dispatch onmainwith the successful exact-source main-push CI run ID.scripts/ci/container-bootstrap.ts:main: main-only job withactions: read,contents: read, andpackages: write; explicit destination variables select two different GHCR packages in theopenclaworganization..github/workflows/container-resume.yml:jobs.publish: manual recovery using retained archives from an unchanged producer run attempt.
Flow
graph TD
A["Operator dispatches bootstrap"] --> C["Runner verifies public main source, CI and branch policy"]
C --> D["GitHub returns destination metadata"]
D -->|invalid existing package or API error| X["Run fails"]
D -->|valid public or private package or 404| E["Build scratch marker from temporary context"]
E --> F["Recheck gates and package metadata"]
F -->|valid existing package| G["Keep package unchanged"]
F -->|404| H["Copy marker with workflow token"]
H --> I["Wait for metadata and verify remote digest"]
I -->|mismatch| X
I -->|verified| J["Record marker in job summary"]
G --> K["Continue to next package"]
J --> K
K --> L["Operator completes package setup for Enterprise publication"]
R["Operator dispatches recovery of retained archives"] --> S["Verify recovery CI and original preparation"]
S --> U["Verify original seals, CI and public packages"]
U --> V["Inspect authenticated remote source tag"]
V -->|matching digest| W["Keep existing image"]
V -->|manifest unknown| Y["Copy original archive and verify digest"]
V -->|conflict or other error| X
W --> Z["Repeat for both images then write recovery receipt"]
Y --> ZThe diagram describes implemented control flow; it does not establish that a hosted bootstrap or subsequent release has succeeded.
Execution Trace
1. Validate the approved source and destinations
scripts/ci/container-bootstrap.ts:main reuses
scripts/ci/container-release.mjs:verifyMainSource, verifyCi, and
verifyEnvironment. Source equals the trusted main workflow source commit and
checkout. The repository is public, exact-source main-push CI succeeds, and the
environment disables admin bypass and permits only branch main. Invalid context fails before a registry write.
Each configured package name passes ghcrPackageName. Existing metadata must
pass validatePackage for public or private bootstrap visibility and, when
returned, exact public repository linkage. GitHub's optional repository field may be absent or null.
Both bootstrap and publication accept omitted linkage without an approval
comment. Operators configure the package connection and Actions access at setup.
Only bootstrap opts into github's 404 result; normal publication still fails
on missing metadata. A 404 can also hide inaccessible packages, so it authorizes
only the non-sensitive marker attempt. Authorization and other API errors fail.
2. Build and transfer only marker bytes
scripts/ci/container-bootstrap.ts:main creates a temporary context with a
scratch Dockerfile and fixed text marker. Repository source and source commit labels
link the image to Enterprise. Docker exports linux/amd64 OCI bytes without
copying the checkout, fetching a base image, or receiving registry credentials.
Skopeo authenticates using the workflow token over stdin and a temporary auth file.
For the chart marker, scripts/ci/chart-package.ts:pushChart checks Helm's exit
status and reads the pushed digest from stderr before bootstrap checks the remote
manifest digest. A missing digest or failed push stops the run.
Before each transfer, the helper repeats source, CI, environment, and package checks. Valid existing packages remain unchanged. A 404 permits copying the marker under a unique run/attempt tag. The helper retries post-push metadata 404s up to five times, two seconds apart, then requires acceptable bootstrap metadata and a matching remote manifest digest. Other API errors fail immediately. A failed post-push check fails the run and leaves the harmless marker for operator inspection; it changes no grants or visibility and performs no automatic deletion.
3. Hand verified packages to release operators
scripts/ci/container-bootstrap.ts:main records each existing or bootstrapped
package in the job summary and removes the temporary context, archive, and auth
file in finally. Bootstrap and publication share the same workflow concurrency
lock, which does not constrain external package administrators. Partial success
is possible. The operator follows the existing publication procedure to build,
smoke and publish actual Enterprise images.
scripts/ci/container-release.mjs:verifyGhcr is shared by publication and promotion.
It checks public package identity and rejects conflicting repository metadata.
When GitHub omits repository metadata, it accepts the omission without querying
approval history. Package linkage is configured during
operator setup.
4. Recover retained publication bytes after a partial failure
.github/workflows/container-resume.yml runs validation without registry write
permission, then uses the same main-only environment and concurrency lock as
publication. scripts/ci/container-resume.ts:verifyPreparation checks the
current recovery workflow's main-push CI separately from the original image
source. The original producer must be the trusted publication workflow on main,
completed at the unchanged selected attempt, with successful validation, all four
native platform jobs and both image assembly jobs on the original source SHA. A
complete older run that prepared each image in one job is still accepted. Exactly
named, nonexpired artifacts must belong to that run
and source; the workflow downloads their validated IDs with digest checks.
scripts/ci/container-resume.ts:resume preserves the producer identity in each
seal and rechecks original source CI. It calls
scripts/ci/container-release.mjs:publishPrepared, which verifies both archive
hashes and OCI digests before registry writes. Before each image, source, CI,
producer, environment, and public-package metadata are rechecked. A
matching existing source tag is inspected remotely and left untouched, even if
package metadata has not caught up. Only the registry's explicit manifest-unknown
response permits copying an unlisted tag; authorization and transport failures
stop recovery. A conflicting tag or remote digest fails.
Metadata GET requests use a 30-second timeout per attempt and report the endpoint if transport retries fail. No archive
is rebuilt and no original seal is rewritten.
Only after both remote digests match does resume write the recovery receipt,
separating original image provenance from the current publishing run. The
operator retains that receipt and uses digest references from it. The current
Docker Hub promotion workflow does not consume recovery receipts. A failed
recovery can leave one image published; follow the
recovery procedure
without deleting the original archives or rerunning their producer.
Debugging and Verification
-
node --test tests/integration/container-resume.test.tsexercises the recovery CLI with HTTP/transport fixtures; a hosted run must prove actual GHCR transfer. -
node --test tests/integration/container-release.test.mjschecks shared gate behavior, bootstrap 404 handling, and stderr-only Helm push output. The subprocess-stream case does not publish to GHCR. -
Inspect the hosted job summary and authenticated package metadata for both destinations. Marker success proves package bootstrap, not Enterprise availability.
-
A package or metadata permission failure needs operator access repair. Keep the main-only environment policy and public-package checks enabled.
-
Missing repository metadata does not require an approval comment. An explicit wrong repository always fails.
-
Treat
bootstrap-*as non-deployable markers. Release evidence comes from the separate publisher's receipt and authenticated image digest verification.
