Distribution
A socle version is two OCI artifacts with the same tag, signed by the same
workflow, publish-artifact.yaml.
Tags and commands are in Artifacts.
| Package | Carries | Pulled by | When |
|---|---|---|---|
ghcr.io/do-now-io/socle/opentofu-modules | the whole commit, as an OpenTofu module package | tofu init, on your runner | before any cluster exists |
ghcr.io/do-now-io/socle/flux-modules | oci/, minus every tests/ folder | Flux, in the cluster | every minute |
Why two, and not one
Section titled “Why two, and not one”The first pull happens where no cluster exists yet, so Flux cannot make it. And one OCI tag carries one manifest type: an OpenTofu module package and a Flux artifact cannot share a name.
Under the hood
The module package is application/vnd.opentofu.modulepkg over one
archive/zip layer, pushed with oras; the Flux artifact is Flux’s
tar+gzip. The package is git archive of the commit, so the bootstrap
module travels in it and a consumer picks a module with //opentofu/<cloud>.
One version for both
Section titled “One version for both”compute-tag.sh runs once per push
and both packages take its tag, so they never drift.
| Trigger | Tag | Signed as |
|---|---|---|
push to main | <next>-alpha.N | publish-artifact.yaml@refs/heads/main |
| push to another branch | 0.0.0-<branch-slug>.<short-sha> | publish-artifact.yaml@refs/heads/<branch> |
| merge of the release PR | <next>, a second tag on that push’s alpha | the alpha’s signature: main |
Under the hood
<next>is what release-please will propose sinceVERSION, the last release: aRelease-As:footer wins; a breaking change bumps the major (the minor before 1.0.0),featthe minor, anything else the patch. Before the first release it is0.1.0; on the release commit,VERSION.Nis one more than the highest published alpha of<next>. A registry that cannot answer fails the job rather than risk overwriting.- A branch tag is a SemVer pre-release, collected by
cleanup-artifacts.yaml.
Releases
Section titled “Releases”release-please keeps one release PR open, advanced only to a commit whose
alpha passed the e2e proofs. Merging it is the release: promote gives that
commit’s alpha the version as a second tag, so the release is the exact bytes
and signature the proofs ran on. A release tag is never overwritten
(contributor side in CONTRIBUTING).
Under the hood
The PR carries the CHANGELOG.md entry and rewrites VERSION,
.release-please-manifest.json and every # x-release-please-version line
(release-please-config.json).
release.sh finds the alpha whose
org.opencontainers.image.revision is main@sha1:<commit> and tags it with
crane tag. It refuses a tag that is not the commit’s VERSION, a commit
with no alpha, and a version already on another digest; a re-run after a
partial failure finishes the release. All of it is one workflow because a
release made with the workflow’s token triggers no other workflow.
Signatures
Section titled “Signatures”Both packages are signed keyless with cosign; the subject is the workflow file on its ref:
https://github.com/do-now-io/socle/.github/workflows/publish-artifact.yaml@refs/heads/main- Flux verifies the artifact on every reconciliation against
cosign_identity, which trustsmainby default and cannot be turned off. Its issuer and subject are regexes: the plan refuses one not anchored at both ends, or only a wildcard, which would accept any signer. - OpenTofu does not. Run the command
in CI before
init; nothing forces it. - Renaming
publish-artifact.yamlbreaks every deployed verification.
Visibility
Section titled “Visibility”Both packages, flux-modules and opentofu-modules, are public: tofu init,
cosign verify and the cluster pull with no credential. A private mirror is
the one case that needs one
(Pull from a private registry).
Anonymous tofu init needs OpenTofu 1.13 or later, the floor every
versions.tf declares. Before 1.13, OpenTofu pings /v2/ before it asks for
the repository; ghcr answers with a challenge for a placeholder scope and
refuses an anonymous token for it, and the init fails with a 403 that reads
like an access problem
(opentofu/opentofu#3316,
fixed in 1.13.0, not backported to 1.12). With the floor, a 1.12 user gets
“Unsupported OpenTofu Core version” instead.