From fdbee68a8dc51bea1fe48e30fb158928cc85c8e3 Mon Sep 17 00:00:00 2001 From: "ccf-lisa[bot]" <286799724+ccf-lisa[bot]@users.noreply.github.com> Date: Fri, 9 Oct 2026 11:15:15 -0300 Subject: [PATCH 1/2] ci: release, preview and cut-prerelease workflows --- .github/workflows/cut-prerelease.yml | 13 +++++++ .github/workflows/preview.yml | 28 ++++++++++++++ .github/workflows/publish.yml | 56 ---------------------------- .github/workflows/release.yml | 21 +++++++++++ 4 files changed, 62 insertions(+), 56 deletions(-) create mode 100644 .github/workflows/cut-prerelease.yml create mode 100644 .github/workflows/preview.yml delete mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/cut-prerelease.yml b/.github/workflows/cut-prerelease.yml new file mode 100644 index 00000000..e841d585 --- /dev/null +++ b/.github/workflows/cut-prerelease.yml @@ -0,0 +1,13 @@ +# Cuts the next release candidate (vX.Y.Z-rcN) of the version the open release-please PR +# proposes, as ccf-release-bot; release.yml then publishes :X.Y.Z-rcN. Run it by hand. +name: cut-prerelease +on: + workflow_dispatch: +permissions: + contents: read +jobs: + cut: + uses: compliance-framework/workflows/.github/workflows/cut-prerelease.yml@899dbe5d7dac02de5fd60a92d764b189259e03dd # v1.5.0 + permissions: + contents: read + secrets: inherit diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml new file mode 100644 index 00000000..bd45c243 --- /dev/null +++ b/.github/workflows/preview.yml @@ -0,0 +1,28 @@ +# Publishes preview images of ghcr.io/compliance-framework/api: :main and :sha-<7> on pushes to +# main, and :pr- on PRs labelled `preview`. It never moves :latest (release.yml does). +name: preview + +on: + push: + branches: [main] + pull_request: + types: [opened, synchronize, reopened, labeled] + +permissions: + contents: read + +concurrency: + # A merged PR's events carry the base branch as github.ref, so key PR runs by number. + group: preview-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + preview: + uses: compliance-framework/workflows/.github/workflows/preview.yml@899dbe5d7dac02de5fd60a92d764b189259e03dd # v1.5.0 + with: + kind: image + on-main: true + images: '[{"name":"api","dockerfile":"Dockerfile","context":"."}]' + permissions: + contents: read + packages: write diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index f72ab405..00000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: Publish - -permissions: - contents: read - -on: - push: - branches: - - main - - seed - tags: - - v* - -jobs: - publish: - runs-on: ubuntu-latest - permissions: - packages: write - contents: read - steps: - - uses: actions/checkout@v4 - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v3 - - name: Docker meta - id: meta - uses: docker/metadata-action@v5 - with: - images: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }} - flavor: | - latest=auto - tags: | - type=raw,value=latest,enable={{is_default_branch}} - type=schedule - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - type=ref,event=branch - type=ref,event=pr - type=sha - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push - uses: docker/build-push-action@v5 - with: - context: . - platforms: linux/amd64,linux/arm64 - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - push: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..cbc637fb --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,21 @@ +# Publishes ghcr.io/compliance-framework/api when a release is published: for vX.Y.Z the tags +# X.Y.Z, X.Y, X and latest; for an rc (vX.Y.Z-rcN, from cut-prerelease) only X.Y.Z-rcN. +# Built for linux/amd64 and linux/arm64 with the build arg VERSION=X.Y.Z[-rcN]. +name: release + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + release: + uses: compliance-framework/workflows/.github/workflows/release-go-image.yml@899dbe5d7dac02de5fd60a92d764b189259e03dd # v1.5.0 + with: + images: '[{"name":"api","dockerfile":"Dockerfile","context":"."}]' + permissions: + contents: read + packages: write + secrets: inherit From 42c1cb5859f91631e247be79071604f52587ccae Mon Sep 17 00:00:00 2001 From: "ccf-lisa[bot]" <286799724+ccf-lisa[bot]@users.noreply.github.com> Date: Fri, 9 Oct 2026 11:15:15 -0300 Subject: [PATCH 2/2] build: keep the image's OCI labels and document the release flow --- AGENTS.md | 6 ++++-- Dockerfile | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index d58a989a..edf3cdc6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -19,8 +19,10 @@ Versions are coupled: - plugins pin the agent; - the UI depends on our JSON shapes. -Releases are tags (`vX.Y.Z`, or `vX.Y.Z-rcN` for release candidates). CI publishes -`ghcr.io/compliance-framework/api`; the publish workflow takes about 20 minutes. A +Releases are tags (`vX.Y.Z`, or `vX.Y.Z-rcN` for release candidates), created by release-please +when its release PR merges and by the `cut-prerelease` workflow for an rc; nobody pushes them by +hand. Each published release runs `release.yml`, which publishes `ghcr.io/compliance-framework/api`; +`preview.yml` publishes `:main`, `:sha-<7>` and, on PRs labelled `preview`, `:pr-`. A mixed-version rollout must keep working: a new API must accept evidence from older agents. ## Commands diff --git a/Dockerfile b/Dockerfile index eb4dcf8f..5ae00463 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,6 +32,15 @@ RUN GOOS=linux go build -o /api FROM gcr.io/distroless/base-debian12 AS production +# The release and preview workflows pass VERSION (X.Y.Z, X.Y.Z-rcN, main- or +# pr--) and set the source and revision labels themselves. +ARG VERSION=dev +LABEL org.opencontainers.image.title="api" \ + org.opencontainers.image.description="Service responsible for storing and retrieving OSCAL configuration" \ + org.opencontainers.image.url="https://github.com/compliance-framework/api" \ + org.opencontainers.image.licenses="AGPL-3.0" \ + org.opencontainers.image.version="${VERSION}" + COPY --from=builder /api /api # Open port 8080 to traffic EXPOSE 8080