Skip to content

Document crl_chain_file and client_ca for chart users #766

Document crl_chain_file and client_ca for chart users

Document crl_chain_file and client_ca for chart users #766

Workflow file for this run

name: CI
on:
push:
branches: ["main"]
# Deliberately unfiltered by base branch. A filter of ["main"] silently
# skipped every stacked PR — one targeting another unmerged branch rather
# than main — while container-images.yml, which has no filter, still showed
# a full row of green checks from image builds alone, so the checks tab read
# as a passing build. An allowlist only narrows that trap: the next base
# prefix nobody thought of fails the same silent way. Running on any base
# means a stacked PR is exercised before it merges into its base, rather than
# first being run by the downstream PR into main where the regression is
# already buried in the stack's history. Exercised, not gated: the "Main"
# ruleset covers the default branch only, so on a stacked PR these results
# are the author's to read rather than a merge block.
#
# push stays on main: a PR already gets a pull_request run, and widening
# push would double the load for no extra signal.
pull_request:
permissions:
contents: read
# Cancel in-flight runs for the same branch/PR so pushes don't queue up.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# -- Format / vet / tidy ------------------------------------------------------
check:
name: Format / vet / tidy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: true
- name: Install Mage
run: go install github.com/magefile/mage@v1.17.2
- name: Install golangci-lint
run: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.13.2
# Named for the target rather than its contents: the enumeration this
# step used to carry went stale twice as dev:check grew checks.
- name: Run the CI gate (mage dev:check)
run: mage dev:check
- name: Magefile tests
# The magefile is build-tagged, so its Ginkgo suite is invisible to
# the ordinary `go test ./...` run; test:magefile is the canonical
# invocation, shared with the pre-push hook.
run: mage test:magefile
# -- Dockerfile lint (hadolint) ----------------------------------------------
# Lints every Dockerfile in the repo. hadolint has no auto-fix mode (it only
# reports), so this job fails the build on violations and the developer fixes
# them -- the same fail-and-fix contract as `mage dev:check` above. One matrix
# leg per Dockerfile so annotations stay attributed to the right file.
hadolint:
name: Dockerfile lint (${{ matrix.dockerfile }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
dockerfile:
- Dockerfile
- Dockerfile.alpine
- test/Dockerfile.run
- docker/puppet/Dockerfile
- docker/puppet/Dockerfile.client
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Run hadolint
uses: hadolint/hadolint-action@06be81baf89a55ffd0e24b8f04a4185738dd3387 # v3.5.0
with:
dockerfile: ${{ matrix.dockerfile }}
# -- Markdown lint (markdownlint-cli2) ---------------------------------------
# Lints every Markdown document against .markdownlint-cli2.yaml. Like
# hadolint, markdownlint-cli2 fails the build on violations (though it can fix
# most of them locally with `markdownlint-cli2 --fix`). Node is preinstalled
# on GitHub-hosted runners, so npx runs the pinned version with no setup step.
markdownlint:
name: Markdown lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Run markdownlint-cli2
run: npx --yes markdownlint-cli2@0.23.1
# -- Monitoring mixin --------------------------------------------------------
# The mixin ships Prometheus alerting rules and no Go code, so nothing in the
# unit suite would catch a malformed selector substitution, or an expression
# that parses but silently never matches. Renders it with jsonnet, then runs
# promtool over the result: `check rules` for syntax, `test rules` for the
# behaviour of the rules whose expressions are not simple thresholds.
mixin:
name: Monitoring mixin
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: true
- name: Install jsonnet
run: go install github.com/google/go-jsonnet/cmd/jsonnet@v0.21.0
# From the release tarball rather than `go install`: the prometheus module
# carries replace directives, so installing its commands from source
# fails. Release assets are mutable, so the download is pinned by digest
# as well as by version — every other third-party artefact this workflow
# pulls in is content-pinned (actions by commit SHA, Go modules by the
# checksum database), and an unverified binary we then execute should not
# be the exception. PROMETHEUS_SHA256 is the published sha256sums.txt
# entry for the tarball below; bump both together.
- name: Install promtool
env:
PROMETHEUS_VERSION: 3.13.2
PROMETHEUS_SHA256: 0e8c4d46101bd025ea8265e377d2caabc57f488fc1be1c367f37db69ea41be6f
run: |
set -euo pipefail
tarball="prometheus-${PROMETHEUS_VERSION}.linux-amd64"
curl -fsSL -o promtool.tar.gz \
"https://github.com/prometheus/prometheus/releases/download/v${PROMETHEUS_VERSION}/${tarball}.tar.gz"
echo "${PROMETHEUS_SHA256} promtool.tar.gz" | sha256sum -c -
tar -xzf promtool.tar.gz "${tarball}/promtool"
install -m 0755 "${tarball}/promtool" "$(go env GOPATH)/bin/promtool"
rm -rf promtool.tar.gz "${tarball}"
- name: Install Mage
run: go install github.com/magefile/mage@v1.17.2
- name: Check the mixin
run: mage test:mixin
# -- Helm chart --------------------------------------------------------------
# Everything the chart is gated on, in one job: its version tracks
# internal/version, it lints under every fixture in charts/openvox-ca/ci/,
# every manifest it renders validates against the real Kubernetes and CRD
# schemas, the rendered values are asserted (schema validity is not
# correctness), and it packages. The publish workflow only packages and
# pushes, so this is where a broken chart is caught.
chart:
name: Helm chart (Helm ${{ matrix.helm }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Both supported Helm majors: the chart has to render identically for
# users still on 3 and for those who have moved to 4. Renovate keeps
# each leg current within its own major, one PR per major — the Helm 3
# PR carries this leg and helm-chart.yml's packaging pin together,
# because verifyChartPins refuses them separately. The two majors stay
# in separate PRs on purpose: fail-fast: false above says a Helm 4
# regression must not take the Helm 3 leg down with it, and a shared PR
# would do exactly that.
#
# Major bumps are off (see renovate.json): moving a leg across a major
# deletes the coverage that leg exists to provide, and adding or
# retiring a major is a decision about what the chart supports rather
# than a version bump. The cost is that nothing here will announce
# Helm 5 — that one is on whoever is watching upstream.
#
# Renovate only sees an entry that carries the annotation below;
# verifyChartPins fails the build on one that does not, because a leg
# it cannot see is a leg that silently goes stale.
helm:
# renovate: datasource=github-releases depName=helm packageName=helm/helm
- v3.21.4
# renovate: datasource=github-releases depName=helm packageName=helm/helm
- v4.2.4
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: true
- name: Install Mage
run: go install github.com/magefile/mage@v1.17.2
- name: Install kubeconform
run: go install github.com/yannh/kubeconform/cmd/kubeconform@v0.8.0
# helm is preinstalled on GitHub-hosted runners, but at whatever version
# the runner image happens to carry; pin it so the matrix means something.
- name: Set up Helm
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1
with:
version: ${{ matrix.helm }}
- name: Check the chart version tracks internal/version
run: mage chart:version
- name: Lint and validate the rendered manifests
run: mage chart:validate
# Schema validity is not correctness: these assert what the templates
# actually resolve to, and that each precondition really refuses what it
# claims to.
- name: Assert the chart renders the right values
run: mage chart:test
# Exercise the packaging step the publish workflow performs, so a chart
# that renders but cannot be packaged fails here rather than on a tag.
- name: Package the chart
run: mage chart:package
# -- Unit tests --------------------------------------------------------------─
unit:
name: Unit tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: true
- name: Install Mage
run: go install github.com/magefile/mage@v1.17.2
- name: Run unit tests
run: mage test:unit
# Host-side and sub-second, with no container runtime, so it rides in the
# cheapest job rather than inside the container jobs whose diagnostics it
# covers. It guards the failure-log dump both compose harnesses share, so
# pinning it to either the puppet or the backends job would have run it
# twice or covered one of them only.
#
# It does not gate those jobs, and that is deliberate rather than an
# oversight: this job and the compose jobs are siblings with no `needs:`
# edge, so a failure here appears beside them rather than stopping them.
# `needs:` would be right if a broken helper could change whether a
# compose suite passes -- the way test:migrationHelpers guards a retry
# bound its suite's assertions depend on -- but this one only decides
# what gets printed once something else has already failed. Gating would
# serialise the compose jobs behind this one on every green run to save
# compute on a rare red one.
- name: Run failure-log helper tests
run: mage test:failureLogHelpers
- name: Coverage summary
if: always()
continue-on-error: true
run: |
if [ ! -f coverage.out ]; then exit 0; fi
{
echo "## Test coverage"
echo '```'
go tool cover -func=coverage.out
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
# -- Release artefact build --------------------------------------------------
# Builds each dist tarball exactly as the Release workflow does — one
# variant per job, on a runner native to the target architecture (so the
# cgo/boringcrypto FIPS variants need no cross toolchain and every built
# binary can be executed for verification) — and discards the output.
# Without these legs, that build path would first run when a release tag is
# pushed, turning any breakage into a delete-tag/fix/retag cycle.
dist:
name: Release artefact build (${{ matrix.variant }})
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- variant: linux_amd64
runner: ubuntu-latest
- variant: linux_arm64
runner: ubuntu-24.04-arm
- variant: linux_amd64_fips
runner: ubuntu-latest
- variant: linux_arm64_fips
runner: ubuntu-24.04-arm
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
# setup-go's cache is keyed only on go.sum, and that key is claimed
# by whichever job saves it first — none of whose build caches
# match this variant's build configuration. Use a per-variant cache
# below instead, shared with release.yml.
cache: false
- name: Go caches (${{ matrix.variant }})
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
~/go/pkg/mod
~/.cache/go-build
# Unique key per commit so every run saves its updated cache;
# restore-keys fall back to the most recent cache for this variant.
# Caches saved on main are visible to all refs, but release tags no
# longer restore them: release.yml's build job sets cache: false and
# links from source, so nothing that can write a cache entry here
# reaches a published binary.
key: dist-gocache-${{ matrix.variant }}-${{ hashFiles('go.mod', 'go.sum') }}-${{ github.sha }}
restore-keys: |
dist-gocache-${{ matrix.variant }}-${{ hashFiles('go.mod', 'go.sum') }}-
dist-gocache-${{ matrix.variant }}-
- name: Install Mage
run: go install github.com/magefile/mage@v1.17.2
- name: Build release artifact
run: mage build:distVariant ${{ matrix.variant }}
- name: Verify artifact
# Shared with the Release workflow's build job, so the artefacts that
# actually get published receive the same verification as PR builds.
uses: ./.github/actions/verify-dist-artifact
with:
variant: ${{ matrix.variant }}
- name: Generate SBOMs
# Generated but not attested: signing needs id-token: write and a tag
# context, neither of which belongs on a PR. The point is that the
# scan-and-validate half of the release's SBOM step runs on every pull
# request, so a Syft upgrade or a cataloguer regression fails here
# rather than midway through a release, when the only remedy is
# delete-tag/fix/retag.
uses: ./.github/actions/generate-sbom
with:
variant: ${{ matrix.variant }}
# -- Puppet stack integration tests ------------------------------------------
# Runs the full OpenVox 8 stack: Go CA (TLS) → OpenVox Server (WEBrick) →
# OpenVoxDB. Requires docker compose and network access to pull base images
# on first run. Same standard/FIPS matrix as the compose job.
puppet:
name: Puppet stack tests (${{ matrix.build }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- build: standard
mage_target: test:puppet
- build: fips
mage_target: test:puppetFIPS
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: true
- name: Install Mage
run: go install github.com/magefile/mage@v1.17.2
- name: Start rngd (replenish entropy pool for FIPS crypto)
if: matrix.build == 'fips'
run: sudo apt-get install -y --no-install-recommends rng-tools && sudo rngd -r /dev/urandom
- name: Run Puppet stack integration tests
env:
MAGE_TARGET: ${{ matrix.mage_target }}
run: mage "$MAGE_TARGET"
# -- Migration integration tests --------------------------------------------
# Boots a real VoxPupuli Puppet Server, creates a genuine CA, then imports
# it into openvox-ca and verifies the full migration path.
migration:
name: Migration tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: true
- name: Install Mage
run: go install github.com/magefile/mage@v1.17.2
# Ahead of the suite it supports, and cheap: seconds on the host with no
# container runtime. A break in the helpers' retry bound or failure
# diagnostics would otherwise surface as a confusing migration failure,
# or -- worse for a change whose whole point is reporting -- not surface
# at all.
- name: Run migration HTTP helper tests
run: mage test:migrationHelpers
- name: Run migration integration tests
run: mage test:migration
# -- Storage backend integration tests --------------------------------------
# Runs the full Puppet stack against a Redis-backed CA topology with two
# CA replicas sharing a single Redis prefix. Validates blob offload,
# distributed bootstrap locking, cross-replica state visibility, and
# concurrent CSR submissions split across replicas.
backends-redis:
name: Storage backend tests (Redis)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: true
- name: Install Mage
run: go install github.com/magefile/mage@v1.17.2
- name: Run Redis-backend integration tests
run: mage test:backendsRedis
# Brings up a throwaway Redis and runs the Redis-backend Go integration suite
# (build tag redis_integration) against it. Distinct from backends-redis
# above, which runs the full-stack bash TAP suite; this job exercises the Go
# suite directly (Put/Get/Delete, List, concurrent AppendLine set-equality,
# cross-replica lock serialisation) so the build-tagged Go suite is not left
# unrun.
backends-redis-go:
name: Storage backend tests (Redis, Go suite)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: true
- name: Install Mage
run: go install github.com/magefile/mage@v1.17.2
- name: Run Redis-backend Go integration tests
run: mage test:backendsRedisGo
# Brings up a throwaway PostgreSQL and runs the SQL-backend Go integration
# suite (build tag postgres_integration) against it. Validates the PostgreSQL
# dialect: upsert, FOR UPDATE AppendLine atomicity across two backends, and
# pg_advisory_lock mutual exclusion. (SQLite needs no dedicated job: its tests
# run unconditionally in the unit job above.)
backends-postgres:
name: Storage backend tests (PostgreSQL)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: true
- name: Install Mage
run: go install github.com/magefile/mage@v1.17.2
- name: Run PostgreSQL-backend integration tests
run: mage test:backendsPostgres
# Brings up a throwaway MySQL and runs the SQL-backend Go integration suite
# (build tag mysql_integration) against it. Validates the MySQL/MariaDB
# dialect: LONGBLOB widening, ON DUPLICATE KEY upsert, FOR UPDATE AppendLine
# atomicity with InnoDB deadlock retry across two backends, and GET_LOCK
# mutual exclusion.
backends-mysql:
name: Storage backend tests (MySQL)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: true
- name: Install Mage
run: go install github.com/magefile/mage@v1.17.2
- name: Run MySQL-backend integration tests
run: mage test:backendsMySQL
# Runs the etcd-backend Go integration suite (build tag etcd_integration).
# The suite boots an in-process embedded etcd, so it needs no external service
# or compose stack.
backends-etcd:
name: Storage backend tests (etcd)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: true
- name: Install Mage
run: go install github.com/magefile/mage@v1.17.2
- name: Run etcd-backend integration tests
run: mage test:backendsEtcd
# Brings up a throwaway OpenBao dev server and runs the OpenBao Transit
# signer Go integration suite (build tag openbao_integration) against it: signs
# a digest through a real Transit key and verifies the signature, and
# exercises the "create the key on first boot" convenience path. The mage
# target also configures the transit engine and a scoped AppRole itself, so
# no extra setup step is needed here.
backends-openbao:
name: Storage backend tests (OpenBao)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: true
- name: Install Mage
run: go install github.com/magefile/mage@v1.17.2
- name: Run OpenBao-backend integration tests
run: mage test:backendsOpenBao
# -- Compose integration tests (docker compose) ------------------------------─
# podman-compose is not pre-installed on GitHub runners; composeCmd() in
# magefile.go falls back to `docker compose` (v2 plugin, always available).
# Same standard/FIPS matrix as the unit test job above.
compose:
name: Compose integration tests (${{ matrix.build }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- build: standard
mage_target: test:integCompose
- build: fips
mage_target: test:integComposeFIPS
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: true
- name: Install Mage
run: go install github.com/magefile/mage@v1.17.2
- name: Start rngd (replenish entropy pool for FIPS crypto)
if: matrix.build == 'fips'
run: sudo apt-get install -y --no-install-recommends rng-tools && sudo rngd -r /dev/urandom
- name: Run compose integration tests
env:
MAGE_TARGET: ${{ matrix.mage_target }}
run: mage "$MAGE_TARGET"
# -- Aggregate result ---------------------------------------------------------
# Single fan-in job so branch protection only has to name one required check,
# instead of every matrix leg above (which would also have to be updated by
# hand each time a leg is added/renamed/removed).
ci:
name: CI success
if: always()
needs:
- check
- hadolint
- markdownlint
- mixin
- chart
- unit
- dist
- puppet
- migration
- backends-redis
- backends-redis-go
- backends-postgres
- backends-mysql
- backends-etcd
- backends-openbao
- compose
runs-on: ubuntu-latest
steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@b5b5b37504aa4183270bd3d855c52a67f212be35 # v1.3.0
with:
jobs: ${{ toJSON(needs) }}
# -- Auto-merge bot PRs -------------------------------------------------------
# Holds contents: write / pull-requests: write and runs `gh pr merge`, so it
# is pinned to a default-branch base. The repository's "Main" ruleset -- the
# required reviews, status checks and code scanning that make an unattended
# merge safe -- applies to ~DEFAULT_BRANCH only, so enabling auto-merge on a
# PR targeting any other branch would merge it under no ruleset at all. The
# workflow's pull_request trigger is deliberately unfiltered by base (see the
# top of this file), which is what makes the condition load-bearing rather
# than a restatement of the trigger.
automerge:
name: Enable auto-merge
# The label exclusion is not decoration: renovate.json applies
# 'review-signing-path' to bumps of the release signing surface (cosign,
# Syft, actions/attest), and nothing in this workflow runs cosign — signing
# happens in container-images.yml's merge job and in helm-chart.yml, which
# has no pull_request trigger at all. Without this clause a bump that
# changed signing behaviour would go green here, merge unattended, and
# first misbehave on a tag. `mage dev:check` enforces the clause
# (verifyAutomergeLabelExclusion), so it cannot be tidied away.
if: >-
github.event_name == 'pull_request'
&& github.event.pull_request.base.ref == github.event.repository.default_branch
&& !contains(github.event.pull_request.labels.*.name, 'review-signing-path')
&& (github.event.pull_request.user.login == 'dependabot[bot]'
|| github.event.pull_request.user.login == 'renovate[bot]')
needs:
- ci
runs-on: ubuntu-24.04
permissions:
contents: write
pull-requests: write
steps:
- name: Enable auto-merge for PR
env:
GH_TOKEN: ${{ github.token }}
PR_URL: ${{ github.event.pull_request.html_url }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: gh pr merge --auto --merge --match-head-commit "$PR_HEAD_SHA" "$PR_URL"