feat: rename hawk binary, module, and config surface to graycode (#272) #822
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
| name: Docker | |
| on: | |
| push: | |
| branches: [main] | |
| tags: ["v*"] | |
| pull_request: | |
| branches: [main] | |
| paths: | |
| - "Dockerfile" | |
| - "internal/sandbox/container_version" | |
| - "internal/sandbox/sandbox.Dockerfile" | |
| - "**.go" | |
| - "go.mod" | |
| - "go.sum" | |
| permissions: | |
| contents: read | |
| packages: write | |
| security-events: write | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: graycodeai/graycode | |
| jobs: | |
| # Build each platform natively on its own runner (arm64 natively via the | |
| # ubuntu-24.04-arm runner instead of QEMU emulation, which took ~28 min for | |
| # the multi-arch push build). The two jobs run in parallel; merge-manifest | |
| # then combines the per-platform images into the shared multi-arch tags. | |
| # A cache mount in the Dockerfile (persisted through cache-to: gha, mode=max) | |
| # keeps per-commit rebuilds to a relink instead of a cold Go compile. | |
| build-amd64: | |
| name: build + scan (amd64) | |
| runs-on: ubuntu-latest | |
| outputs: | |
| image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:amd64-${{ github.sha }} | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 | |
| - name: Log in to GHCR | |
| if: github.event_name != 'pull_request' | |
| uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| # Build a single-platform image locally first so Trivy can gate the push: | |
| # CRITICAL/HIGH findings fail this job before anything reaches GHCR. | |
| - name: Build image for scan | |
| uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 | |
| with: | |
| context: . | |
| platforms: linux/amd64 | |
| push: false | |
| load: true | |
| tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:scan | |
| cache-from: type=gha,scope=graycode-amd64 | |
| cache-to: type=gha,mode=max,scope=graycode-amd64 | |
| build-args: | | |
| VERSION=${{ github.ref_name }} | |
| COMMIT=${{ github.sha }} | |
| BUILD_DATE=${{ github.event.head_commit.timestamp }} | |
| - name: Scan image with Trivy | |
| uses: aquasecurity/setup-trivy@3fb12ec12f41e471780db15c232d5dd185dcb514 | |
| with: | |
| version: v0.70.0 | |
| cache: true | |
| - name: Run Trivy scan (sarif) | |
| shell: bash | |
| run: | | |
| # Go reachability is enforced separately by govulncheck in CI. The | |
| # binary also carries the full workspace module graph, including | |
| # non-reachable packages that Trivy reports as binary findings. | |
| # CVE-2026-14456 (OpenSSL) is ignored via .trivyignore — the fixed | |
| # libcrypto 3.5.8-r0 is not yet published in Alpine 3.23. | |
| trivy image \ | |
| --severity CRITICAL,HIGH \ | |
| --ignore-unfixed \ | |
| --ignorefile "${GITHUB_WORKSPACE}/.trivyignore" \ | |
| --vuln-type os \ | |
| --format sarif \ | |
| --output trivy-image.sarif \ | |
| --exit-code 1 \ | |
| ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:scan | |
| # Second build is a cache hit (layers exported by the scan build), so it | |
| # only re-links and pushes the platform image. | |
| - name: Build and push (amd64) | |
| uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 | |
| with: | |
| context: . | |
| platforms: linux/amd64 | |
| push: ${{ github.event_name != 'pull_request' }} | |
| tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:amd64-${{ github.sha }} | |
| cache-from: type=gha,scope=graycode-amd64 | |
| cache-to: type=gha,mode=max,scope=graycode-amd64 | |
| build-args: | | |
| VERSION=${{ github.ref_name }} | |
| COMMIT=${{ github.sha }} | |
| BUILD_DATE=${{ github.event.head_commit.timestamp }} | |
| # Publish the scan results to GitHub code scanning. The scan itself runs | |
| # on PRs; only the release-side publish path stays off PRs. | |
| - name: Upload Trivy image scan results | |
| if: always() | |
| uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4 | |
| with: | |
| sarif_file: trivy-image.sarif | |
| build-arm64: | |
| name: build + scan (arm64) | |
| runs-on: ubuntu-24.04-arm | |
| outputs: | |
| image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:arm64-${{ github.sha }} | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 | |
| - name: Log in to GHCR | |
| if: github.event_name != 'pull_request' | |
| uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| # Build a single-platform image locally first so Trivy can gate the push: | |
| # CRITICAL/HIGH findings fail this job before anything reaches GHCR. | |
| - name: Build image for scan | |
| uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 | |
| with: | |
| context: . | |
| platforms: linux/arm64 | |
| push: false | |
| load: true | |
| tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:scan | |
| cache-from: type=gha,scope=graycode-arm64 | |
| cache-to: type=gha,mode=max,scope=graycode-arm64 | |
| build-args: | | |
| VERSION=${{ github.ref_name }} | |
| COMMIT=${{ github.sha }} | |
| BUILD_DATE=${{ github.event.head_commit.timestamp }} | |
| - name: Scan image with Trivy | |
| uses: aquasecurity/setup-trivy@3fb12ec12f41e471780db15c232d5dd185dcb514 | |
| with: | |
| version: v0.70.0 | |
| cache: true | |
| - name: Run Trivy scan (sarif) | |
| shell: bash | |
| run: | | |
| # Go reachability is enforced separately by govulncheck in CI. The | |
| # binary also carries the full workspace module graph, including | |
| # non-reachable packages that Trivy reports as binary findings. | |
| # CVE-2026-14456 (OpenSSL) is ignored via .trivyignore — the fixed | |
| # libcrypto 3.5.8-r0 is not yet published in Alpine 3.23. | |
| trivy image \ | |
| --severity CRITICAL,HIGH \ | |
| --ignore-unfixed \ | |
| --ignorefile "${GITHUB_WORKSPACE}/.trivyignore" \ | |
| --vuln-type os \ | |
| --format sarif \ | |
| --output trivy-image.sarif \ | |
| --exit-code 1 \ | |
| ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:scan | |
| # Second build is a cache hit (layers exported by the scan build), so it | |
| # only re-links and pushes the platform image. | |
| - name: Build and push (arm64) | |
| uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 | |
| with: | |
| context: . | |
| platforms: linux/arm64 | |
| push: ${{ github.event_name != 'pull_request' }} | |
| tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:arm64-${{ github.sha }} | |
| cache-from: type=gha,scope=graycode-arm64 | |
| cache-to: type=gha,mode=max,scope=graycode-arm64 | |
| build-args: | | |
| VERSION=${{ github.ref_name }} | |
| COMMIT=${{ github.sha }} | |
| BUILD_DATE=${{ github.event.head_commit.timestamp }} | |
| # Publish the scan results to GitHub code scanning. The scan itself runs | |
| # on PRs; only the release-side publish path stays off PRs. | |
| - name: Upload Trivy image scan results | |
| if: always() | |
| uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4 | |
| with: | |
| sarif_file: trivy-image.sarif | |
| merge-manifest: | |
| name: merge multi-arch manifest (release only) | |
| if: github.event_name != 'pull_request' | |
| needs: [build-amd64, build-arm64] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 | |
| - name: Log in to GHCR | |
| uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Docker metadata | |
| id: meta | |
| uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=ref,event=branch | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=sha,prefix=sha-,format=long | |
| # Point every shared tag (main, sha-<long>, semver) at a manifest list | |
| # covering both platform images pushed by the native jobs. | |
| - name: Merge per-platform images into multi-arch tags | |
| run: | | |
| set -euo pipefail | |
| src="${{ needs.build-amd64.outputs.image }} ${{ needs.build-arm64.outputs.image }}" | |
| printf '%s\n' "${{ steps.meta.outputs.tags }}" | while IFS= read -r tag; do | |
| if [ -n "$tag" ]; then | |
| docker buildx imagetools create -t "$tag" $src | |
| fi | |
| done | |
| sandbox-image: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| - name: Read sandbox image version | |
| id: sandbox-version | |
| shell: bash | |
| run: echo "tag=$(tr -d '[:space:]' < internal/sandbox/container_version)" >> "$GITHUB_OUTPUT" | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 | |
| - name: Log in to GHCR | |
| if: github.event_name != 'pull_request' | |
| uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build sandbox image for scan | |
| uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 | |
| with: | |
| context: internal/sandbox | |
| file: internal/sandbox/sandbox.Dockerfile | |
| platforms: linux/amd64 | |
| push: false | |
| load: true | |
| tags: ${{ env.REGISTRY }}/graycodeai/graycode-sandbox:scan | |
| cache-from: type=gha,scope=graycode-sandbox | |
| cache-to: type=gha,mode=max,scope=graycode-sandbox | |
| - name: Scan sandbox image | |
| uses: aquasecurity/setup-trivy@3fb12ec12f41e471780db15c232d5dd185dcb514 | |
| with: | |
| version: v0.70.0 | |
| cache: true | |
| - name: Run Trivy sandbox scan (sarif) | |
| shell: bash | |
| run: | | |
| # This image gate covers the Debian OS package surface. npm's | |
| # bundled CLI dependency tree is pinned by the Node base image and | |
| # reviewed separately from the runtime OS scan. | |
| trivy image \ | |
| --severity CRITICAL,HIGH \ | |
| --ignore-unfixed \ | |
| --ignorefile "${GITHUB_WORKSPACE}/.trivyignore" \ | |
| --vuln-type os \ | |
| --format sarif \ | |
| --output trivy-sandbox-image.sarif \ | |
| --exit-code 1 \ | |
| ${{ env.REGISTRY }}/graycodeai/graycode-sandbox:scan | |
| - name: Build and publish public sandbox image | |
| uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 | |
| with: | |
| context: internal/sandbox | |
| file: internal/sandbox/sandbox.Dockerfile | |
| platforms: linux/amd64,linux/arm64 | |
| push: ${{ github.event_name != 'pull_request' }} | |
| tags: | | |
| ${{ env.REGISTRY }}/graycodeai/graycode-sandbox:${{ steps.sandbox-version.outputs.tag }} | |
| ${{ env.REGISTRY }}/graycodeai/graycode-sandbox:latest | |
| cache-from: type=gha,scope=graycode-sandbox | |
| cache-to: type=gha,mode=max,scope=graycode-sandbox | |
| # Publish the sandbox scan to GitHub code scanning. PRs still run the | |
| # scan; they just do not publish the release image artifacts. | |
| - name: Upload sandbox image scan results | |
| if: always() | |
| uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4 | |
| with: | |
| sarif_file: trivy-sandbox-image.sarif |