diff --git a/README.md b/README.md index c0a32d6..b4bbf1a 100644 --- a/README.md +++ b/README.md @@ -13,4 +13,4 @@ This repository defines the reusable workflows and repository contract that Meig - [OCI image contract reference](docs/reference/oci-image-contract.md) - [Copyable Go release example](examples/go-release/) -Consumer repositories call the reusable workflows at one full commit SHA. The current released pin is `5fb7584b465ab9c0ca4e1057c7b2ca694f950d59` (`v0.1.1`). +Consumer repositories call the reusable workflows at one full commit SHA. The current released pin is `611195c21fdd44ff2cf95c6a8833f84d095270b0` (`v0.1.2`). diff --git a/docs/how-to/configure-github-releases.md b/docs/how-to/configure-github-releases.md index f700147..9b96ea9 100644 --- a/docs/how-to/configure-github-releases.md +++ b/docs/how-to/configure-github-releases.md @@ -2,7 +2,7 @@ Use this guide to add the shared Meigma Go release workflows to a repository. The [GitHub Release contract](../reference/github-release-contract.md) defines the reusable workflow inputs, permissions, artifacts, and failure behavior. -The documented workflow revision is `5fb7584b465ab9c0ca4e1057c7b2ca694f950d59` (`v0.1.1`). +The documented workflow revision is `611195c21fdd44ff2cf95c6a8833f84d095270b0` (`v0.1.2`). ## Prerequisites @@ -94,28 +94,29 @@ Do not overwrite an existing repository's `go.mod` or command source. Adapt its In the copied files, replace the example values with values from the consumer repository: -- In `.goreleaser.yaml`, replace project name, build ID, archive ID, command path, and binary name `example` with the consumer's values. +- In `.goreleaser.yaml`, replace project name, build ID, archive ID, nFPM ID, command path, binary name, vendor, homepage, maintainer, description, and license with the consumer's values. - Keep the `main.version` and `main.commit` linker variable names only if the command's `main` package defines both variables and uses them for `--version`. Otherwise, change the ldflags to the consumer command's real linker variables. - If you copied the sample source, replace module path `example.com/meigma/release-consumer` and the literal command name and output in `cmd/example/main.go`. - In `release-please-config.json`, replace package name `example` and choose the intended first release in `initial-version`. - In `.release-please-manifest.json`, keep `0.0.0` only for a repository that has never released. For an existing project, set `.` to its latest released version without the `v` prefix. - In `.github/workflows/release-please.yml`, replace `main` if the consumer's default branch is different. -- In `melange.yaml` and `apko.yaml`, replace the package name, command path, description, license, source URL, and image annotations as described in [Configure OCI image publication](configure-oci-images.md). +- In `melange.yaml` and `apko.yaml`, replace package name, vendor, homepage, maintainer, command path, description, license, source URL, and image annotations as described in [Configure OCI image publication](configure-oci-images.md). Do not replace these shared contract values: -- reusable workflow revision `5fb7584b465ab9c0ca4e1057c7b2ca694f950d59`; -- `checksum-signing-workflow-ref` value `meigma/release/.github/workflows/go-pre-publish.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59`; +- reusable workflow revision `611195c21fdd44ff2cf95c6a8833f84d095270b0`; +- `checksum-signing-workflow-ref` value `meigma/release/.github/workflows/go-pre-publish.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0`; - variable name `MEIGMA_RELEASE_APP_CLIENT_ID`; or - secret name `MEIGMA_RELEASE_APP_PRIVATE_KEY`. To change the immutable revision later, follow [Upgrade GitHub Release workflows](upgrade-github-release-workflows.md). Update all reusable workflow references and the checksum signing identity together; do not edit one reference in isolation. -Keep `checksum-signing-workflow-ref` in `owner/repository/workflow@revision` form without a URL prefix. The publisher adds `https://github.com/` and passes the resulting exact certificate identity to `release-cli verify bundle` with `--identity`. For example, the documented input becomes `--identity https://github.com/meigma/release/.github/workflows/go-pre-publish.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59`. +Keep `checksum-signing-workflow-ref` in `owner/repository/workflow@revision` form without a URL prefix. The publisher adds `https://github.com/` and passes the resulting exact certificate identity to `release-cli verify bundle` with `--identity`. For example, the documented input becomes `--identity https://github.com/meigma/release/.github/workflows/go-pre-publish.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0`. The copied GoReleaser configuration builds Darwin, Linux, and Windows archives -for amd64 and arm64. Confirm that the consumer command supports those targets -before releasing it. Keep both `changelog.disable: true` and +for amd64 and arm64. It also packages each canonical Linux binary as DEB, RPM, +and APK without rebuilding it. Confirm that the consumer command supports those +targets before releasing it. Keep both `changelog.disable: true` and `release.disable: true`: Release Please owns the release notes and initial draft, and GoReleaser must not publish a release. @@ -211,7 +212,7 @@ gh release view "$TAG" \ --json tagName,isDraft,isPrerelease,publishedAt,url ``` -The final result must report the expected tag, `"isDraft": false`, and `"isPrerelease": false`. The release contains six platform archives, six archive SBOMs, `checksums.txt`, and `checksums.txt.sigstore.json`. +The final result must report the expected tag, `"isDraft": false`, and `"isPrerelease": false`. The release contains six platform archives, six native Linux packages, twelve SBOMs, `checksums.txt`, and `checksums.txt.sigstore.json`. To stop before publication and inspect the populated draft, follow [Rehearse and recover GitHub Releases](rehearse-and-recover-github-releases.md). @@ -241,14 +242,14 @@ On Linux, use: sha256sum --check checksums.txt ``` -Every listed archive and SBOM must report `OK`. +Every listed archive, native package, and SBOM must report `OK`. Verify that the checksum manifest was signed by the canonical reusable pre-publish workflow revision: ```bash mise exec -- cosign verify-blob \ --bundle checksums.txt.sigstore.json \ - --certificate-identity 'https://github.com/meigma/release/.github/workflows/go-pre-publish.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59' \ + --certificate-identity 'https://github.com/meigma/release/.github/workflows/go-pre-publish.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0' \ --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \ checksums.txt ``` @@ -264,10 +265,39 @@ while IFS= read -r entry; do mise exec -- gh attestation verify "$asset" \ --repo "$REPOSITORY" \ --signer-workflow meigma/release/.github/workflows/publish-github-release.yml \ - --signer-digest 5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 \ + --signer-digest 611195c21fdd44ff2cf95c6a8833f84d095270b0 \ --source-ref "refs/tags/$TAG" \ --deny-self-hosted-runners done < checksums.txt ``` -Each invocation must exit successfully. The signer workflow names the reusable publisher rather than the consumer caller, and `--signer-digest` binds it to the canonical revision. GitHub attestations cover the twelve payloads in `checksums.txt`; the checksum manifest and Cosign bundle are control files and are not attestation subjects. +Each invocation must exit successfully. The signer workflow names the reusable publisher rather than the consumer caller, and `--signer-digest` binds it to the canonical revision. GitHub attestations cover the 24 payloads in `checksums.txt`; the checksum manifest and Cosign bundle are control files and are not attestation subjects. + +## 8. Install a native Linux package + +Choose the package for the host architecture from the downloaded release +directory. Package filenames follow +`__linux_.`. + +Install the DEB on Debian or Ubuntu: + +```bash +sudo dpkg -i "__linux_.deb" +``` + +Install the RPM on Fedora or another RPM-based distribution: + +```bash +sudo rpm -i "__linux_.rpm" +``` + +Install the APK on Alpine: + +```bash +sudo apk add --allow-untrusted "__linux_.apk" +``` + +Run the installed command's version or health check after installation. These +standalone packages are not signed with a native package-manager key and are +not distributed through a package repository. Verify `checksums.txt`, its +Cosign signature, and the package's GitHub attestation before installation. diff --git a/docs/how-to/configure-oci-images.md b/docs/how-to/configure-oci-images.md index 3f1bf35..b2896bf 100644 --- a/docs/how-to/configure-oci-images.md +++ b/docs/how-to/configure-oci-images.md @@ -2,7 +2,7 @@ Use this guide to add signed, multi-architecture GHCR images to a repository that already uses the Meigma Go release workflows. The [OCI image contract](../reference/oci-image-contract.md) defines the reusable workflow interfaces, image contents, tags, signatures, attestations, and recovery behavior. -The documented workflow revision is `5fb7584b465ab9c0ca4e1057c7b2ca694f950d59` (`v0.1.1`). +The documented workflow revision is `611195c21fdd44ff2cf95c6a8833f84d095270b0` (`v0.1.2`). ## Prerequisites @@ -20,7 +20,7 @@ Record the consumer repository and immutable workflow revision: ```bash export REPOSITORY="$(gh repo view --json nameWithOwner --jq .nameWithOwner)" -export RELEASE_REVISION=5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 +export RELEASE_REVISION=611195c21fdd44ff2cf95c6a8833f84d095270b0 export IMAGE="ghcr.io/${REPOSITORY,,}" ``` @@ -112,7 +112,7 @@ permissions: Pin every reusable workflow to the same full revision: ```text -5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 +611195c21fdd44ff2cf95c6a8833f84d095270b0 ``` Make `github-release` depend on `oci-publish`. That ordering keeps the GitHub Release in draft state when registry publication, signing, or attestation fails. diff --git a/docs/how-to/rehearse-and-recover-github-releases.md b/docs/how-to/rehearse-and-recover-github-releases.md index d5951c2..426c6db 100644 --- a/docs/how-to/rehearse-and-recover-github-releases.md +++ b/docs/how-to/rehearse-and-recover-github-releases.md @@ -2,7 +2,7 @@ Use this guide to populate a draft GitHub Release without publishing it, then resume publication through the same tag and draft. Complete [Configure GitHub Releases](configure-github-releases.md) first. The [GitHub Release contract](../reference/github-release-contract.md) defines the checks that each run enforces. -The documented workflow revision is `5fb7584b465ab9c0ca4e1057c7b2ca694f950d59` (`v0.1.1`). +The documented workflow revision is `611195c21fdd44ff2cf95c6a8833f84d095270b0` (`v0.1.2`). `release-cli publish github` owns draft discovery, tag and commit binding, expected-asset upload, asset convergence, and the optional undraft operation. It never creates a release, re-drafts a public release, or deletes an asset. @@ -106,7 +106,7 @@ gh run watch "$RELEASE_RUN_ID" \ --exit-status ``` -At the documented current revision, a successful draft-only run leaves the Release workflow green, the release unpublished with six platform archives, six archive SBOMs, `checksums.txt`, and `checksums.txt.sigstore.json`, and GHCR unchanged. With `publish-release: false`, the workflow runs `release-cli publish github --no-undraft`; the CLI converges and verifies the expected asset set, then confirms that the release remains a draft. The run also retains the verified multi-architecture layout, signed APK repository, apko lock, and image SBOMs in the `oci-image` workflow artifact. When rehearsing another revision, use the target contracts in [Upgrade GitHub Release workflows](upgrade-github-release-workflows.md). +At the documented current revision, a successful draft-only run leaves the Release workflow green, the release unpublished with six platform archives, six native Linux packages, twelve SBOMs, `checksums.txt`, and `checksums.txt.sigstore.json`, and GHCR unchanged. With `publish-release: false`, the workflow runs `release-cli publish github --no-undraft`; the CLI converges and verifies the expected asset set, then confirms that the release remains a draft. The run also retains the verified multi-architecture layout, signed APK repository, apko lock, and image SBOMs in the `oci-image` workflow artifact. When rehearsing another revision, use the target contracts in [Upgrade GitHub Release workflows](upgrade-github-release-workflows.md). ## 3. Inspect the populated draft @@ -123,7 +123,7 @@ gh api "repos/$REPOSITORY/releases/$RELEASE_ID" \ --jq '{id, tag_name, draft, prerelease, assets: [.assets[] | {name, state, digest}]}' ``` -For the documented current revision, the query must select exactly one release with the exact tag, `"draft": true`, `"prerelease": false`, and fourteen assets. Twelve asset names come from `checksums.txt`; the other two are the checksum manifest and its Cosign bundle. For an upgrade rehearsal, require the names and count defined by the target contract instead. +For the documented current revision, the query must select exactly one release with the exact tag, `"draft": true`, `"prerelease": false`, and 26 assets. Twenty-four asset names come from `checksums.txt`; the other two are the checksum manifest and its Cosign bundle. For an upgrade rehearsal, require the names and count defined by the target contract instead. If this rehearsal query reports `"draft": false`, stop. A `publish-release: false` run requires the release to remain a draft, so `publish github --no-undraft` classifies an already-public release as indeterminate even when all assets match. Inspect how the release became public; do not rerun the rehearsal or ask the CLI to re-draft it. @@ -320,7 +320,7 @@ If the repository does not need a correction, rerun the complete top-level workf For the documented current revision, the publisher requires a nonempty `checksums.txt`, the exact closed payload list, matching payload hashes, a regular Cosign bundle file, issuer `https://token.actions.githubusercontent.com`, and this certificate identity: ```text -https://github.com/meigma/release/.github/workflows/go-pre-publish.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 +https://github.com/meigma/release/.github/workflows/go-pre-publish.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0 ``` For an upgrade rehearsal, replace the current-revision identity with the target value described in [Upgrade GitHub Release workflows](upgrade-github-release-workflows.md). diff --git a/docs/how-to/upgrade-github-release-workflows.md b/docs/how-to/upgrade-github-release-workflows.md index 9a23e89..2f0cb38 100644 --- a/docs/how-to/upgrade-github-release-workflows.md +++ b/docs/how-to/upgrade-github-release-workflows.md @@ -178,7 +178,7 @@ Review the final diff and confirm that it contains no moving reusable workflow r After the upgrade reaches the default branch, perform the draft-only procedure in [Rehearse and recover GitHub Releases](rehearse-and-recover-github-releases.md). Do not enable either publisher until the target revision has populated and verified a draft and produced the expected OCI artifact. -Use the linked guide for its release creation, exact run selection, draft lookup, resumption, and recovery mechanics. During an upgrade rehearsal, the target contract overrides every baseline constant in that guide. In particular, require the target asset names and count, the checksum certificate identity ending in `@$NEW_RELEASE_REVISION`, and the publisher `--signer-digest "$NEW_RELEASE_REVISION"`. Do not reject a target-compliant draft because it differs from the baseline fourteen-asset set or baseline revision. +Use the linked guide for its release creation, exact run selection, draft lookup, resumption, and recovery mechanics. During an upgrade rehearsal, the target contract overrides every baseline constant in that guide. In particular, require the target asset names and count, the checksum certificate identity ending in `@$NEW_RELEASE_REVISION`, and the publisher `--signer-digest "$NEW_RELEASE_REVISION"`. Do not reject a target-compliant draft because it differs from the baseline 26-asset set or baseline revision. The rehearsal must produce these observable results: diff --git a/docs/reference/github-release-contract.md b/docs/reference/github-release-contract.md index 672b831..29ac121 100644 --- a/docs/reference/github-release-contract.md +++ b/docs/reference/github-release-contract.md @@ -1,6 +1,6 @@ # GitHub release contract reference -This page defines the cross-repository contract for the reusable Go producer and GitHub Release publisher at revision `5fb7584b465ab9c0ca4e1057c7b2ca694f950d59` (`v0.1.1`). +This page defines the cross-repository contract for the reusable Go producer and GitHub Release publisher at revision `611195c21fdd44ff2cf95c6a8833f84d095270b0` (`v0.1.2`). For configuration steps, see [Configure GitHub releases](../how-to/configure-github-releases.md). For draft rehearsals and recovery steps, see [Rehearse and recover GitHub releases](../how-to/rehearse-and-recover-github-releases.md). The [`release-cli` contract](release-cli-contract.md) defines the command, output, and exit-code surface used by the producer. The [OCI image contract](oci-image-contract.md) defines the image builder and publisher that gate the complete delivery caller. [Release trust boundaries](../explanation/release-trust-boundaries.md) explains why the workflows, setup action, and CLI have separate responsibilities. To adopt another immutable revision, see [Upgrade GitHub release workflows](../how-to/upgrade-github-release-workflows.md). A complete consumer repository is available in the [Go release example](../../examples/go-release/). @@ -9,17 +9,17 @@ For configuration steps, see [Configure GitHub releases](../how-to/configure-git The complete caller pins all four reusable workflows to one full revision. The GitHub Release path directly calls the producer and GitHub publisher: ```yaml -uses: meigma/release/.github/workflows/go-pre-publish.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 +uses: meigma/release/.github/workflows/go-pre-publish.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0 ``` ```yaml -uses: meigma/release/.github/workflows/publish-github-release.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 +uses: meigma/release/.github/workflows/publish-github-release.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0 ``` The checksum signer identity input must name the same producer workflow revision: ```yaml -checksum-signing-workflow-ref: meigma/release/.github/workflows/go-pre-publish.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 +checksum-signing-workflow-ref: meigma/release/.github/workflows/go-pre-publish.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0 ``` ## Caller contract @@ -48,7 +48,7 @@ jobs: attestations: read contents: read id-token: write - uses: meigma/release/.github/workflows/go-pre-publish.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 + uses: meigma/release/.github/workflows/go-pre-publish.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0 oci-image: name: Build OCI image @@ -57,7 +57,7 @@ jobs: actions: read attestations: read contents: read - uses: meigma/release/.github/workflows/go-oci-build.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 + uses: meigma/release/.github/workflows/go-oci-build.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0 with: artifact-id: ${{ needs.release-assets.outputs.oci-input-artifact-id }} artifact-digest: ${{ needs.release-assets.outputs.oci-input-artifact-digest }} @@ -72,7 +72,7 @@ jobs: contents: read id-token: write packages: write - uses: meigma/release/.github/workflows/publish-oci-image.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 + uses: meigma/release/.github/workflows/publish-oci-image.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0 with: artifact-id: ${{ needs.oci-image.outputs.artifact-id }} artifact-digest: ${{ needs.oci-image.outputs.artifact-digest }} @@ -91,11 +91,11 @@ jobs: attestations: write contents: read id-token: write - uses: meigma/release/.github/workflows/publish-github-release.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 + uses: meigma/release/.github/workflows/publish-github-release.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0 with: artifact-id: ${{ needs.release-assets.outputs.artifact-id }} artifact-digest: ${{ needs.release-assets.outputs.artifact-digest }} - checksum-signing-workflow-ref: meigma/release/.github/workflows/go-pre-publish.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 + checksum-signing-workflow-ref: meigma/release/.github/workflows/go-pre-publish.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0 require-oci-image: true oci-image-reference: ${{ needs.oci-publish.outputs.image-reference }} release-app-client-id: ${{ vars.MEIGMA_RELEASE_APP_CLIENT_ID }} @@ -273,12 +273,12 @@ A compatible `.goreleaser.yaml` uses schema version 2 and writes the release bun - Build Darwin, Linux, and Windows binaries for `amd64` and `arm64` with `CGO_ENABLED=0`. - Package Darwin and Linux binaries as `tar.gz`; package Windows binaries as `zip`. -- Name archives `___` before the format extension. +- Package each canonical Linux binary as DEB, RPM, and APK through one GoReleaser nFPM definition. The package step reuses the build output and installs the binary in `/usr/bin`. - Build with `-trimpath` and linker flags `-s -w -buildid=`. - Populate `main.version` from `{{ .Version }}` and `main.commit` from `{{ .FullCommit }}`. - Set `mod_timestamp` to `{{ .CommitTimestamp }}`. - Use GoReleaser's module-proxy mode and the local Go toolchain. The current profile sets `GOPROXY=https://proxy.golang.org,direct` and `GOSUMDB=sum.golang.org` for module resolution. -- Emit one archive SBOM per archive through GoReleaser's `artifacts: archive` SBOM configuration. +- Emit one SBOM per archive and one per native package through GoReleaser's `artifacts: archive` and `artifacts: package` SBOM configurations. - Write the SHA-256 manifest as `checksums.txt`. - Sign `checksums.txt` with `cosign sign-blob --bundle=${signature} ${artifact} --yes` and name the bundle `checksums.txt.sigstore.json`. - Disable GoReleaser changelog generation and the GoReleaser release pipe. Release Please owns release notes and the draft; the reusable publisher owns asset upload and publication. @@ -299,12 +299,15 @@ The producer uploads one Actions artifact named `release-assets`. Its upload set ```text dist/*.tar.gz dist/*.zip +dist/*.deb +dist/*.rpm +dist/*.apk dist/*.sbom.json dist/checksums.txt dist/checksums.txt.sigstore.json ``` -For the supported three-operating-system, two-architecture Go profile, this is six archives, six archive SBOMs, `checksums.txt`, and `checksums.txt.sigstore.json`: fourteen files in total. +For the supported three-operating-system, two-architecture Go profile, this is six archives, six native Linux packages, twelve SBOMs, `checksums.txt`, and `checksums.txt.sigstore.json`: 26 files in total. Before upload, the producer obtains `release-cli` through the shared setup action and runs `release-cli stage --profile go --dist dist`. The command first builds the release bundle through GoReleaser. It then verifies every payload listed in `checksums.txt`, requires a nonempty regular `checksums.txt.sigstore.json`, verifies the two canonical Linux binaries described in the [`release-cli` contract](release-cli-contract.md), and writes the OCI input projection. @@ -341,14 +344,14 @@ The checksum signature is accepted only when `release-cli verify bundle` invokes | Field | Required value | | --- | --- | -| Certificate identity | `https://github.com/meigma/release/.github/workflows/go-pre-publish.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59` | +| Certificate identity | `https://github.com/meigma/release/.github/workflows/go-pre-publish.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0` | | Certificate OIDC issuer | `https://token.actions.githubusercontent.com` | | Signed blob | `checksums.txt` | | Bundle | `checksums.txt.sigstore.json` | The workflow adds the `https://github.com/` prefix to `checksum-signing-workflow-ref` and passes the resulting exact URL to `release-cli verify bundle` with `--identity`. A branch name, tag name, different commit, or different workflow path does not satisfy the documented identity. -The publisher at `meigma/release/.github/workflows/publish-github-release.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59` creates GitHub build-provenance attestations in the consumer repository. Its job token creates attestations but has only `contents: read`. The workflow mints a short-lived Release App installation token with `contents: write` and passes it to `release-cli publish github`. The CLI stores the value as a redacted secret and uses it for release discovery and publication; it never mints an App token. +The publisher at `meigma/release/.github/workflows/publish-github-release.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0` creates GitHub build-provenance attestations in the consumer repository. Its job token creates attestations but has only `contents: read`. The workflow mints a short-lived Release App installation token with `contents: write` and passes it to `release-cli publish github`. The CLI stores the value as a redacted secret and uses it for release discovery and publication; it never mints an App token, changes repository settings, or persists credentials. ## Publication states @@ -387,7 +390,7 @@ This contract does not provide or imply: - OCI construction or publication behavior beyond the dependency ordering defined here; see the separate [OCI image contract](oci-image-contract.md). - Homebrew, MacPorts, Nix, Scoop, mise registry, or other package-manager publication. -- DEB, RPM, APK, package-repository, or installer publication. +- Native package repository publication or native package-manager signing. DEB, RPM, and APK files are standalone GitHub Release assets protected by the release checksum, Cosign, and attestation contract. - Release support for languages other than the documented Go producer profile. - Consumer CI policy or tests in the OIDC-enabled release job. - Release-note generation in GoReleaser. diff --git a/docs/reference/oci-image-contract.md b/docs/reference/oci-image-contract.md index dc45acc..cade22e 100644 --- a/docs/reference/oci-image-contract.md +++ b/docs/reference/oci-image-contract.md @@ -1,6 +1,6 @@ # OCI image contract -This page defines the cross-repository contract for the reusable Go OCI builder and GHCR publisher at revision `5fb7584b465ab9c0ca4e1057c7b2ca694f950d59` (`v0.1.1`). +This page defines the cross-repository contract for the reusable Go OCI builder and GHCR publisher at revision `611195c21fdd44ff2cf95c6a8833f84d095270b0` (`v0.1.2`). For adoption steps, see [Configure OCI image publication](../how-to/configure-oci-images.md). The [GitHub Release contract](github-release-contract.md) defines the upstream Go release producer and GitHub Release publisher. A complete consumer is available in the [Go release example](../../examples/go-release/). @@ -27,11 +27,11 @@ The image builder consumes the canonical binaries built and selected by `release Consumers call both workflows at the same immutable revision: ```yaml -uses: meigma/release/.github/workflows/go-oci-build.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 +uses: meigma/release/.github/workflows/go-oci-build.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0 ``` ```yaml -uses: meigma/release/.github/workflows/publish-oci-image.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 +uses: meigma/release/.github/workflows/publish-oci-image.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0 ``` Moving branches and tags are not supported workflow references. @@ -248,7 +248,7 @@ The publisher signs the index and both platform manifests with Cosign keyless si | Field | Value | | --- | --- | -| Certificate identity | `https://github.com/meigma/release/.github/workflows/publish-oci-image.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59` | +| Certificate identity | `https://github.com/meigma/release/.github/workflows/publish-oci-image.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0` | | Certificate OIDC issuer | `https://token.actions.githubusercontent.com` | | Subject | Digest-pinned image or platform manifest. | diff --git a/docs/reference/release-cli-contract.md b/docs/reference/release-cli-contract.md index 2c5208b..569bbed 100644 --- a/docs/reference/release-cli-contract.md +++ b/docs/reference/release-cli-contract.md @@ -795,7 +795,7 @@ The projection records staged facts only. The image builder recomputes each dige ## Release unit and consumer pin -The reusable workflows, `.github/actions/setup-release-cli`, and `release-cli` form one release unit and share one version. The producer loads the sibling action with `uses: $/.github/actions/setup-release-cli`. A consumer pins the workflow at one full commit SHA, and that self-reference selects the action from the same commit and its stamped default CLI version. The current released pin is `5fb7584b465ab9c0ca4e1057c7b2ca694f950d59` (`v0.1.1`). Consumers cannot select an independent CLI version. +The reusable workflows, `.github/actions/setup-release-cli`, and `release-cli` form one release unit and share one version. The producer loads the sibling action with `uses: ./.github/actions/setup-release-cli`. A consumer pins the workflow at one full commit SHA, and that self-reference selects the action from the same commit and its stamped default CLI version. The current released pin is `611195c21fdd44ff2cf95c6a8833f84d095270b0` (`v0.1.2`). Consumers cannot select an independent CLI version. The setup action has two optional inputs: diff --git a/docs/tutorials/release-a-go-project.md b/docs/tutorials/release-a-go-project.md index 60d8901..45ae073 100644 --- a/docs/tutorials/release-a-go-project.md +++ b/docs/tutorials/release-a-go-project.md @@ -101,7 +101,7 @@ done You see one `copied` line for each of the eleven paths. -## Adapt the Go command and archives +## Adapt the Go command and packages Install the locked tools, then set the module path to the GitHub repository: @@ -124,7 +124,7 @@ Edit `cmd/hello-release/main.go`. Replace the two user-facing occurrences of `example` with `hello-release`. Keep the `version` and `commit` variables: the copied GoReleaser configuration sets both at link time. -Edit `.goreleaser.yaml` so its project, build, archive, and binary values read: +Edit `.goreleaser.yaml` so its project, build, archive, nFPM, and binary values read: ```yaml project_name: hello-release @@ -138,11 +138,21 @@ archives: - id: hello-release ids: - hello-release -``` + +nfpms: + - id: hello-release + ids: + - hello-release + vendor: Meigma + homepage: https://github.com/OWNER/hello-release + maintainer: Meigma + description: Hello release tutorial command. + license: LicenseRef-Proprietary These lines replace the corresponding `example` values; keep the remaining -build, archive, checksum, SBOM, signing, changelog, and release settings from the -example. In particular, keep: +build, archive, nFPM, checksum, SBOM, signing, changelog, and release settings +from the example. Replace `OWNER` with the owner shown in `$REPOSITORY`. In +particular, keep: ```yaml changelog: @@ -173,7 +183,7 @@ The command prints: hello-release dev (none) ``` -## Adapt the image +## Adapt the packages and image Edit `melange.yaml` for the same command: @@ -181,6 +191,9 @@ Edit `melange.yaml` for the same command: package: name: hello-release description: Hello release tutorial command. + vendor: Meigma + homepage: https://github.com/OWNER/hello-release + maintainer: Meigma copyright: - license: LicenseRef-Proprietary @@ -211,7 +224,7 @@ annotations: org.opencontainers.image.licenses: LicenseRef-Proprietary ``` -Replace `OWNER` with the owner shown in `$REPOSITORY`. Keep the nonroot account, +Keep the `OWNER` replacement consistent with the nFPM and Melange package metadata. Keep the nonroot account, architectures, certificate settings, and environment from the example. Validate the completed release configuration: @@ -297,7 +310,7 @@ run-selection, and draft-query commands. Keep the `REPOSITORY`, `TAG`, At the end of the rehearsal: - the Release workflow is green; -- the GitHub Release for `$TAG` is still a draft with fourteen assets; +- the GitHub Release for `$TAG` is still a draft with 26 assets; - the `release-assets`, `oci-build-inputs`, and `oci-image` workflow artifacts exist; and - no image tag has been written to GHCR. @@ -333,8 +346,9 @@ gh run download "$RELEASE_RUN_ID" \ Check the release bundle: ```bash -test "$(find "$INSPECT_DIR/release-assets" -maxdepth 1 -type f -name '*.sbom.json' | wc -l)" -eq 6 +test "$(find "$INSPECT_DIR/release-assets" -maxdepth 1 -type f -name '*.sbom.json' | wc -l)" -eq 12 test "$(find "$INSPECT_DIR/release-assets" -maxdepth 1 -type f \( -name '*.tar.gz' -o -name '*.zip' \) | wc -l)" -eq 6 +test "$(find "$INSPECT_DIR/release-assets" -maxdepth 1 -type f \( -name '*.deb' -o -name '*.rpm' -o -name '*.apk' \) | wc -l)" -eq 6 test -s "$INSPECT_DIR/release-assets/checksums.txt" test -s "$INSPECT_DIR/release-assets/checksums.txt.sigstore.json" printf 'release bundle complete\n' diff --git a/examples/go-release/.github/workflows/release.yml b/examples/go-release/.github/workflows/release.yml index cb3ffff..33d651c 100644 --- a/examples/go-release/.github/workflows/release.yml +++ b/examples/go-release/.github/workflows/release.yml @@ -22,7 +22,7 @@ jobs: attestations: read contents: read id-token: write - uses: meigma/release/.github/workflows/go-pre-publish.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 + uses: meigma/release/.github/workflows/go-pre-publish.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0 oci-image: name: Build OCI image @@ -33,7 +33,7 @@ jobs: # attestation while installing it; a callee cannot exceed this ceiling. attestations: read contents: read - uses: meigma/release/.github/workflows/go-oci-build.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 + uses: meigma/release/.github/workflows/go-oci-build.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0 with: artifact-id: ${{ needs.release-assets.outputs.oci-input-artifact-id }} artifact-digest: ${{ needs.release-assets.outputs.oci-input-artifact-digest }} @@ -47,7 +47,7 @@ jobs: contents: read id-token: write packages: write - uses: meigma/release/.github/workflows/publish-oci-image.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 + uses: meigma/release/.github/workflows/publish-oci-image.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0 with: artifact-id: ${{ needs.oci-image.outputs.artifact-id }} artifact-digest: ${{ needs.oci-image.outputs.artifact-digest }} @@ -67,11 +67,11 @@ jobs: attestations: write contents: read id-token: write - uses: meigma/release/.github/workflows/publish-github-release.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 + uses: meigma/release/.github/workflows/publish-github-release.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0 with: artifact-id: ${{ needs.release-assets.outputs.artifact-id }} artifact-digest: ${{ needs.release-assets.outputs.artifact-digest }} - checksum-signing-workflow-ref: meigma/release/.github/workflows/go-pre-publish.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59 + checksum-signing-workflow-ref: meigma/release/.github/workflows/go-pre-publish.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0 require-oci-image: true oci-image-reference: ${{ needs.oci-publish.outputs.image-reference }} release-app-client-id: ${{ vars.MEIGMA_RELEASE_APP_CLIENT_ID }} diff --git a/examples/go-release/.goreleaser.yaml b/examples/go-release/.goreleaser.yaml index 73e5f2a..8390dc0 100644 --- a/examples/go-release/.goreleaser.yaml +++ b/examples/go-release/.goreleaser.yaml @@ -44,12 +44,29 @@ archives: name_template: >- {{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }} +nfpms: + - id: example + ids: + - example + vendor: Meigma + homepage: https://github.com/meigma/release + maintainer: Meigma + description: Example Go command using the Meigma release workflows. + license: LicenseRef-Proprietary + formats: + - deb + - rpm + - apk + bindir: /usr/bin + checksum: name_template: checksums.txt sboms: - id: archives artifacts: archive + - id: packages + artifacts: package signs: - id: checksums diff --git a/examples/go-release/README.md b/examples/go-release/README.md index 2c38f66..951e2a5 100644 --- a/examples/go-release/README.md +++ b/examples/go-release/README.md @@ -35,6 +35,11 @@ release-cli stage --profile go --dist dist The stage command runs `goreleaser release --clean --skip=publish` under mise's environment, then validates the release bundle and writes the OCI input projection. GoReleaser shells out to the mise-managed Go, Syft, and Cosign executables during the build. +The GoReleaser configuration packages each Linux build as DEB, RPM, and APK +and emits one SBOM for every archive and native package. These standalone +packages are GitHub Release assets; the example does not configure a package +repository or native package-manager signing. + GoReleaser has no command-line distribution-directory option in this invocation. The consumer's `.goreleaser.yaml` must write the same distribution directory that the workflow passes to `release-cli stage --dist`. This example uses GoReleaser's default `dist` directory and passes `--dist dist`. The `--clean` option deletes and rebuilds `dist`. Keep `release.disable: true` in `.goreleaser.yaml`; `--skip=publish` is a second boundary against GoReleaser publication. Keep `changelog.disable: true` because Release Please owns release notes. @@ -45,8 +50,8 @@ Replace these project-specific example values: - `example.com/meigma/release-consumer` in `go.mod` with the consumer's module path. - `./cmd/example` in `.goreleaser.yaml` with the consumer command package. -- Project name, build ID, archive ID, binary name, and Release Please package name `example` with the consumer's project and binary names. -- Package name, description, license, and installed command path in `melange.yaml`. +- Project name, build ID, archive ID, nFPM ID, binary name, and Release Please package name `example` with the consumer's project and binary names. +- Package name, vendor, homepage, maintainer, description, license, and installed command path in `.goreleaser.yaml` and `melange.yaml`. - Package name, entrypoint, image annotations, and source URL in `apko.yaml`. - The literal command name and default output in `cmd/example/main.go` if you copy the sample command. - Branch name `main` in `.github/workflows/release-please.yml` if the consumer uses another default branch. @@ -56,13 +61,13 @@ Replace these project-specific example values: The example uses one full commit SHA for every reusable workflow reference and the checksum signing identity. That SHA is the consumer pin for the complete -release unit. The current pin is the `v0.1.1` release revision, -`5fb7584b465ab9c0ca4e1057c7b2ca694f950d59`. +release unit. The current pin is the `v0.1.2` release revision, +`611195c21fdd44ff2cf95c6a8833f84d095270b0`. Keep these contract values unchanged: -- all four reusable workflow references at `5fb7584b465ab9c0ca4e1057c7b2ca694f950d59`; -- `checksum-signing-workflow-ref` value `meigma/release/.github/workflows/go-pre-publish.yml@5fb7584b465ab9c0ca4e1057c7b2ca694f950d59`; +- all four reusable workflow references at `611195c21fdd44ff2cf95c6a8833f84d095270b0`; +- `checksum-signing-workflow-ref` value `meigma/release/.github/workflows/go-pre-publish.yml@611195c21fdd44ff2cf95c6a8833f84d095270b0`; - organization variable `MEIGMA_RELEASE_APP_CLIENT_ID`; - organization secret `MEIGMA_RELEASE_APP_PRIVATE_KEY`; and - the locked Go 1.26.6, GoReleaser 2.17.1, Syft 1.51.0, Cosign 3.1.3, GitHub CLI 2.97.0, Melange 0.59.1, and apko 1.2.37 versions unless the shared workflow contract is deliberately updated. diff --git a/examples/go-release/melange.yaml b/examples/go-release/melange.yaml index f30013a..b1ccce9 100644 --- a/examples/go-release/melange.yaml +++ b/examples/go-release/melange.yaml @@ -6,6 +6,9 @@ package: target-architecture: - x86_64 - aarch64 + vendor: Meigma + homepage: https://github.com/meigma/release + maintainer: Meigma copyright: - license: LicenseRef-Proprietary