-
Notifications
You must be signed in to change notification settings - Fork 3
STAC-25457 Publish and sign the agent and cluster-agent images from GitHub Actions #454
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: STAC-25142-agent-lint-unit
Are you sure you want to change the base?
Changes from all commits
98efcef
93709cd
61e2bce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -236,7 +236,7 @@ jobs: | |
| timeout-minutes: 60 | ||
| env: | ||
| ARCH: ${{ matrix.arch }} | ||
| LOCAL_IMAGE: stackstate-agent:ci-${{ matrix.arch }} | ||
| LOCAL_IMAGE: quay.io/stackstate/stackstate-k8s-agent:ci-${{ matrix.arch }} | ||
| steps: | ||
| - name: Check out repository | ||
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
|
|
@@ -255,8 +255,6 @@ jobs: | |
| REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} | ||
| run: | | ||
| set -eo pipefail | ||
| # Dockerfiles/agent pulls its ubuntu extract stage through the proxy; | ||
| # the BCI stages come from registry.suse.com and need no auth. | ||
| printf '%s' "${REGISTRY_PASSWORD}" | docker login -u "${REGISTRY_USER}" --password-stdin "${REGISTRY_HOST}" | ||
|
|
||
| - name: Build agent image | ||
|
|
@@ -278,6 +276,129 @@ jobs: | |
| set -eo pipefail | ||
| docker run --rm --entrypoint /opt/stackstate-agent/bin/agent/agent "${LOCAL_IMAGE}" version | ||
|
|
||
| - name: Scan agent image (Trivy and Grype vulnerabilities, VEX-aware, plus Trivy secrets) | ||
| uses: StackVista/image-pipeline/.github/actions/scan-image@6284a6fc006a7cc46a7f00d02c50d5f21b117b63 | ||
| with: | ||
| image: ${{ env.LOCAL_IMAGE }} | ||
| mode: gate | ||
| severity: UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL | ||
| with-grype: true | ||
| exceptions-path: exceptions | ||
| upload-sarif: false | ||
| sarif-category: stackstate-k8s-agent-${{ matrix.arch }} | ||
|
|
||
| publish-agent-image: | ||
| name: Publish and sign agent image (${{ matrix.arch }}) | ||
| if: github.event_name == 'push' | ||
| needs: | ||
| - build-agent-image | ||
| - test-deb-renaming | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| - arch: amd64 | ||
| runner: docker-public | ||
| - arch: arm64 | ||
| runner: arm64-xlarge-public | ||
| runs-on: ${{ matrix.runner }} | ||
| timeout-minutes: 60 | ||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| env: | ||
| ARCH: ${{ matrix.arch }} | ||
| IMAGE: quay.io/stackstate/stackstate-k8s-agent | ||
| steps: | ||
| - name: Check out repository | ||
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - name: Download DEB package | ||
| uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 | ||
| with: | ||
| name: deb-package-${{ matrix.arch }} | ||
|
|
||
| - name: Stage the DEB in the image build context | ||
| run: | | ||
| set -eo pipefail | ||
| shopt -s nullglob | ||
| debs=(outcomes/pkg/stackstate-agent_*_"${ARCH}".deb) | ||
| if [ "${#debs[@]}" -ne 1 ]; then | ||
| echo "Expected exactly one stackstate-agent_*_${ARCH}.deb, found ${#debs[@]}: ${debs[*]}" >&2 | ||
| exit 1 | ||
| fi | ||
| cp "${debs[0]}" Dockerfiles/agent/ | ||
|
|
||
| - name: Resolve image tag | ||
| id: image | ||
| env: | ||
| SOURCE_SHA: ${{ github.sha }} | ||
| run: | | ||
| set -euo pipefail | ||
| echo "tag=$(printf '%s' "${SOURCE_SHA}" | cut -c1-8)" >> "${GITHUB_OUTPUT}" | ||
|
|
||
| - name: Resolve canonical OCI labels | ||
| id: oci | ||
| uses: StackVista/image-pipeline/.github/actions/apply-oci-labels@6284a6fc006a7cc46a7f00d02c50d5f21b117b63 | ||
| with: | ||
| image-name: stackstate-k8s-agent | ||
| tag: ${{ steps.image.outputs.tag }} | ||
| title: SUSE Observability Agent | ||
| description: Node agent collecting metrics, logs, traces and topology for SUSE Observability. | ||
| component: stackstate-k8s-agent | ||
| dockerfile: Dockerfiles/agent/Dockerfile | ||
| base-name: registry.suse.com/bci/bci-micro:latest | ||
| registry-credentials: | | ||
| [{"registry": "${{ vars.REGISTRY_HOST }}", "username": "${{ vars.REGISTRY_USER }}", "password": "${{ secrets.REGISTRY_PASSWORD }}"}] | ||
|
|
||
| - name: Build, publish, and sign architecture image | ||
| uses: StackVista/image-pipeline/.github/actions/push-single-arch@6284a6fc006a7cc46a7f00d02c50d5f21b117b63 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P1] Gate publication on image scanning.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in Publication is now gated on the scan through the job graph.
You were right that the cluster-agent path had the same gap; both are covered now. Two things were needed to make the gate actually bite, and the second was not obvious:
I checked this against the real evaluator rather than by eye — built Confirmed on CI (amd64): The secret scan runs as a separate fail-closed invocation, unfiltered by severity, per the AGENTS.md rule. |
||
| with: | ||
| image: ${{ env.IMAGE }} | ||
| tag: ${{ steps.image.outputs.tag }} | ||
| arch: ${{ matrix.arch }} | ||
| docker-context: Dockerfiles/agent | ||
| dockerfile: Dockerfiles/agent/Dockerfile | ||
| build-args: ARCH=${{ matrix.arch }} | ||
| labels: | | ||
| ${{ steps.oci.outputs.labels }} | ||
| org.opencontainers.image.revision=${{ github.sha }} | ||
| source-registry-credentials: | | ||
| [{"registry": "${{ vars.REGISTRY_HOST }}", "username": "${{ vars.REGISTRY_USER }}", "password": "${{ secrets.REGISTRY_PASSWORD }}"}] | ||
| target-registry: quay.io | ||
| target-registry-user: ${{ vars.QUAY_USER }} | ||
| target-registry-password: ${{ secrets.QUAY_PASSWORD }} | ||
|
|
||
| merge-agent-manifest: | ||
| name: Publish and sign multi-architecture agent image | ||
| if: github.event_name == 'push' | ||
| needs: publish-agent-image | ||
| runs-on: docker-public | ||
| timeout-minutes: 30 | ||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| steps: | ||
| - name: Resolve image tag | ||
| id: image | ||
| env: | ||
| SOURCE_SHA: ${{ github.sha }} | ||
| run: | | ||
| set -euo pipefail | ||
| echo "tag=$(printf '%s' "${SOURCE_SHA}" | cut -c1-8)" >> "${GITHUB_OUTPUT}" | ||
|
|
||
| - name: Merge and sign multi-architecture manifest | ||
| uses: StackVista/image-pipeline/.github/actions/merge-multiarch@6284a6fc006a7cc46a7f00d02c50d5f21b117b63 | ||
| with: | ||
| image: quay.io/stackstate/stackstate-k8s-agent | ||
| tag: ${{ steps.image.outputs.tag }} | ||
| arches: amd64,arm64 | ||
| target-registry: quay.io | ||
| target-registry-user: ${{ vars.QUAY_USER }} | ||
| target-registry-password: ${{ secrets.QUAY_PASSWORD }} | ||
|
|
||
| cerberus-notify: | ||
| name: Report failure to Slack (Cerberus) | ||
| needs: | ||
|
|
@@ -286,6 +407,8 @@ jobs: | |
| - build-deb | ||
| - test-deb-renaming | ||
| - build-agent-image | ||
| - publish-agent-image | ||
| - merge-agent-manifest | ||
| if: >- | ||
| always() | ||
| && github.event_name == 'push' | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| schema_version: '1' | ||
| vulnerability: | ||
| id: CVE-2025-15366 | ||
| severity: MEDIUM | ||
| product: | ||
| consumer: stackstate-k8s-agent | ||
| image: quay.io/stackstate/stackstate-k8s-agent | ||
| component: | ||
| purl: pkg:generic/python@3.13.13 | ||
| paths: | ||
| - opt/stackstate-agent/embedded/bin/python3.13 | ||
| status: accepted_pending_upstream_fix | ||
| reason: no_upstream_fix_for_pinned_runtime_line | ||
| expires: '2026-08-20' | ||
| owner: "@StackVista/observability-team" | ||
| upstream_owner: python | ||
| upstream_reference: https://www.cve.org/CVERecord?id=CVE-2025-15366 | ||
| statement: | | ||
| No fix is published for the CPython 3.13 maintenance line. Upstream | ||
| currently carries the fix only in 3.15.0a6, a pre-release of a different | ||
| minor version, so there is no compatible patch we could apply without | ||
| moving the embedded interpreter to an unreleased runtime. Under the | ||
| remediation SLA this falls outside the patch commitment, so the date below | ||
| is a short review deadline rather than an acceptance: re-check upstream for | ||
| a 3.13 backport before renewing. Tracked with the rest of the | ||
| embedded-runtime work in STAC-25556. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[P2] Pull BCI bases through the SUSE Private Registry proxy. These jobs run on self-hosted
docker-publicandarm64-xlarge-public, but both Dockerfiles pull BCI stages directly fromregistry.suse.com. Parameterize those bases and passregistry.tooling.stackstate.io/suse/...to both builds;source-registry-credentialsdoes not rewrite theFROMreferences.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@LouisParkin some of this feedback is recurring now. Something I find useful is to tell the agent to not only fix feedback like this but also understand why this mistake happened and write down guidance so it does not make the same mistake again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. Both Dockerfiles now parameterize the base registry and default it to the proxy:
Dockerfiles/agent/DockerfileDockerfiles/cluster-agent/Dockerfilegets the same treatment, including theubuntu:20.04builder stage.Your diagnosis was exactly right:
source-registry-credentialsauthenticates but does not rewriteFROM, so the proxying has to happen where the base is named. Defaulting in the Dockerfile rather than passing--build-argfrom the workflow is deliberate — these Dockerfiles are built from more places than this workflow (the GitLab jobs during the overlap period, local helper scripts), and only the default reaches all of them. It also matches theBASE_IMAGE_REGISTRYconvention already in the files.One deliberate exception:
apply-oci-labels'base-namestays onregistry.suse.com/bci/bci-micro:latest. That feedsorg.opencontainers.image.base.name, which VEX data and base-image tracking key on upstream identity, so it should record where the base really comes from even though the bytes arrive via the proxy.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair point, and taken. The recurrence was the signal — the same class of mistake kept reappearing because the reasoning behind the fix lived only in review threads.
The guidance is now written down in the mission-control wiki, in
wiki/concepts/gitlab-to-github-ci-porting.md, as a section titled "The registry proxy is a Dockerfile concern, not a credentials concern". It records the trap in the form that actually causes it:...along with the rule (
ARGbefore the firstFROM, defaulted to the proxy), why the default belongs in the Dockerfile rather than in a workflow--build-arg, and two caveats that are easy to get wrong in the opposite direction:apply-oci-labels'base-nameon the upstream name, because VEX and base-image tracking key on upstream identityThe same document now also carries the scan-gate section and the house rule on not commenting YAML, both of which came out of this review round.