Skip to content

Repository files navigation

GitHub Actions Monorepo for OpenCHAMI

Reusable GitHub Actions for CI/CD.

Structure

  • actions/gpg-ephemeral-key: Deprecated - use actions/gpg-configure-release-keys instead
  • actions/gpg-configure-release-keys: Generates and certifies a per-run ephemeral GPG key through the repo's release key chain
  • actions/gpg-sign-rpm: RPM signing with ephemeral keys
  • actions/gpg-check-key-expiration: Fails CI if a signing key is expired or expiring soon
  • actions/gpg-verify-trust-chain: Verifies the master/repo-cert/ephemeral trust chain and optionally checksigs RPMs
  • .github/workflows/go-build-release.yml: Reusable workflow for GoReleaser builds
  • .github/workflows/docker-build-release.yml: Reusable workflow for multi-arch container image builds
  • .github/workflows/build-publish-container-goreleaser.yml: Builds and publishes a container image via GoReleaser
  • .github/workflows/build-rpm-quadlet.yml: Builds a caller repo's podman quadlet RPM
  • .github/workflows/gpg-sign-artifacts.yml: Signs unsigned RPM artifacts with a per-run ephemeral key
  • .github/workflows/validate-rpm-quadlet.yml: Validates a signed quadlet RPM's installed file list
  • .github/workflows/release-signed-artifacts.yml: Publishes a GitHub Release with signed RPMs and public keys
  • .github/workflows/publish-release.yml: Publishes the draft GitHub Release for a tag
  • .github/workflows/lint-workflows.yml: Reusable workflow that lints workflow files (actionlint + zizmor)
  • .github/workflows/lint-go.yml: Reusable workflow that runs golangci-lint and checks go.mod/go.sum are tidy
  • .github/workflows/test-go.yml: Reusable workflow that runs Go unit tests
  • .github/workflows/coverage-go.yml: Reusable workflow that reports Go coverage and uploads it to Coveralls
  • .github/workflows/reuse.yml: Reusable workflow that checks REUSE copyright/licensing compliance
  • .github/workflows/govulncheck.yml: Reusable workflow that scans Go modules for known CVEs
  • .github/workflows/dependency-review.yml: Reusable workflow that gates PRs introducing CVE-flagged deps
  • .github/workflows/trivy-image-scan.yml: Reusable workflow that scans built container images for CVEs
  • .github/workflows/scorecard.yml: Reusable workflow that runs the OpenSSF Scorecard supply-chain analysis
  • .github/workflows/pr-registry-cleanup.yml: Deletes the GHCR container images a PR published, once it closes

Versioning & Usage

Use major version tags for stability:

# For actions
- uses: OpenCHAMI/github-actions/actions/gpg-configure-release-keys@v3.8
- uses: OpenCHAMI/github-actions/actions/gpg-sign-rpm@v3.8

# For reusable workflows
jobs:
  release:
    uses: OpenCHAMI/github-actions/.github/workflows/go-build-release.yml@v3.8

Pin a commit SHA internally for maximum supply-chain safety if desired.

Workflows

go-build-release (Reusable Workflow)

Standardized GoReleaser workflow for building and releasing Go applications with:

  • Multi-architecture builds (linux/amd64, linux/arm64)
  • Flexible pre-build setup steps
  • Wraps goreleaser-action action with all .gorelease.yaml configurations
  • Container image builds and publishing
  • Binary and container attestation/signing
  • Snapshot builds on pull requests

Usage:

name: GoReleaser
run-name: GoReleaser ${{ startsWith(github.ref, 'refs/tags/v') && 'Release' || 'Snapshot' }}

on:
  workflow_dispatch:
  pull_request:
  push:
    tags:
      - v*

jobs:
  goreleaser:
    name: GoReleaser ${{ startsWith(github.ref, 'refs/tags/v') && 'Release' || 'Snapshot' }}
    uses: OpenCHAMI/github-actions/.github/workflows/go-build-release.yml@v3.8
    with:
      pre-build-commands: |
        go install github.com/swaggo/swag/cmd/swag@latest
      attestation-binary-path: "dist/cloud-init*"
      registry-name: ghcr.io/openchami/cloud-init

See the workflow for additional input parameters.

lint-workflows (Reusable Workflow)

