Skip to content

[ADD] github: reusable build-image workflow with self-test - #1

Open
piruin wants to merge 1 commit into
mainfrom
ci/build-image-workflow
Open

piruin wants to merge 1 commit into
mainfrom
ci/build-image-workflow

Conversation

@piruin

@piruin piruin commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

What changed

  • .github/workflows/build-image.yml, a reusable workflow (workflow_call) for application images:
    • builds the image, then scans it with digest-pinned Trivy. Fixable CRITICAL vulnerabilities fail the build; HIGH findings go to the run summary; exceptions go in the caller's .trivyignore
    • pull requests: build and scan only, with no login, push, or signing
    • other events: push to ghcr.io/<image> (optional Docker Hub mirror) with SBOM and provenance attestations, sign the digest with keyless cosign, and output image = ghcr.io/<image>@sha256:… for deployment
    • all actions pinned by commit SHA, using releases at least two weeks old
  • .github/workflows/build-image-selftest.yml: actionlint, then builds a tiny pinned busybox image (.github/build-image-selftest/). On a pull request it asserts nothing was pushed. On a push it asserts the digest resolves in GHCR and passes cosign verify against this workflow's signing identity.
  • README: a third purpose of this repository (reusable workflows), with usage, inputs and outputs, vulnerability policy, the always-on signing note, and the verify command.

Why

nirun, nirun-3rd-party, and nirun-dop each keep their own Docker workflow, and the copies have drifted: two use unpinned action tags (@v3), nirun-3rd-party pushes images from pull requests, and none scans for vulnerabilities. One shared workflow fixes this once for every repository and outputs the digest that vmkit's deploy requires.

It lives here because public repositories (nirun) cannot call workflows from a private repository.

Part of nirun-life/vmkit#7.

Scope

New reusable workflow and self-test in nirun-life/.github. No application repository changes yet: nirun, nirun-3rd-party, and nirun-dop keep their current workflows until they switch in follow-up PRs. vmkit's reference caller follows in a separate PR, pinned to this PR's merge commit.

Risk / Impact

  • Public signing metadata: keyless signing is always on. For private callers it records the repository name, commit, branch, image digest, and run link in Sigstore's public transparency log (no code, images, or secrets). nirun-3rd-party and nirun-dop already sign this way today. This is recorded as an accepted risk (vmkit docs/risks.md R13).
  • New package: the self-test's first push creates the package ghcr.io/nirun-life/build-image-selftest.
  • Pin by commit: callers must pin build-image.yml@<commit-sha>. A change to this workflow reaches a repository only when that repository bumps its pin.

How tested

  • Unit/integration tests: the self-test workflow is the integration test. This PR's run is its first execution (pull request path and branch push path)
  • Manual check: actionlint 1.7.12 and yamllint 1.38.0 (strict) pass on both workflows
  • Not tested / explain why:

Documentation

  • Module README.md updated
  • Not needed (no Odoo module); the repository README documents the workflow

Notes for reviewer

  • For a reusable workflow, the cosign signing identity is the reusable workflow (nirun-life/.github/.github/workflows/build-image.yml@…), not the calling repository. The README's verify command and the self-test both use that identity.
  • Free-plan note: private repositories share 2,000 Actions minutes a month; public nirun builds are free.

Application repositories each kept their own Docker workflow, and the
copies drifted: unpinned action tags, images pushed from pull requests,
and no vulnerability scan. build-image.yml is one standard they call:

- builds the image, scans it with digest-pinned Trivy, and fails on
  fixable CRITICAL vulnerabilities (HIGH reported, .trivyignore for
  documented exceptions)
- pull requests build and scan only; other events push to GHCR (with an
  optional Docker Hub mirror) with SBOM and provenance attestations,
  sign the digest with keyless cosign, and output image@sha256 for
  deployment
- every action pinned by commit SHA

build-image-selftest.yml checks each change: a pull request must not
push, and a push must return a digest that resolves and verifies
against this workflow's signing identity. It lives in this public
repository so public repositories can call it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant