Repository navigation
Open
Container
2 / 22 of 2 issues completed
Copy link
Description
Every app release, and the Keycloak image of the platform, yields an attested private image in GHCR that the platform pins by digest.
Caller
- platform#1, slice P1, target picture under Images: every app image is built in its own CI and stored privately in GHCR, and the PC pulls it with a read-only token.
- The operator, hal head chat, 06.11.2026, on model weights: „den besten weg gehen … wenn sie in ein volume gehören sollten wir das so machen oder nicht idk“. Where weights live is decided per service here, by what serves best.
- One release path for the fleet: quality's release gate, image build and tag workflows quality#364 owns the reusable
imageworkflow as its own slice, with hopin as first caller. Platform's inputs for it are posted there (comment of 06.11.2026); quality's head confirmed they fit its cut. The bump from a release to Flux stays this item's.
What is known
- The interface (proposal on quality#364): one image per call; outputs
digestandref; platformslinux/amd64; one optionalbuild-secretssecret as BuildKit mounts;push: falsefor the pull request proof. - Tags: apps keep their
v*tags; images are built only for a release (hal ruling of 16.10.2026: only av*tag goes live). - Sizes of the images on the PC: Platform on k3s and Flux: from an empty PC to every app live, with hal archived #1, third comment.
Ruled
- The bump path (the operator, 06.11.2026, platform's head tab; recorded on Platform on k3s and Flux: from an empty PC to every app live, with hal archived #1): right after a release, the release's last job opens the bump pull request in platform through an organisation GitHub App installed only on platform, with write access to code and pull requests. Several releases a day update the same pull request; he merges, then Flux deploys. Dependabot's docker ecosystem is not used for app images. His words: „so dass ich sofort updaten kann wenn ich will?“ and „das macht ja hal apply gerade bzw hal update und hal apply? … sonst muss ich ja warten?“
- The guard: platform's CI refuses a bump whose app tag is missing or points at another commit than the attested image; quality#364's
imagebuilds no guard of its own (quality's head, 06.11.2026).
Open, settled at this item's cut
- Weights per service: speech-runtime bakes them so it runs with no egress; songmaker's scoring worker bakes 3 GB of Whisper weights and uses an HF token in the build; songmaker's acestep image holds no weights. Decided after the runner-disk measurement.
- GHCR: private-only package creation in the organisation, and the PC's read-only pull credential, which is a secret and lands with P4.
Neighbours
- After an appkit bump Keycloak links a stylesheet hal apply has deleted, until someone restarts it hal#908 (Keycloak's theme built into its image).
- hopin#459 line 10, the GHCR push in hopin's own item; speech-runtime#110; songmaker#2284, whose auto-deploy exits in P11.
- P3 (the manifests that pin the digests) and P4 (the pull credential).
version = 1
now = "quality#364's image workflow releases hopin and speech-runtime as attested private images, which run on the PC. Children landed: #49 (the images job judges every ref) and #83 (21046c9, it refuses HelmRepository and HelmChart too). quality#364 stays open for the rest of the fleet's release path."
next = "Each remaining app (presentator, songmaker, skat, Keycloak's theme image) gets its attested release at its move; the bump path's plan follows the app standard (#126)."
done_when = "quality's image workflow ships; every app's release and the Keycloak image yield an attested private GHCR image; the bump path from a release to a platform pull request is decided, built and proven once; the weights of each service have their decided home."
size = "L"
Metadata
Metadata
Assignees
Labels
No labels
Activity
FlexOr2 commentedon Nov 6, 2026
Inputs for this item's cut, from the plan for P2 to P4 (v3, 06.11.2026; plan review Codex gpt-6-astra high and Opus 5.5 high: APPROVE).
The operator's ruling on the bump path (the "Ruled" section above, a GitHub App opening the pull request right after a release) binds over the plan text below. So the plan's Dependabot route (D5 route A) and its Dependabot spike B1 are not built. What carries over to the cut:
Verbatim below.
D5. The bump path from an app release to a platform pull request
Releases flow: release-gate, then
image(outputsdigestandref), then release-tag (quality#364). So an image canexist in GHCR whose release-tag step failed afterwards.
releaseenvironment in each app repositorydockerecosystem on the Flux treedependabot.yml@sha256(Opus table row 13). OrdersvYYYY.MM.DD.Nnumerically oncevis stripped, but only among tags of the same precision: a tag without.Nis silently skipped (Opus table row 15). It may propose an image whose release-tag step failed; the eligibility check below makes that pull request red.workflow_dispatchandrepository_dispatch(https://docs.github.com/en/actions/concepts/security/github_token)renovate.jsondocs/gate.mdnames Dependabot for workflow pins; it bans no other image tool, so this is upkeep, not a rule.Recommendation: B, gated by the spike in B1 (an app's real release yields a Dependabot pull request in platform
from
…:vA@sha256:xto…:vB@sha256:y). If the spike fails, or the operator wants minutes instead of hours (Q4), B2first weighs Renovate's self-hosted action and a maintained pull request action against A before anything is written.
Release eligibility (revised for Opus v2 follow-up 2). A bump is mergeable only for a completed release. Platform
CI gets a job
images, inmandatory_jobsandquality.needs(plan invariant 4), that runs on every pull request andpush and checks every
ghcr.io/overnightworks/…ref in the Flux tree (apps/andinfrastructure/, so theplatform-built Keycloak image is covered; not only changed refs, so it needs no diff logic and a later tag deletion
also shows). Third-party images (the local-path provisioner, Traefik's chart) are outside it. Per ref
ghcr.io/overnightworks/<repo>[/<name>]:<version>@sha256:<digest>:git ls-remote https://github.com/overnightworks/<repo> refs/tags/<version>(quality#364's tag islightweight, so no peeling) yields the tag's commit; no tag means red, naming the missing tag.
<repo>is theimage path's first segment after the owner: an app image is named after its repository.
signature.certificateand theverifiedTimestampsproperties contain values that cannot be manipulated by theworkflow that originated the attestation" and warns about
statement.predicate; so the job reads nothing from thepredicate and runs
gh attestation verify oci://<ref> --repo overnightworks/<repo> --signer-workflow overnightworks/quality/.github/workflows/<image workflow> --source-digest <tag's commit> --source-ref refs/heads/main --predicate-type <the type quality#364's actions/attest writes> --deny-self-hosted-runners(flags fromgh attestation verify --help, gh 2.103.2).--repoties the image to itsown app's repository;
--source-digestties it to the tagged commit;--source-refholds because quality#364'sgate refuses a ref other than main. gh defaults
--predicate-typetohttps://slsa.dev/provenance/v1; the jobpasses the value explicitly, matched in B1 against quality#364's landed workflow (its body says "provenance
mode=max, an SBOM andactions/attest", so an SBOM attestation of another type may sit beside it).--signer-workflowpins no ref. Pinning one quality commit with--signer-digestisrejected: each app pins its own quality sha and Dependabot moves it, so platform would hold a copy of every app's
pin. Instead the job reads the signer digest from
signature.certificate(unforgeable; exact field name unverified,B1) and requires it to be a commit on quality's main (GitHub's compare API,
aheadoridentical), so an imageworkflow edited on a quality branch does not pass.
release.ymlcalling quality's image workflow (quality#364lists "platform's Keycloak" as an app caller), so its
<repo>isplatformand its tag a platformv*tag. Itsname must keep the first-segment rule (for example
ghcr.io/overnightworks/platform/keycloak; GHCR names withseveral segments unverified); naming it is the Keycloak item's at P6, and B1 builds nothing for it without that
caller.
Because quality#364 creates the tag last, an existing tag at the attested commit means gate, image and tag all
completed. The failed-release case (image pushed, tag step failed) has no tag: the job is red and the Dependabot pull
request cannot merge (main requires
quality / verdict). If the tag step is re-run successfully, a re-run of the jobturns green; the next release supersedes the pull request either way.
Alternative weighed: quality#364 pushes only a digest and adds the GHCR
v*tag after the git tag, so Dependabot neversees an unreleased version. It would spare red pull requests, but it changes quality#364's design, and platform must
verify what it deploys anyway. Named to quality#364 as an option, not a demand.
Constraints on P6's layout and the apps: image refs stay in a Deployment's
image:field (Dependabot support forkustomize
images:or HelmRelease values is unverified); app tags keep four parts until quality#364 decides the appgrammar; an image's first path segment is its source repository; each private package grants platform Read (for
Dependabot and for the
imagesjob'spackages: read).Item #4: bump path (its open part)
Invariants kept: 2, 3; the bump never changes anything but an image ref; merging stays a person's yes (head decision,
section 4) until P10 re-asks.
pull request in platform that moves
ghcr.io/overnightworks/hopin:vA@sha256:xtovB@sha256:y, and theimagesjob (D5) holds every cell below.
Files:
.github/dependabot.yml(thedockerentries for the Flux tree's directories, schedule);.github/workflows/ci.yml(jobimageswithpermissions: contents: read, packages: read;quality.needsgains
images);quality/config.toml(mandatory_jobsplusimages);scripts/verify_image_release.sh(about 30 lines: parse each ref,
git ls-remote,gh attestation verifywith D5's flags, the signer-digest check;it only calls gh and git).
Outside the diff: the package grant (platform Read under "Manage Actions access"), one per package, by the operator
or the head.
Settled against quality#364's landed workflow before the job is written: the image workflow's file name, the
--predicate-typevalue, and the certificate field holding the signer digest.Depends on quality#364 (image), P6's hopin manifest, P4d.
Cells (release eligibility, material risk):
vB(tag at the attested commit)imagesgreen; the Dependabot pull request mergeableimagesred naming the missing tag;quality / verdictredvB@<digest of vA>)--source-digest)--signer-workflow)packages: readworks or the gap is named--repo)--predicate-typediffers (for example the SBOM attestation alone)statement.predicateDocumentation: README's "shipping an app" line, once true; the four-part tag and first-segment naming constraints
to quality#364 and the app heads.
Verification: the observed pull request; CI; the cells.
Review: material risk (release eligibility is what keeps "only a
v*tag goes live"): cross-provider gate.Rollback: remove the entry and the job (a declared loosening for the removed mandatory job).
Deletes: songmaker's auto-deploy and the others in P11, named on Platform on k3s and Flux: from an empty PC to every app live, with hal archived #1.
Named gaps: who may create
v*tags in an app (a tag ruleset) is the app's and quality#364's (its opencreationrule); a fork pull request in platform could read private images through
packages: read, held by GitHub'sapproval for outside contributors' workflows; the Keycloak image's name and tag scheme (D5 point 4) are the
Keycloak item's at P6.
request action against route A, then build the cleanest; done when the same pull request appears within minutes and
E1 to E4 and E7 to E9 still hold.
Unknowns rows for this item (plan section 5):
| Unknown | Settled in |
|
packages: readfor Dependabot-triggered runs; the package-grant API | P4d, B1 || Dependabot's cron minimum; the image workflow's file name, its predicate type and the certificate field holding the signer digest | B1 |
FlexOr2 commentedon Nov 6, 2026
Facts from quality's head (06.11.2026) for B1's check. The operator gave quality#364's
imageworkflow top priority in quality's session; it is planned and built now, beside slice 1b (release-tag) and the gate's app version form.vYYYY.MM.DD.N, which is today's practice. hopin, presentator, songmaker and speech-runtime tag this way, read through the tags API. Month and day are zero-padded; N starts at 1. The gate adopts it in its own small lane.ghcr.io/overnightworks/<repo>[/<name>], formed from the caller's repository. The first segment is the app repository, as B1 assumes.actions/attest-build-provenance, pushed to the registry. Still to be confirmed once quality's plan is written: the exact action, and whether the SBOM is a second GitHub attestation or BuildKit's in-image SBOM.refs/heads/mainfor a dispatched release, since quality's gate refuses any other ref. Dispatch is the standard's only path..github/workflows/image.yml. B1 passes--signer-workflow overnightworks/quality/.github/workflows/image.yml. It also requires the certificate's signer digest to be a commit on quality's main.release-tag(1b), or from an app's hand-pushed dated tag until 1b lands.FlexOr2 commentedon Nov 6, 2026
quality's
imageworkflow has landed: quality#402, PR #404, merge89069a1a97e1ef9da92f1cc37b45064e21962f77(quality's head, 06.11.2026).uses: overnightworks/quality/.github/workflows/image.yml@89069a1a97e1ef9da92f1cc37b45064e21962f77. quality has no tag before The legal sections and their declared Stand move to platform #228's R.context,file,target,image,version,build-args,push,cache.imageis the sub-name below the repository's path; empty means the repository itself.versionis a valid Docker tag.push: falseonly builds.cacheis off by default.build-secrets, passed by name. There is nosecrets: inherit.digest, andref=ghcr.io/<owner>/<repository>[/<image>]:<version>@<digest>, lowercased.attestations: write,contents: read,id-token: write,packages: write.github.sha, linux/amd64 only.actions/attestwrites SLSA provenance v1, pushed to the registry, with no storage record.mode=maxand an in-image SBOM (sbom: true). The SBOM is not separately signed.--predicate-type https://slsa.dev/provenance/v1(the default).YYYY.MM.DD.Nthrough an optionalforminput.FlexOr2 commentedon Nov 6, 2026
presentator's caller of quality's image workflow is overnightworks/presentator#851 (template hopin#537, blocked by quality#406 and quality#407). It builds one image: the sealed build worker runs the same image with its own command. What a Deployment needs (uid, volumes, port and health, one replica, file secrets, the worker's seal, and the open question of where the worker runs) is in overnightworks/presentator#851 (comment).
FlexOr2 commentedon Nov 6, 2026
GHCR storage and retention (platform's head, 06.11.2026).
GITHUB_TOKENnever counts.ghcr.io/overnightworks/songmaker/{web,music-worker,scoring-worker,acestep-worker}.FlexOr2 commentedon Nov 7, 2026
Caller: overnightworks/hopin#561, blocked by this item (hopin's head, 07.11.2026). It adds the bump workflow as the last job of hopin's release.yml and passes the Image job's ref and digest. hopin's release.yml has only the jobs Gate, Image and Tag today, so the bump pull request into platform does not exist yet; until it does, a pin changes by a hand-written platform pull request the operator merges. Once the workflow has a ref, hopin's head starts #561.
docs/github-settings.md holds the six ruled sentences on GitHub setti…
docs/VISION.md states what the platform promises, for whom, and what …