Lints the caller repo's GitHub Actions workflow files.

  • actionlint - syntax validation, shellcheck on run: steps, deprecated-action checks.
  • zizmor - security-focused static analysis (script injection, excessive permissions, unpinned third-party actions). Uploads SARIF findings to the caller's GitHub Advanced Security tab.

Usage:

name: Lint Workflows
on:
  pull_request:
  push:
    branches: [main]

jobs:
  lint:
    uses: OpenCHAMI/github-actions/.github/workflows/lint-workflows.yml@v3.8

lint-go (Reusable Workflow)

Lints the caller's Go module. Runs golangci-lint, and separately verifies go.mod/go.sum are tidy by running the tidy command and failing on a dirty diff. Uses Go stable unless the caller sets go_version or go_version_file. golangci-lint tracks latest unless pinned.

Usage:

name: Lint
on:
  pull_request:
  push:
    branches: [main]

jobs:
  lint:
    uses: OpenCHAMI/github-actions/.github/workflows/lint-go.yml@v3.9
    # Optional overrides:
    # with:
    #   golangci-lint-version: v2.13.2
    #   go_version_file: go.mod
    #   tidy-command: make mod

test-go (Reusable Workflow)

Runs the caller's Go unit tests. Fetches tags so tests asserting on git describe version metadata behave as they do locally.

Usage:

name: Test
on:
  pull_request:
  push:
    branches: [main]

jobs:
  test:
    uses: OpenCHAMI/github-actions/.github/workflows/test-go.yml@v3.9
    # Optional overrides:
    # with:
    #   go_version_file: go.mod
    #   test-command: make test

coverage-go (Reusable Workflow)

Produces a Go coverage profile, writes the total to the job summary, and uploads the profile to Coveralls using the automatically-provided GITHUB_TOKEN. The caller repo must be enrolled in Coveralls.

Usage:

name: Coverage
on:
  pull_request:
  push:
    branches: [main]

jobs:
  coverage:
    uses: OpenCHAMI/github-actions/.github/workflows/coverage-go.yml@v3.9
    # Optional overrides:
    # with:
    #   go_version_file: go.mod
    #   coverage-command: make coverage

reuse (Reusable Workflow)

Runs the reuse tool over the caller repo via pipx to check REUSE compliance: every file carries a copyright notice and an SPDX license identifier, and every referenced license is present under LICENSES/. Pins reuse 6.2.0.

Usage:

name: REUSE
on:
  pull_request:
  push:
    branches: [main]

jobs:
  reuse:
    uses: OpenCHAMI/github-actions/.github/workflows/reuse.yml@v3.9

govulncheck (Reusable Workflow)

Runs the Go team's vulnerability scanner against the caller's module. Detects known CVEs in the import graph (direct and transitive). Reads the Go version from the caller's go.mod by default.

Usage:

name: govulncheck
on:
  pull_request:
  push:
    branches: [main]
  schedule:
    - cron: '0 6 * * 1'  # weekly catch-up for newly-disclosed CVEs

jobs:
  govulncheck:
    uses: OpenCHAMI/github-actions/.github/workflows/govulncheck.yml@v3.8

dependency-review (Reusable Workflow)

PR gate that compares the dependency changes between the PR head and base against GitHub's vulnerability database. Fails the check when the PR introduces a dependency at or above fail-on-severity (default: high). Optionally enforces license policy and posts a summary comment on the PR.

Usage:

name: Dependency Review
on:
  pull_request:

jobs:
  dependency-review:
    uses: OpenCHAMI/github-actions/.github/workflows/dependency-review.yml@v3.8
    # Optional overrides:
    # with:
    #   fail-on-severity: moderate
    #   deny-licenses: GPL-3.0,AGPL-3.0

trivy-image-scan (Reusable Workflow)

Scans an already-pushed container image with Trivy and uploads SARIF findings to GitHub Advanced Security. Designed to chain after docker-build-release with a digest-pinned image reference.

Usage:

jobs:
  build:
    uses: OpenCHAMI/github-actions/.github/workflows/docker-build-release.yml@v3.8
    with:
      registry-name: ghcr.io/openchami/foo

  scan:
    needs: build
    uses: OpenCHAMI/github-actions/.github/workflows/trivy-image-scan.yml@v3.8
    with:
      image-ref: ghcr.io/openchami/foo:${{ github.sha }}

scorecard (Reusable Workflow)

Runs the OpenSSF Scorecard supply-chain analysis and uploads SARIF findings to GitHub Advanced Security. Outside of pull_request runs it also publishes to the public OpenSSF dashboard, which is what backs the Scorecard badge. Trigger it on the default branch, on PRs, and on a schedule — running it on other branches scores an incomplete tree.

Usage:

name: Scorecard
on:
  branch_protection_rule:
  pull_request:
  push:
    branches: [main]
  schedule:
    - cron: '39 5 * * 1'

permissions:
  contents: read
  security-events: write
  id-token: write

jobs:
  scorecard:
    uses: OpenCHAMI/github-actions/.github/workflows/scorecard.yml@v3.9

build-publish-container-goreleaser (Reusable Workflow)

Builds and publishes a container image via GoReleaser, with multi-arch builds, build provenance attestation, and PR snapshot support. Release builds (is_pr_build: false) pass GitHub's auto-generated release notes for the pushed tag to GoReleaser via --release-notes.

Optional build_deps is a space-separated list of apt packages installed before the build, for cases such as CGO cross-compilation that need a toolchain not present on the runner.

Usage:

jobs:
  build:
    uses: OpenCHAMI/github-actions/.github/workflows/build-publish-container-goreleaser.yml@v3.8
    with:
      registry_subject_name: ghcr.io/openchami/foo
      release_draft: false
      cgo_enabled: 1
      build_deps: gcc-aarch64-linux-gnu libc6-dev-arm64-cross

build-rpm-quadlet (Reusable Workflow)

Builds the caller repo's podman quadlet RPM and uploads it as an unsigned artifact for downstream signing.

Usage:

jobs:
  build:
    uses: OpenCHAMI/github-actions/.github/workflows/build-rpm-quadlet.yml@v3.8

gpg-sign-artifacts (Reusable Workflow)

Signs unsigned RPM artifacts with a per-run ephemeral key certified through the repo's release key chain, verifies the chain, and uploads the signed RPMs and public keys. Intended as the common entry point for signing all release artifact types (RPMs today; other formats later).

Usage:

jobs:
  sign:
    uses: OpenCHAMI/github-actions/.github/workflows/gpg-sign-artifacts.yml@v3.8
    secrets: inherit

validate-rpm-quadlet (Reusable Workflow)

Validates a signed quadlet RPM's installed file list against the set of files the caller expects it to ship.

Usage:

jobs:
  validate:
    uses: OpenCHAMI/github-actions/.github/workflows/validate-rpm-quadlet.yml@v3.8
    with:
      rpms: |
        - name: foo-*.rpm
          files:
            - /etc/containers/systemd/foo.container

release-signed-artifacts (Reusable Workflow)

Publishes a GitHub Release for a tag, attaching signed RPMs and public keys, with trust-chain verification instructions in the release body.

Usage:

jobs:
  release:
    uses: OpenCHAMI/github-actions/.github/workflows/release-signed-artifacts.yml@v3.8
    with:
      release_draft: false

publish-release (Reusable Workflow)

Publishes the draft GitHub Release for a tag, for pipelines that set release_draft: true upstream so the release only appears once every artifact is attached.

Usage:

jobs:
  publish:
    needs: release
    uses: OpenCHAMI/github-actions/.github/workflows/publish-release.yml@v3.8

pr-registry-cleanup (Reusable Workflow)

Deletes the GHCR container image versions a pull request published, once that pull request closes. Matches the PR's base tag and any separated qualifier (pr-12, pr-12-amd64, pr-12-dirty-abc123).

Usage:

name: Cleanup
on:
  pull_request:
    types: [closed]

jobs:
  cleanup:
    uses: OpenCHAMI/github-actions/.github/workflows/pr-registry-cleanup.yml@v3.8
    permissions:
      packages: write

Actions

gpg-ephemeral-key (Deprecated - use gpg-configure-release-keys)

Generates a short-lived RSA key and signs it with a repo-scoped subkey. See the action README.

gpg-configure-release-keys

Generates a per-run ephemeral GPG key, certified through the repo's release key chain (master certifies a repo cert key, which certifies the ephemeral key). See the action README.

gpg-sign-rpm

Signs an RPM using a provided GPG fingerprint (works with the ephemeral key output from gpg-configure-release-keys) and exposes signature verification output. See the action README.

gpg-check-key-expiration

Fails CI if the provided signing key is expired or expiring within a threshold. See the action README.

gpg-verify-trust-chain

Verifies the master/repo-cert/ephemeral trust chain and optionally checksigs RPMs. See the action README.

Security Model

Trust chain: Ephemeral Key <- Repo Cert Key <- Offline Master Key.

Design principles:

  • Ephemeral keys reduce exposure window.
  • Repo cert keys are easily revocable & rotated.
  • Isolated GNUPGHOME avoids polluting runner defaults.
  • GNUPGHOME cleanup is the calling workflow's responsibility, not optional.

Key expiration limits future signing only; existing signatures remain valid if the trust chain remains intact.

Example Workflow (Combined)

Adapted from metadata-service's PR build workflow, chaining container build, RPM build, signing, and validation:

name: Build each PR for testing and validation
on:
    pull_request:
        branches:
            - main
        types: [opened, synchronize, reopened, edited]
    workflow_dispatch:
      inputs:
        pr_number:
          description: 'PR Number to build (optional, for manual PR builds)'
          required: false
          type: string

permissions: write-all # Necessary for the generate-build-provenance action with containers
jobs:

  config:
    runs-on: ubuntu-latest
    outputs:
      rpm-unsigned: ${{ steps.names.outputs.rpm-unsigned }}
      rpm-signed:   ${{ steps.names.outputs.rpm-signed }}
      keys-public:  ${{ steps.names.outputs.keys-public }}
    steps:
      - id: names
        run: |
          {
            echo "rpm-unsigned=rpms-unsigned"
            echo "rpm-signed=rpms-signed"
            echo "keys-public=public-keys"
          } >> "$GITHUB_OUTPUT"

  build:
    uses: OpenCHAMI/github-actions/.github/workflows/build-publish-container-goreleaser.yml@v3.8
    secrets: inherit
    with:
      cgo_enabled: 0
      registry_subject_name: ghcr.io/openchami/metadata-service
      is_pr_build: true
      pr_number: ${{ inputs.pr_number || github.event.pull_request.number || 0 }}

  rpmbuild:
    needs: [config, build]
    uses: OpenCHAMI/github-actions/.github/workflows/build-rpm-quadlet.yml@v3.8
    secrets: inherit
    with:
      artifact-name-unsigned-rpms: ${{ needs.config.outputs.rpm-unsigned }}

  rpmsign:
    needs: [config, rpmbuild]
    uses: OpenCHAMI/github-actions/.github/workflows/gpg-sign-artifacts.yml@v3.8
    secrets: inherit
    with:
      artifact-name-unsigned-rpms: ${{ needs.config.outputs.rpm-unsigned }}
      artifact-name-signed-rpms:   ${{ needs.config.outputs.rpm-signed }}
      artifact-name-public-keys:   ${{ needs.config.outputs.keys-public }}

  rpmvalidate:
    needs: [config, rpmsign]
    uses: OpenCHAMI/github-actions/.github/workflows/validate-rpm-quadlet.yml@v3.8
    secrets: inherit
    with:
      artifact-name-signed-rpms:   ${{ needs.config.outputs.rpm-signed }}
      rpms: |
        - name: metadata-service-*.rpm
          files:
            - /usr/share/containers/systemd/metadata-data.volume
            - /usr/share/containers/systemd/metadata-service.container
            - /usr/share/licenses/metadata-service
            - /usr/share/licenses/metadata-service/MIT.txt

Continuous Integration

  • Workflow files are linted via lint-workflows.yml (actionlint + zizmor).
  • RPM/quadlet output is validated via validate-rpm-quadlet.yml.
  • TODO: matrix test invoking each action directly.

Rotation & Revocation

Repo cert key and master key rotation/revocation procedures live in gpg-signing-manager. Tag a new release here if this repo's actions or workflows change as a result.

Contributing

  • Open issues for feature requests.
  • Submit PRs with accompanying test workflow updates.

License

MIT

About

Organization Level Github Actions

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors