Repository navigation
Conversation
The Dockerfile now has two runtime targets that share one base: - agent (default, last stage): same image as before, with Node and snyk-broker. - grpc: no Node and no snyk-broker. AXON_RELAY_TRANSPORT is forced to grpc-tunnel when snyk-broker is not on the image. Agent files are copied in a final layer, so a code change no longer rebuilds the snyk-broker layer. curl is now installed explicitly; the github-app-token plugin needs it, and before it came only from the NodeSource setup script. CI builds both targets through a reusable workflow. The grpc variant publishes to the same package with a -grpc suffix on every tag, never moves latest, and has its own Trivy SARIF category and daily scan. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment on lines
+29
to
+115
| runs-on: ubuntu-latest | ||
| env: | ||
| IS_DEFAULT_BRANCH: ${{ github.ref == format('refs/heads/{0}', 'main') }} | ||
| IS_TAG: ${{ startsWith(github.ref, 'refs/tags/') }} | ||
| IS_PUBLISH: ${{ github.event_name == 'workflow_dispatch' || github.ref == format('refs/heads/{0}', 'main') || startsWith(github.ref, 'refs/tags/') }} | ||
| # ARM64 builds via QEMU are slow - only build on main/tags, not workflow_dispatch | ||
| IS_ARM64_BUILD: ${{ github.ref == format('refs/heads/{0}', 'main') || startsWith(github.ref, 'refs/tags/') }} | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v6 | ||
| - name: Set up QEMU | ||
| uses: docker/setup-qemu-action@v3 | ||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@v3 | ||
| - name: Cache Docker layers | ||
| uses: actions/cache@v5 | ||
| with: | ||
| path: /tmp/.buildx-cache | ||
| key: ${{ runner.os }}-buildx-${{ inputs.target }}-${{ github.sha }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-buildx-${{ inputs.target }}- | ||
|
|
||
| - name: Log in to GitHub Container Registry | ||
| uses: docker/login-action@v3 | ||
| with: | ||
| registry: ghcr.io | ||
| username: ${{ github.actor }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Docker meta | ||
| id: meta | ||
| uses: docker/metadata-action@v5 | ||
| with: | ||
| images: | | ||
| ghcr.io/${{ github.repository_owner }}/cortex-axon-agent | ||
| flavor: | | ||
| latest=${{ inputs.latest }} | ||
| suffix=${{ inputs.tag-suffix }} | ||
| tags: | | ||
| type=ref,event=branch | ||
| type=semver,pattern={{version}} | ||
| type=semver,pattern={{major}}.{{minor}} | ||
| type=sha | ||
|
|
||
| - name: Build and push Docker image | ||
| uses: docker/build-push-action@v6 | ||
| with: | ||
| file: ./docker/Dockerfile | ||
| target: ${{ inputs.target }} | ||
| push: ${{ env.IS_PUBLISH == 'true' }} | ||
| tags: ${{ steps.meta.outputs.tags }} | ||
| labels: ${{ steps.meta.outputs.labels }} | ||
| build-args: | | ||
| BUILD_VERSION=${{ github.ref_name }}-${{ github.sha }} | ||
| # arm64 via QEMU is slow, so only build it on main branch or tags (not workflow_dispatch) | ||
| platforms: ${{ env.IS_ARM64_BUILD == 'true' && 'linux/amd64,linux/arm64' || 'linux/amd64' }} | ||
| cache-from: type=local,src=/tmp/.buildx-cache | ||
| cache-to: type=local,dest=/tmp/.buildx-cache | ||
| load: ${{ env.IS_PUBLISH != 'true' }} | ||
|
|
||
| - name: Determine local image tag | ||
| if: env.IS_PUBLISH != 'true' | ||
| id: local-tag | ||
| run: echo "tag=$(echo '${{ steps.meta.outputs.tags }}' | head -n1)" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Save Docker image for scanning | ||
| if: env.IS_PUBLISH != 'true' | ||
| run: docker save '${{ steps.local-tag.outputs.tag }}' -o /tmp/docker-image.tar | ||
|
|
||
| - name: Upload Docker image artifact | ||
| if: env.IS_PUBLISH != 'true' | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: docker-image-${{ inputs.target }} | ||
| path: /tmp/docker-image.tar | ||
| retention-days: 1 | ||
|
|
||
| outputs: | ||
| image-tag: ${{ steps.local-tag.outputs.tag }} | ||
| # The primary tag metadata-action resolved -- the semver version on a | ||
| # tag build, the branch name on main. The release scan targets this | ||
| # rather than a hardcoded :main, so a tag build reports on the image | ||
| # that tag actually published. | ||
| published-ref: ghcr.io/${{ github.repository_owner }}/cortex-axon-agent:${{ steps.meta.outputs.version }} | ||
|
|
||
| trivy-pr: |
Comment on lines
+116
to
+169
| name: Run Trivy PR scan (local image) | ||
| needs: build | ||
| if: ${{ !(github.event_name == 'workflow_dispatch' || github.ref == format('refs/heads/{0}', 'main') || startsWith(github.ref, 'refs/tags/')) }} | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Download Docker image artifact | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| name: docker-image-${{ inputs.target }} | ||
| path: /tmp | ||
|
|
||
| - name: Load Docker image | ||
| run: docker load -i /tmp/docker-image.tar | ||
|
|
||
| - name: Run Trivy vulnerability scanner (SARIF) | ||
| uses: aquasecurity/trivy-action@master | ||
| with: | ||
| image-ref: ${{ needs.build.outputs.image-tag }} | ||
| format: 'sarif' | ||
| output: 'trivy-results.sarif' | ||
| severity: 'CRITICAL,HIGH' | ||
| ignore-unfixed: true | ||
| exit-code: '0' | ||
| skip-dirs: 'usr/local/go' | ||
|
|
||
| - name: Upload Trivy scan results to GitHub Security tab | ||
| uses: github/codeql-action/upload-sarif@v4.32.2 | ||
| with: | ||
| sarif_file: 'trivy-results.sarif' | ||
| # Matches the release scan's category so PR and post-merge findings | ||
| # for this image track one series instead of churning against | ||
| # each other in the Security tab. | ||
| category: ${{ inputs.category }} | ||
|
|
||
| # The bypass-trivy-fail label lets a PR merge past CVEs it did not | ||
| # introduce. The findings are still uploaded above and listed here. | ||
| - name: Fail on CRITICAL/HIGH vulnerabilities | ||
| env: | ||
| BYPASS: ${{ contains(github.event.pull_request.labels.*.name, 'bypass-trivy-fail') }} | ||
| run: | | ||
| COUNT=$(jq '[.runs[].results[] | select(.level == "error")] | length' trivy-results.sarif) | ||
| if [ "$COUNT" -gt 0 ]; then | ||
| LEVEL=error | ||
| if [ "$BYPASS" = "true" ]; then LEVEL=warning; fi | ||
| echo "::$LEVEL::Found $COUNT CRITICAL/HIGH fixable vulnerabilities:" | ||
| jq -r '.runs[].results[] | select(.level == "error") | "\(.ruleId): \(.message.text | split("\n") | .[0])"' trivy-results.sarif | ||
| if [ "$BYPASS" = "true" ]; then | ||
| echo "::warning::Not failing: the PR has the bypass-trivy-fail label." | ||
| exit 0 | ||
| fi | ||
| exit 1 | ||
| fi | ||
|
|
||
| trivy: |
Comment on lines
+18
to
+25
| name: Agent image | ||
| uses: ./.github/workflows/docker-image.yml | ||
| with: | ||
| image-ref: ${{ needs.build.outputs.published-ref }} | ||
| target: agent | ||
| category: trivy-cortex-axon-agent | ||
| secrets: inherit | ||
|
|
||
| grpc: |
Comment on lines
+26
to
+33
| name: Agent image (gRPC only) | ||
| uses: ./.github/workflows/docker-image.yml | ||
| with: | ||
| target: grpc | ||
| tag-suffix: -grpc | ||
| latest: 'false' | ||
| category: trivy-cortex-axon-agent-grpc | ||
| secrets: inherit |
Contributor
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
docker-tests-grpc and the tunnel load test built the default image, so no test exercised the image without Node and snyk-broker. They now build the grpc target, tagged cortex-axon-agent:local-grpc so it does not replace the default local image. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds a second variant of the agent image that has no Node.js and no snyk-broker. The variant publishes to the same package,
ghcr.io/cortexapps/cortex-axon-agent, with a-grpcsuffix on every tag. The default image does not change.:1.4.0,:main,:latestAXON_RELAY_TRANSPORTselects it; defaultsnyk-broker:1.4.0-grpc,:main-grpcgrpc-tunnelChanges
docker/Dockerfile: There are now four stages:builder→base(OS packages, Go, static env) →files(agent binary, accept files, plugins, scaffolds, scripts) →grpc/agent.agentis the last stage, so a build without--targetstill produces the default image. The agent files are copied in the final layer, so a code change no longer rebuilds the snyk-broker layer.curlis now installed explicitly. Thegithub-app-tokenplugin callscurl. Before,curlcame into the image only through the NodeSource setup script, so without this change the gRPC image would break GitHub App auth.docker/start,docker/entrypoint.sh: Whensnyk-brokeris not in the image, the scripts forceAXON_RELAY_TRANSPORT=grpc-tunnel.docker-image.yml.docker.ymlcalls it once for each variant. The gRPC variant useslatest=false, so it never moveslatest. Each variant has its own Trivy SARIF category, its own buildx cache key, and its own PR artifact name.trivy.ymlalso scans:main-grpcevery day.Makefile: Adds adocker-build-grpctarget.README.relay.md: Documents the-grpctags.docker-tests-grpcand the tunnel load test now build thegrpctarget, taggedcortex-axon-agent:local-grpc. So the gRPC e2e scenarios run on the image without Node.docker-testsstill runs the snyk-broker scenarios on the default image.Notes for reviewers
Run Trivy PR scan (local image)becomesAgent image / Run Trivy PR scan (local image). If branch protection requires the old names, update it.Test plan
docker-tests-grpcpasses on the-grpcimage (with and without proxy).docker-testspasses on the default image (snyk-broker).docker run --rm --entrypoint sh <grpc image> -c 'command -v node snyk-broker npm'prints nothing.-grpcimage runs the gRPC tunnel whenAXON_RELAY_TRANSPORT=snyk-brokeris set.🤖 Generated with Claude Code