name: Benchmark image — build + push to ECR (any adapter) # Adapter-agnostic image build. The bench image carries the full # ``tests/benchmarks/`` tree, so every registered adapter ships in the # same image. ``benchmark-run.yml`` selects which adapter actually runs # via its ``config`` input. See ``tests/benchmarks/_framework/registry.py`` # for the registration contract. # Builds tests/benchmarks/cloudopsbench/infra/Dockerfile.bench and pushes the resulting image to the # opensre-bench ECR repository. The bench container is what # `Benchmark run (manual)` invokes on AWS Fargate, so this workflow's # output is the input to that one. # # Triggered automatically on changes to the bench code (or the Dockerfile # itself) and manually via workflow_dispatch. # # After the image is pushed, update the task definition by re-applying the # Terraform with the new tag: # # cd tests/benchmarks/cloudopsbench/infra # terraform apply -var="image_tag=" # # (Or wire a follow-up step into this workflow to update task definition # automatically — out of scope for v1.) # # Tag format: short git SHA (`git rev-parse --short HEAD`). Stable, unique # per commit, recognizable in `aws ecr describe-images` output. ECR is # IMMUTABLE — a tag pushed once cannot be overwritten, so re-running the # workflow on the same commit just re-tags (no-op layer push). on: workflow_dispatch: inputs: tag: description: Image tag to push (default = short git SHA) required: false type: string push: branches: - main paths: - "tests/benchmarks/cloudopsbench/infra/Dockerfile.bench" - "tests/benchmarks/cloudopsbench/infra/Dockerfile.bench.dockerignore" - "pyproject.toml" - "uv.lock" - "surfaces/**" - "config/**" - "core/**" - "platform/deployment/**" - "integrations/**" - "platform/**" - "tools/**" - "tests/benchmarks/**" - ".github/workflows/benchmark-image.yml" permissions: contents: read id-token: write # required for AWS OIDC role assumption concurrency: # Allow one in-flight build per ref so two pushes in quick succession # don't race ECR. The newer push cancels the older. group: bench-image-${{ github.ref }} cancel-in-progress: true env: AWS_REGION: us-east-1 # Account ID is repo-level configuration, not a secret. Set as a GitHub # repository Variable (Settings > Secrets and variables > Actions > # Variables) so it doesn't need to be edited in every workflow file # when the bench moves accounts. ACCOUNT_ID: ${{ vars.AWS_ACCOUNT_ID }} ECR_REPOSITORY: opensre-bench jobs: build-and-push: if: github.repository == 'Tracer-Cloud/opensre' name: build + push runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v5 with: # Fetch enough history that `git rev-parse --short HEAD` is stable fetch-depth: 1 - name: Resolve image tag id: tag env: # Route `inputs.tag` through env so the shell treats it as DATA, # not code. Without this, a workflow_dispatch caller could inject # shell commands via a crafted `tag` value containing $() or # backticks. See: # https://securitylab.github.com/research/github-actions-untrusted-input/ INPUT_TAG: ${{ inputs.tag }} run: | if [ -n "$INPUT_TAG" ]; then TAG="$INPUT_TAG" else TAG="$(git rev-parse --short HEAD)" fi echo "tag=$TAG" >> "$GITHUB_OUTPUT" echo "Will push: $ECR_REPOSITORY:$TAG" - name: Configure AWS credentials (OIDC role assumption) uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT_ID }}:role/opensre-bench-github-actions role-session-name: github-actions-bench-image-${{ github.run_id }} aws-region: us-east-1 - name: Login to Amazon ECR id: ecr-login uses: aws-actions/amazon-ecr-login@v2 - name: Set up Docker Buildx # Buildx adds multi-platform support + better cache control. Even # for single-platform builds, it's the modern default. uses: docker/setup-buildx-action@v3 - name: Build and push id: build uses: docker/build-push-action@v6 with: context: . file: tests/benchmarks/cloudopsbench/infra/Dockerfile.bench platforms: linux/amd64 push: true tags: | ${{ steps.ecr-login.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ steps.tag.outputs.tag }} # Stamp the COMMIT SHA into the image so the runtime can read it # via the OPENSRE_SHA env var. We use github.sha (the full 40-char # commit being built), NOT steps.tag.outputs.tag (which resolves # to the user-supplied inputs.tag like ``hotfix-june`` on # workflow_dispatch and would stamp an unverifiable string as if # it were a SHA). The image tag (for ECR naming) and OPENSRE_SHA # (for provenance) are intentionally decoupled — the tag is for # humans/operators; the SHA is for reproducibility. The runtime # gate also validates SHA shape (7-40 lowercase hex chars), so # even a manually-built image with a bad OPENSRE_SHA fails loudly. build-args: | OPENSRE_SHA=${{ github.sha }} # GitHub Actions cache for Docker layers - speeds up rebuilds # when only the source changes (deps stay in the cached layer). cache-from: type=gha cache-to: type=gha,mode=max provenance: false # smaller manifest; matches ECR's tolerance for OCI - name: Summarise # Route step outputs through env so the shell sees them as DATA, # not code. `steps.tag.outputs.tag` is derived verbatim from the # `inputs.tag` user input — without env scoping, a workflow_dispatch # caller could inject shell commands here even though the # "Resolve image tag" step is hardened. Same risk applies to any # tag-derived chain. env: REGISTRY: ${{ steps.ecr-login.outputs.registry }} TAG: ${{ steps.tag.outputs.tag }} DIGEST: ${{ steps.build.outputs.digest }} run: | echo "## Image pushed" >> "$GITHUB_STEP_SUMMARY" echo "" >> "$GITHUB_STEP_SUMMARY" echo "| field | value |" >> "$GITHUB_STEP_SUMMARY" echo "| --- | --- |" >> "$GITHUB_STEP_SUMMARY" echo "| Registry | \`$REGISTRY\` |" >> "$GITHUB_STEP_SUMMARY" echo "| Repository | \`$ECR_REPOSITORY\` |" >> "$GITHUB_STEP_SUMMARY" echo "| Tag | \`$TAG\` |" >> "$GITHUB_STEP_SUMMARY" echo "| Digest | \`$DIGEST\` |" >> "$GITHUB_STEP_SUMMARY" echo "" >> "$GITHUB_STEP_SUMMARY" echo "To deploy this image:" >> "$GITHUB_STEP_SUMMARY" echo "" >> "$GITHUB_STEP_SUMMARY" echo "\`\`\`bash" >> "$GITHUB_STEP_SUMMARY" echo "cd tests/benchmarks/cloudopsbench/infra" >> "$GITHUB_STEP_SUMMARY" echo "terraform apply -var=\"image_tag=$TAG\"" >> "$GITHUB_STEP_SUMMARY" echo "\`\`\`" >> "$GITHUB_STEP_SUMMARY"