From ad7d34829742d7a49680a14ee62c3fbea0511a3a Mon Sep 17 00:00:00 2001 From: Terry Tata Date: Mon, 5 Oct 2026 15:55:19 -0700 Subject: [PATCH 1/4] secret free workflows --- .github/actions/aws-ecr-auth/action.yaml | 9 +++- .../actions/build-devenv-docker/action.yaml | 10 ++-- .github/actions/run-load-test/action.yaml | 15 +++--- .../actions/setup-github-token/action.yaml | 53 +++++++++++++++++++ .github/workflows/golangci-lint.yaml | 2 +- .github/workflows/repo-hygiene.yaml | 2 +- .github/workflows/test-cl-smoke.yaml | 31 +++++++++-- .github/workflows/test-coverage-report.yaml | 4 ++ .github/workflows/test-deployment-module.yaml | 2 +- .github/workflows/test-devenv-module.yaml | 2 +- .../test-evm-integration-module.yaml | 2 +- .github/workflows/test-services.yaml | 2 +- .github/workflows/test-smoke.yaml | 25 +++++++-- 13 files changed, 134 insertions(+), 25 deletions(-) create mode 100644 .github/actions/setup-github-token/action.yaml diff --git a/.github/actions/aws-ecr-auth/action.yaml b/.github/actions/aws-ecr-auth/action.yaml index e90851a99..5fe4a1bc3 100644 --- a/.github/actions/aws-ecr-auth/action.yaml +++ b/.github/actions/aws-ecr-auth/action.yaml @@ -1,9 +1,12 @@ name: 'AWS ECR Authentication' description: 'Configure AWS credentials and authenticate to ECR Public' inputs: + # An empty role (no repo secrets, e.g. Dependabot PR runs) skips auth entirely; + # callers must then skip any step that pulls from ECR. role-to-assume: - description: 'IAM role to assume' - required: true + description: 'IAM role to assume. Empty skips authentication.' + required: false + default: '' aws-region: description: 'AWS region' required: true @@ -20,12 +23,14 @@ runs: using: "composite" steps: - name: Configure AWS credentials using OIDC + if: inputs.role-to-assume != '' uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 with: role-to-assume: ${{ inputs.role-to-assume }} aws-region: ${{ inputs.aws-region }} - name: Authenticate to ECR id: login-ecr + if: inputs.role-to-assume != '' uses: aws-actions/amazon-ecr-login@062b18b96a7aff071d4dc91bc00c4c1a7945b076 # v2.0.1 with: registry-type: ${{ inputs.registry-type }} diff --git a/.github/actions/build-devenv-docker/action.yaml b/.github/actions/build-devenv-docker/action.yaml index e3e44686f..a26fb0f23 100644 --- a/.github/actions/build-devenv-docker/action.yaml +++ b/.github/actions/build-devenv-docker/action.yaml @@ -3,11 +3,15 @@ description: Build CCV service images via just build-docker-ci inputs: ccv-iam-role: - description: 'AWS IAM role for CCV' - required: true + # Empty on secretless runs (Dependabot PRs); the ECR auth steps then self-skip, + # which is fine because these builds pull only public base images. + description: 'AWS IAM role for CCV. Empty skips ECR authentication.' + required: false + default: '' jd-registry: description: 'JD registry ID' - required: true + required: false + default: '' runs: using: composite diff --git a/.github/actions/run-load-test/action.yaml b/.github/actions/run-load-test/action.yaml index f549494ed..b3d6d0d2c 100644 --- a/.github/actions/run-load-test/action.yaml +++ b/.github/actions/run-load-test/action.yaml @@ -9,14 +9,17 @@ inputs: description: 'Test timeout duration' required: true ccv-iam-role: - description: 'AWS IAM role for CCV' - required: true + description: 'AWS IAM role for CCV. Empty skips ECR authentication.' + required: false + default: '' jd-registry: - description: 'JD registry ID' - required: true + description: 'JD registry ID. Empty skips the private ECR login.' + required: false + default: '' jd-image: - description: 'JD Docker image' - required: true + description: 'JD Docker image. Empty (secretless runs) fails the load test; gate those jobs instead.' + required: false + default: '' env_name: description: 'Environment name for CCV' required: false diff --git a/.github/actions/setup-github-token/action.yaml b/.github/actions/setup-github-token/action.yaml new file mode 100644 index 000000000..27c2057fc --- /dev/null +++ b/.github/actions/setup-github-token/action.yaml @@ -0,0 +1,53 @@ +name: Setup GitHub Token +description: >- + Calls smartcontractkit/.github's GATI token setup, or skips it when the GATI + secrets are unavailable. Dependabot and fork PR runs get no repo secrets, and + all module dependencies of these workflows are public, so the token is + optional there; the merge queue (merge_group) always runs with full secrets. + +inputs: + aws-role-arn: + description: ARN of role capable of getting token from GATI + required: false + default: '' + aws-lambda-url: + description: URL of GATI lambda function + required: false + default: '' + aws-region: + description: AWS region + required: false + default: '' + aws-role-duration-seconds: + description: Duration of role in seconds + required: false + default: '900' + role-session-name: + description: Session name to use when assuming the role. + required: false + default: '${{ github.run_id }}-${{ github.run_number }}-${{ github.job }}' + set-git-config: + description: Set git config + required: false + default: 'false' + +outputs: + access-token: + description: The github access token that has permissions reflecting the current AWS role value + value: ${{ steps.gati.outputs.access-token }} + +runs: + using: composite + steps: + # Empty inputs mean the run has no repo secrets (Dependabot or fork PR), so skip GATI. + - name: Setup GitHub Token + id: gati + if: inputs.aws-region != '' && inputs.aws-role-arn != '' && inputs.aws-lambda-url != '' + uses: smartcontractkit/.github/actions/setup-github-token@ef78fa97bf3c77de6563db1175422703e9e6674f # setup-github-token@0.2.1 + with: + aws-role-arn: ${{ inputs.aws-role-arn }} + aws-lambda-url: ${{ inputs.aws-lambda-url }} + aws-region: ${{ inputs.aws-region }} + aws-role-duration-seconds: ${{ inputs.aws-role-duration-seconds }} + role-session-name: ${{ inputs.role-session-name }} + set-git-config: ${{ inputs.set-git-config }} diff --git a/.github/workflows/golangci-lint.yaml b/.github/workflows/golangci-lint.yaml index f9b29a572..43ef0b85e 100644 --- a/.github/workflows/golangci-lint.yaml +++ b/.github/workflows/golangci-lint.yaml @@ -18,7 +18,7 @@ jobs: steps: - name: Setup GitHub Token id: setup-github-token - uses: smartcontractkit/.github/actions/setup-github-token@ef78fa97bf3c77de6563db1175422703e9e6674f # setup-github-token@0.2.1 + uses: ./.github/actions/setup-github-token with: aws-role-arn: ${{ secrets.GATI_AWS_ROLE_ARN_CHAINLINK_READ_ONLY }} aws-lambda-url: ${{ secrets.GATI_LAMBDA_URL_RELENG }} diff --git a/.github/workflows/repo-hygiene.yaml b/.github/workflows/repo-hygiene.yaml index 533578eed..7ebd7ae95 100644 --- a/.github/workflows/repo-hygiene.yaml +++ b/.github/workflows/repo-hygiene.yaml @@ -16,7 +16,7 @@ jobs: steps: - name: Setup GitHub Token id: setup-github-token - uses: smartcontractkit/.github/actions/setup-github-token@ef78fa97bf3c77de6563db1175422703e9e6674f # setup-github-token@0.2.1 + uses: ./.github/actions/setup-github-token with: aws-role-arn: ${{ secrets.GATI_AWS_ROLE_ARN_CHAINLINK_READ_ONLY }} aws-lambda-url: ${{ secrets.GATI_LAMBDA_URL_RELENG }} diff --git a/.github/workflows/test-cl-smoke.yaml b/.github/workflows/test-cl-smoke.yaml index bc3ac1aba..ec3602863 100644 --- a/.github/workflows/test-cl-smoke.yaml +++ b/.github/workflows/test-cl-smoke.yaml @@ -65,7 +65,7 @@ jobs: - name: Setup GitHub Token id: setup-github-token - uses: smartcontractkit/.github/actions/setup-github-token@ef78fa97bf3c77de6563db1175422703e9e6674f # setup-github-token@0.2.1 + uses: ./.github/actions/setup-github-token with: aws-role-arn: ${{ secrets.GATI_AWS_ROLE_ARN_CHAINLINK_READ_ONLY }} aws-lambda-url: ${{ secrets.GATI_LAMBDA_URL_RELENG }} @@ -97,13 +97,30 @@ jobs: id-token: write contents: read runs-on: runs-on=${{ github.run_id }}/family=c6i/cpu=32+48/ram=64+96/spot=false/image=ubuntu24-full-x64/extras=s3-cache+tmpfs + outputs: + # E2E jobs need ECR + JD secrets, which Dependabot and fork PR runs don't get. + e2e_runnable: ${{ steps.detect-secrets.outputs.e2e_runnable }} steps: - name: Enable S3 Cache for Self-Hosted Runners uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # v2.0.3 + - name: Detect CI secrets + id: detect-secrets + env: + CCV_IAM_ROLE: ${{ secrets.CCV_IAM_ROLE }} + JD_REGISTRY: ${{ secrets.JD_REGISTRY }} + JD_IMAGE: ${{ secrets.JD_IMAGE }} + run: | + if [[ -n "$CCV_IAM_ROLE" && -n "$JD_REGISTRY" && -n "$JD_IMAGE" ]]; then + echo "e2e_runnable=true" >> "$GITHUB_OUTPUT" + else + echo "e2e_runnable=false" >> "$GITHUB_OUTPUT" + echo "CI secrets unavailable; e2e jobs will be skipped." + fi + - name: Setup GitHub Token id: setup-github-token - uses: smartcontractkit/.github/actions/setup-github-token@ef78fa97bf3c77de6563db1175422703e9e6674f # setup-github-token@0.2.1 + uses: ./.github/actions/setup-github-token with: aws-role-arn: ${{ secrets.GATI_AWS_ROLE_ARN_CHAINLINK_READ_ONLY }} aws-lambda-url: ${{ secrets.GATI_LAMBDA_URL_RELENG }} @@ -154,7 +171,7 @@ jobs: - name: Setup GitHub Token id: setup-github-token - uses: smartcontractkit/.github/actions/setup-github-token@ef78fa97bf3c77de6563db1175422703e9e6674f # setup-github-token@0.2.1 + uses: ./.github/actions/setup-github-token with: aws-role-arn: ${{ secrets.GATI_AWS_ROLE_ARN_CHAINLINK_READ_ONLY }} aws-lambda-url: ${{ secrets.GATI_LAMBDA_URL_RELENG }} @@ -186,6 +203,8 @@ jobs: e2e-smoke-cl-mode: name: ${{ matrix.test.name }} needs: [build-cl-image, build-docker-images, build-ccv-cli] + # Skipped on secretless runs (Dependabot/fork PRs); the merge queue runs the full suite. + if: needs.build-docker-images.outputs.e2e_runnable == 'true' permissions: id-token: write contents: read @@ -244,7 +263,7 @@ jobs: - name: Setup GitHub Token id: setup-github-token - uses: smartcontractkit/.github/actions/setup-github-token@ef78fa97bf3c77de6563db1175422703e9e6674f # setup-github-token@0.2.1 + uses: ./.github/actions/setup-github-token with: aws-role-arn: ${{ secrets.GATI_AWS_ROLE_ARN_CHAINLINK_READ_ONLY }} aws-lambda-url: ${{ secrets.GATI_LAMBDA_URL_RELENG }} @@ -359,6 +378,8 @@ jobs: e2e-load-pr: needs: [build-cl-image, build-docker-images] + # Skipped on secretless runs (Dependabot/fork PRs); the merge queue runs the full suite. + if: needs.build-docker-images.outputs.e2e_runnable == 'true' permissions: id-token: write contents: read @@ -376,7 +397,7 @@ jobs: - name: Setup GitHub Token id: setup-github-token - uses: smartcontractkit/.github/actions/setup-github-token@ef78fa97bf3c77de6563db1175422703e9e6674f # setup-github-token@0.2.1 + uses: ./.github/actions/setup-github-token with: aws-role-arn: ${{ secrets.GATI_AWS_ROLE_ARN_CHAINLINK_READ_ONLY }} aws-lambda-url: ${{ secrets.GATI_LAMBDA_URL_RELENG }} diff --git a/.github/workflows/test-coverage-report.yaml b/.github/workflows/test-coverage-report.yaml index 92c4f4450..b15bf609d 100644 --- a/.github/workflows/test-coverage-report.yaml +++ b/.github/workflows/test-coverage-report.yaml @@ -66,9 +66,12 @@ jobs: cat table.txt echo 'COVERAGE_REPORT_DELIM' } >> "$GITHUB_ENV" + # Dependabot PR runs get a read-only GITHUB_TOKEN that cannot write PR comments; + # the comment is best-effort so coverage results still gate the job. - name: Remove previous coverage comments uses: actions/github-script@v6 if: github.event_name == 'pull_request' + continue-on-error: true with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | @@ -91,6 +94,7 @@ jobs: - name: Display coverage in PR comment uses: actions/github-script@v6 if: github.event_name == 'pull_request' + continue-on-error: true with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/test-deployment-module.yaml b/.github/workflows/test-deployment-module.yaml index 1846675c3..21760a0ec 100644 --- a/.github/workflows/test-deployment-module.yaml +++ b/.github/workflows/test-deployment-module.yaml @@ -51,7 +51,7 @@ jobs: - name: Setup GitHub Token if: steps.changes.outputs.changed == 'true' id: setup-github-token - uses: smartcontractkit/.github/actions/setup-github-token@ef78fa97bf3c77de6563db1175422703e9e6674f # setup-github-token@0.2.1 + uses: ./.github/actions/setup-github-token with: aws-role-arn: ${{ secrets.GATI_AWS_ROLE_ARN_CHAINLINK_READ_ONLY }} aws-lambda-url: ${{ secrets.GATI_LAMBDA_URL_RELENG }} diff --git a/.github/workflows/test-devenv-module.yaml b/.github/workflows/test-devenv-module.yaml index 58c0450ee..c49351aae 100644 --- a/.github/workflows/test-devenv-module.yaml +++ b/.github/workflows/test-devenv-module.yaml @@ -51,7 +51,7 @@ jobs: - name: Setup GitHub Token if: steps.changes.outputs.changed == 'true' id: setup-github-token - uses: smartcontractkit/.github/actions/setup-github-token@ef78fa97bf3c77de6563db1175422703e9e6674f # setup-github-token@0.2.1 + uses: ./.github/actions/setup-github-token with: aws-role-arn: ${{ secrets.GATI_AWS_ROLE_ARN_CHAINLINK_READ_ONLY }} aws-lambda-url: ${{ secrets.GATI_LAMBDA_URL_RELENG }} diff --git a/.github/workflows/test-evm-integration-module.yaml b/.github/workflows/test-evm-integration-module.yaml index b1aed8c23..3dd9436c2 100644 --- a/.github/workflows/test-evm-integration-module.yaml +++ b/.github/workflows/test-evm-integration-module.yaml @@ -50,7 +50,7 @@ jobs: - name: Setup GitHub Token if: steps.changes.outputs.changed == 'true' id: setup-github-token - uses: smartcontractkit/.github/actions/setup-github-token@ef78fa97bf3c77de6563db1175422703e9e6674f # setup-github-token@0.2.1 + uses: ./.github/actions/setup-github-token with: aws-role-arn: ${{ secrets.GATI_AWS_ROLE_ARN_CHAINLINK_READ_ONLY }} aws-lambda-url: ${{ secrets.GATI_LAMBDA_URL_RELENG }} diff --git a/.github/workflows/test-services.yaml b/.github/workflows/test-services.yaml index 5231d153f..5a9a530f7 100644 --- a/.github/workflows/test-services.yaml +++ b/.github/workflows/test-services.yaml @@ -55,7 +55,7 @@ jobs: - name: Setup GitHub Token if: steps.changes.outputs.changed == 'true' id: setup-github-token - uses: smartcontractkit/.github/actions/setup-github-token@ef78fa97bf3c77de6563db1175422703e9e6674f # setup-github-token@0.2.1 + uses: ./.github/actions/setup-github-token with: aws-role-arn: ${{ secrets.GATI_AWS_ROLE_ARN_CHAINLINK_READ_ONLY }} aws-lambda-url: ${{ secrets.GATI_LAMBDA_URL_RELENG }} diff --git a/.github/workflows/test-smoke.yaml b/.github/workflows/test-smoke.yaml index d812bf59d..ffff44664 100644 --- a/.github/workflows/test-smoke.yaml +++ b/.github/workflows/test-smoke.yaml @@ -18,13 +18,30 @@ jobs: id-token: write contents: read runs-on: runs-on=${{ github.run_id }}/family=c6i/cpu=32+48/ram=64+96/spot=false/image=ubuntu24-full-x64/extras=s3-cache+tmpfs + outputs: + # E2E jobs need ECR + JD secrets, which Dependabot and fork PR runs don't get. + e2e_runnable: ${{ steps.detect-secrets.outputs.e2e_runnable }} steps: - name: Enable S3 Cache for Self-Hosted Runners uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # v2.0.3 + - name: Detect CI secrets + id: detect-secrets + env: + CCV_IAM_ROLE: ${{ secrets.CCV_IAM_ROLE }} + JD_REGISTRY: ${{ secrets.JD_REGISTRY }} + JD_IMAGE: ${{ secrets.JD_IMAGE }} + run: | + if [[ -n "$CCV_IAM_ROLE" && -n "$JD_REGISTRY" && -n "$JD_IMAGE" ]]; then + echo "e2e_runnable=true" >> "$GITHUB_OUTPUT" + else + echo "e2e_runnable=false" >> "$GITHUB_OUTPUT" + echo "CI secrets unavailable; e2e-smoke jobs will be skipped." + fi + - name: Setup GitHub Token id: setup-github-token - uses: smartcontractkit/.github/actions/setup-github-token@ef78fa97bf3c77de6563db1175422703e9e6674f # setup-github-token@0.2.1 + uses: ./.github/actions/setup-github-token with: aws-role-arn: ${{ secrets.GATI_AWS_ROLE_ARN_CHAINLINK_READ_ONLY }} aws-lambda-url: ${{ secrets.GATI_LAMBDA_URL_RELENG }} @@ -73,7 +90,7 @@ jobs: - name: Setup GitHub Token id: setup-github-token - uses: smartcontractkit/.github/actions/setup-github-token@ef78fa97bf3c77de6563db1175422703e9e6674f # setup-github-token@0.2.1 + uses: ./.github/actions/setup-github-token with: aws-role-arn: ${{ secrets.GATI_AWS_ROLE_ARN_CHAINLINK_READ_ONLY }} aws-lambda-url: ${{ secrets.GATI_LAMBDA_URL_RELENG }} @@ -105,6 +122,8 @@ jobs: e2e-smoke: name: ${{ matrix.test.name }} needs: [build-docker-images, build-ccv-cli] + # Skipped on secretless runs (Dependabot/fork PRs); the merge queue runs the full suite. + if: needs.build-docker-images.outputs.e2e_runnable == 'true' permissions: id-token: write contents: read @@ -214,7 +233,7 @@ jobs: - name: Setup GitHub Token id: setup-github-token - uses: smartcontractkit/.github/actions/setup-github-token@ef78fa97bf3c77de6563db1175422703e9e6674f # setup-github-token@0.2.1 + uses: ./.github/actions/setup-github-token with: aws-role-arn: ${{ secrets.GATI_AWS_ROLE_ARN_CHAINLINK_READ_ONLY }} aws-lambda-url: ${{ secrets.GATI_LAMBDA_URL_RELENG }} From 1e84acdbbae8660183057fd7edfca6f87115160b Mon Sep 17 00:00:00 2001 From: Terry Tata Date: Mon, 5 Oct 2026 16:10:46 -0700 Subject: [PATCH 2/4] fix checkout --- .github/workflows/golangci-lint.yaml | 11 +++--- .github/workflows/repo-hygiene.yaml | 11 +++--- .github/workflows/test-cl-smoke.yaml | 51 +++++++++++++++------------- .github/workflows/test-smoke.yaml | 29 +++++++++------- 4 files changed, 56 insertions(+), 46 deletions(-) diff --git a/.github/workflows/golangci-lint.yaml b/.github/workflows/golangci-lint.yaml index 43ef0b85e..d779e9fb9 100644 --- a/.github/workflows/golangci-lint.yaml +++ b/.github/workflows/golangci-lint.yaml @@ -16,6 +16,12 @@ jobs: id-token: write contents: read steps: + # Local actions need the repo on disk, so checkout must precede setup-github-token. + - name: Checkout code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + fetch-depth: 0 + - name: Setup GitHub Token id: setup-github-token uses: ./.github/actions/setup-github-token @@ -25,11 +31,6 @@ jobs: aws-region: ${{ secrets.GATI_AWS_REGION }} set-git-config: true - - name: Checkout code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - fetch-depth: 0 - - name: Set up Go uses: actions/setup-go@v6 # v6 env: diff --git a/.github/workflows/repo-hygiene.yaml b/.github/workflows/repo-hygiene.yaml index 7ebd7ae95..f20740839 100644 --- a/.github/workflows/repo-hygiene.yaml +++ b/.github/workflows/repo-hygiene.yaml @@ -14,6 +14,12 @@ jobs: id-token: write contents: read steps: + # Local actions need the repo on disk, so checkout must precede setup-github-token. + - name: Checkout code + uses: actions/checkout@v5 + with: + fetch-depth: 0 + - name: Setup GitHub Token id: setup-github-token uses: ./.github/actions/setup-github-token @@ -23,11 +29,6 @@ jobs: aws-region: ${{ secrets.GATI_AWS_REGION }} set-git-config: true - - name: Checkout code - uses: actions/checkout@v5 - with: - fetch-depth: 0 - - name: Set up Go uses: actions/setup-go@v6 # v6 env: diff --git a/.github/workflows/test-cl-smoke.yaml b/.github/workflows/test-cl-smoke.yaml index ec3602863..4d0f5c344 100644 --- a/.github/workflows/test-cl-smoke.yaml +++ b/.github/workflows/test-cl-smoke.yaml @@ -63,6 +63,12 @@ jobs: - name: Enable S3 Cache for Self-Hosted Runners uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # v2.0.3 + # Local actions need the repo on disk, so checkout must precede the token setup. + - name: Checkout code + uses: actions/checkout@v5 + with: + fetch-depth: 0 + - name: Setup GitHub Token id: setup-github-token uses: ./.github/actions/setup-github-token @@ -72,11 +78,6 @@ jobs: aws-region: ${{ secrets.GATI_AWS_REGION }} set-git-config: true - - name: Checkout code - uses: actions/checkout@v5 - with: - fetch-depth: 0 - - name: Build CL Image For Ref uses: ./.github/actions/build-cl @@ -104,6 +105,12 @@ jobs: - name: Enable S3 Cache for Self-Hosted Runners uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # v2.0.3 + # Local actions need the repo on disk, so checkout must precede the token setup. + - name: Checkout code + uses: actions/checkout@v5 + with: + fetch-depth: 0 + - name: Detect CI secrets id: detect-secrets env: @@ -127,11 +134,6 @@ jobs: aws-region: ${{ secrets.GATI_AWS_REGION }} set-git-config: true - - name: Checkout code - uses: actions/checkout@v5 - with: - fetch-depth: 0 - - name: Build devenv Docker images uses: ./.github/actions/build-devenv-docker with: @@ -169,6 +171,10 @@ jobs: - name: Enable S3 Cache for Self-Hosted Runners uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # v2.0.3 + # Local actions need the repo on disk, so checkout must precede the token setup. + - name: Checkout code + uses: actions/checkout@v5 + - name: Setup GitHub Token id: setup-github-token uses: ./.github/actions/setup-github-token @@ -178,9 +184,6 @@ jobs: aws-region: ${{ secrets.GATI_AWS_REGION }} set-git-config: true - - name: Checkout code - uses: actions/checkout@v5 - # Keep this setup-go config identical to the e2e matrix jobs so it restores # the same (~1GB) build cache. The cache key is derived from # cache-dependency-path, so it must point at build/devenv/go.sum (not the @@ -261,6 +264,12 @@ jobs: - name: Enable S3 Cache for Self-Hosted Runners uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # v2.0.3 + # Local actions need the repo on disk, so checkout must precede the token setup. + - name: Checkout code + uses: actions/checkout@v5 + with: + fetch-depth: 0 + - name: Setup GitHub Token id: setup-github-token uses: ./.github/actions/setup-github-token @@ -270,11 +279,6 @@ jobs: aws-region: ${{ secrets.GATI_AWS_REGION }} set-git-config: true - - name: Checkout code - uses: actions/checkout@v5 - with: - fetch-depth: 0 - - name: Download Docker Image uses: actions/download-artifact@v4 with: @@ -395,6 +399,12 @@ jobs: - name: Enable S3 Cache for Self-Hosted Runners uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # v2.0.3 + # Local actions need the repo on disk, so checkout must precede the token setup. + - name: Checkout code + uses: actions/checkout@v5 + with: + fetch-depth: 0 + - name: Setup GitHub Token id: setup-github-token uses: ./.github/actions/setup-github-token @@ -404,11 +414,6 @@ jobs: aws-region: ${{ secrets.GATI_AWS_REGION }} set-git-config: true - - name: Checkout code - uses: actions/checkout@v5 - with: - fetch-depth: 0 - - name: Download Docker Image uses: actions/download-artifact@v4 with: diff --git a/.github/workflows/test-smoke.yaml b/.github/workflows/test-smoke.yaml index ffff44664..9e17c2b38 100644 --- a/.github/workflows/test-smoke.yaml +++ b/.github/workflows/test-smoke.yaml @@ -25,6 +25,12 @@ jobs: - name: Enable S3 Cache for Self-Hosted Runners uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # v2.0.3 + # Local actions need the repo on disk, so checkout must precede the token setup. + - name: Checkout code + uses: actions/checkout@v5 + with: + fetch-depth: 0 + - name: Detect CI secrets id: detect-secrets env: @@ -48,11 +54,6 @@ jobs: aws-region: ${{ secrets.GATI_AWS_REGION }} set-git-config: true - - name: Checkout code - uses: actions/checkout@v5 - with: - fetch-depth: 0 - - name: Build devenv Docker images uses: ./.github/actions/build-devenv-docker with: @@ -88,6 +89,10 @@ jobs: - name: Enable S3 Cache for Self-Hosted Runners uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # v2.0.3 + # Local actions need the repo on disk, so checkout must precede the token setup. + - name: Checkout code + uses: actions/checkout@v5 + - name: Setup GitHub Token id: setup-github-token uses: ./.github/actions/setup-github-token @@ -97,9 +102,6 @@ jobs: aws-region: ${{ secrets.GATI_AWS_REGION }} set-git-config: true - - name: Checkout code - uses: actions/checkout@v5 - # Keep this setup-go config identical to the e2e matrix jobs so it restores # the same (~1GB) build cache. The cache key is derived from # cache-dependency-path, so it must point at build/devenv/go.sum (not the @@ -231,6 +233,12 @@ jobs: - name: Enable S3 Cache for Self-Hosted Runners uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # v2.0.3 + # Local actions need the repo on disk, so checkout must precede the token setup. + - name: Checkout code + uses: actions/checkout@v5 + with: + fetch-depth: 0 + - name: Setup GitHub Token id: setup-github-token uses: ./.github/actions/setup-github-token @@ -240,11 +248,6 @@ jobs: aws-region: ${{ secrets.GATI_AWS_REGION }} set-git-config: true - - name: Checkout code - uses: actions/checkout@v5 - with: - fetch-depth: 0 - - name: Download devenv Docker Images uses: actions/download-artifact@v4 with: From 2b082deebc87c947c704be3adcbae45ffc0e9540 Mon Sep 17 00:00:00 2001 From: Terry Tata Date: Mon, 5 Oct 2026 16:34:48 -0700 Subject: [PATCH 3/4] review comments --- .github/actions/aws-ecr-auth/action.yaml | 34 ++++++++++++++---- .../actions/build-devenv-docker/action.yaml | 31 ++++++++++++---- .github/actions/run-load-test/action.yaml | 15 ++++---- .../actions/setup-github-token/action.yaml | 35 +++++++++++++++---- .github/workflows/test-cl-smoke.yaml | 9 +++-- .github/workflows/test-services.yaml | 3 ++ .github/workflows/test-smoke.yaml | 9 +++-- 7 files changed, 103 insertions(+), 33 deletions(-) diff --git a/.github/actions/aws-ecr-auth/action.yaml b/.github/actions/aws-ecr-auth/action.yaml index 5fe4a1bc3..c30013a4f 100644 --- a/.github/actions/aws-ecr-auth/action.yaml +++ b/.github/actions/aws-ecr-auth/action.yaml @@ -1,12 +1,15 @@ name: 'AWS ECR Authentication' description: 'Configure AWS credentials and authenticate to ECR Public' inputs: - # An empty role (no repo secrets, e.g. Dependabot PR runs) skips auth entirely; - # callers must then skip any step that pulls from ECR. role-to-assume: - description: 'IAM role to assume. Empty skips authentication.' + description: 'IAM role to assume' + required: true + # Fail-closed by default: an empty role fails the job unless the caller explicitly + # opts in; only secretless Dependabot/fork PR runs are allowed to skip. + skip-when-missing-role: + description: 'Skip authentication when role-to-assume is empty (secretless Dependabot/fork PR runs only).' required: false - default: '' + default: 'false' aws-region: description: 'AWS region' required: true @@ -22,16 +25,33 @@ inputs: runs: using: "composite" steps: + - name: Validate role input + id: validate + shell: bash + env: + ROLE_TO_ASSUME: ${{ inputs.role-to-assume }} + SKIP_WHEN_MISSING: ${{ inputs.skip-when-missing-role }} + run: | + if [[ -n "$ROLE_TO_ASSUME" ]]; then + echo "auth=true" >> "$GITHUB_OUTPUT" + elif [[ "$SKIP_WHEN_MISSING" == "true" ]]; then + echo "auth=false" >> "$GITHUB_OUTPUT" + echo "role-to-assume empty with skip-when-missing-role=true; skipping ECR authentication." + else + echo "::error::role-to-assume is empty (missing or renamed secret?); failing closed. Pass skip-when-missing-role=true only for secretless Dependabot/fork PR runs." + exit 1 + fi + - name: Configure AWS credentials using OIDC - if: inputs.role-to-assume != '' + if: steps.validate.outputs.auth == 'true' uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 with: role-to-assume: ${{ inputs.role-to-assume }} aws-region: ${{ inputs.aws-region }} - name: Authenticate to ECR id: login-ecr - if: inputs.role-to-assume != '' + if: steps.validate.outputs.auth == 'true' uses: aws-actions/amazon-ecr-login@062b18b96a7aff071d4dc91bc00c4c1a7945b076 # v2.0.1 with: registry-type: ${{ inputs.registry-type }} - registries: ${{ inputs.registries }} \ No newline at end of file + registries: ${{ inputs.registries }} diff --git a/.github/actions/build-devenv-docker/action.yaml b/.github/actions/build-devenv-docker/action.yaml index a26fb0f23..4a5911fad 100644 --- a/.github/actions/build-devenv-docker/action.yaml +++ b/.github/actions/build-devenv-docker/action.yaml @@ -3,19 +3,34 @@ description: Build CCV service images via just build-docker-ci inputs: ccv-iam-role: - # Empty on secretless runs (Dependabot PRs); the ECR auth steps then self-skip, - # which is fine because these builds pull only public base images. - description: 'AWS IAM role for CCV. Empty skips ECR authentication.' - required: false - default: '' + description: 'AWS IAM role for CCV' + required: true jd-registry: description: 'JD registry ID' - required: false - default: '' + required: true runs: using: composite steps: + - name: Validate ECR inputs + id: validate + shell: bash + env: + CCV_IAM_ROLE: ${{ inputs.ccv-iam-role }} + JD_REGISTRY: ${{ inputs.jd-registry }} + # Dependabot and fork PR runs get no repo secrets; these builds pull only public base images. + SECRETLESS_RUN: ${{ github.event_name == 'pull_request' && (github.actor == 'dependabot[bot]' || github.event.pull_request.head.repo.fork == true) }} + run: | + if [[ -n "$CCV_IAM_ROLE" && -n "$JD_REGISTRY" ]]; then + echo "auth=true" >> "$GITHUB_OUTPUT" + elif [[ -z "$CCV_IAM_ROLE" && -z "$JD_REGISTRY" && "$SECRETLESS_RUN" == "true" ]]; then + echo "auth=false" >> "$GITHUB_OUTPUT" + echo "Dependabot/fork PR without repo secrets; skipping ECR authentication (builds pull only public base images)." + else + echo "::error::ECR inputs incomplete (ccv-iam-role/jd-registry); failing closed so auth cannot silently degrade." + exit 1 + fi + - name: Set up Docker Buildx uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 @@ -25,6 +40,7 @@ runs: just-version: '1.40.0' - name: Authenticate to AWS ECR + if: steps.validate.outputs.auth == 'true' uses: ./.github/actions/aws-ecr-auth with: role-to-assume: ${{ inputs.ccv-iam-role }} @@ -32,6 +48,7 @@ runs: registry-type: public - name: Authenticate to AWS ECR (JD) + if: steps.validate.outputs.auth == 'true' uses: ./.github/actions/aws-ecr-auth with: role-to-assume: ${{ inputs.ccv-iam-role }} diff --git a/.github/actions/run-load-test/action.yaml b/.github/actions/run-load-test/action.yaml index b3d6d0d2c..f549494ed 100644 --- a/.github/actions/run-load-test/action.yaml +++ b/.github/actions/run-load-test/action.yaml @@ -9,17 +9,14 @@ inputs: description: 'Test timeout duration' required: true ccv-iam-role: - description: 'AWS IAM role for CCV. Empty skips ECR authentication.' - required: false - default: '' + description: 'AWS IAM role for CCV' + required: true jd-registry: - description: 'JD registry ID. Empty skips the private ECR login.' - required: false - default: '' + description: 'JD registry ID' + required: true jd-image: - description: 'JD Docker image. Empty (secretless runs) fails the load test; gate those jobs instead.' - required: false - default: '' + description: 'JD Docker image' + required: true env_name: description: 'Environment name for CCV' required: false diff --git a/.github/actions/setup-github-token/action.yaml b/.github/actions/setup-github-token/action.yaml index 27c2057fc..915e3fb55 100644 --- a/.github/actions/setup-github-token/action.yaml +++ b/.github/actions/setup-github-token/action.yaml @@ -1,9 +1,9 @@ name: Setup GitHub Token description: >- - Calls smartcontractkit/.github's GATI token setup, or skips it when the GATI - secrets are unavailable. Dependabot and fork PR runs get no repo secrets, and - all module dependencies of these workflows are public, so the token is - optional there; the merge queue (merge_group) always runs with full secrets. + Calls smartcontractkit/.github's GATI token setup, or skips it when this is a + Dependabot/fork PR run with no repo secrets (all module dependencies here are + public). Any partial configuration, or missing secrets on a trusted run + (push, human PR, merge queue), fails closed so auth cannot silently degrade. inputs: aws-role-arn: @@ -39,10 +39,33 @@ outputs: runs: using: composite steps: - # Empty inputs mean the run has no repo secrets (Dependabot or fork PR), so skip GATI. + - name: Validate GATI inputs + id: validate + shell: bash + env: + AWS_ROLE_ARN: ${{ inputs.aws-role-arn }} + AWS_LAMBDA_URL: ${{ inputs.aws-lambda-url }} + AWS_REGION: ${{ inputs.aws-region }} + # Dependabot and fork PR runs get no repo secrets; every other run is trusted. + SECRETLESS_RUN: ${{ github.event_name == 'pull_request' && (github.actor == 'dependabot[bot]' || github.event.pull_request.head.repo.fork == true) }} + run: | + present=0 + if [[ -n "$AWS_ROLE_ARN" ]]; then present=$((present + 1)); fi + if [[ -n "$AWS_LAMBDA_URL" ]]; then present=$((present + 1)); fi + if [[ -n "$AWS_REGION" ]]; then present=$((present + 1)); fi + if [[ "$present" -eq 3 ]]; then + echo "run=true" >> "$GITHUB_OUTPUT" + elif [[ "$present" -eq 0 && "$SECRETLESS_RUN" == "true" ]]; then + echo "run=false" >> "$GITHUB_OUTPUT" + echo "Dependabot/fork PR without repo secrets; skipping GATI token setup." + else + echo "::error::GATI inputs incomplete (${present}/3 set); failing closed so auth cannot silently degrade." + exit 1 + fi + - name: Setup GitHub Token id: gati - if: inputs.aws-region != '' && inputs.aws-role-arn != '' && inputs.aws-lambda-url != '' + if: steps.validate.outputs.run == 'true' uses: smartcontractkit/.github/actions/setup-github-token@ef78fa97bf3c77de6563db1175422703e9e6674f # setup-github-token@0.2.1 with: aws-role-arn: ${{ inputs.aws-role-arn }} diff --git a/.github/workflows/test-cl-smoke.yaml b/.github/workflows/test-cl-smoke.yaml index 4d0f5c344..ab16bacd4 100644 --- a/.github/workflows/test-cl-smoke.yaml +++ b/.github/workflows/test-cl-smoke.yaml @@ -117,12 +117,17 @@ jobs: CCV_IAM_ROLE: ${{ secrets.CCV_IAM_ROLE }} JD_REGISTRY: ${{ secrets.JD_REGISTRY }} JD_IMAGE: ${{ secrets.JD_IMAGE }} + # Dependabot and fork PR runs get no repo secrets; every other run is trusted. + SECRETLESS_RUN: ${{ github.event_name == 'pull_request' && (github.actor == 'dependabot[bot]' || github.event.pull_request.head.repo.fork == true) }} run: | if [[ -n "$CCV_IAM_ROLE" && -n "$JD_REGISTRY" && -n "$JD_IMAGE" ]]; then echo "e2e_runnable=true" >> "$GITHUB_OUTPUT" - else + elif [[ -z "$CCV_IAM_ROLE" && -z "$JD_REGISTRY" && -z "$JD_IMAGE" && "$SECRETLESS_RUN" == "true" ]]; then echo "e2e_runnable=false" >> "$GITHUB_OUTPUT" - echo "CI secrets unavailable; e2e jobs will be skipped." + echo "Dependabot/fork PR without repo secrets; e2e jobs will be skipped (the merge queue runs the full suite)." + else + echo "::error::CI secrets incomplete (CCV_IAM_ROLE/JD_REGISTRY/JD_IMAGE); failing closed instead of silently skipping e2e." + exit 1 fi - name: Setup GitHub Token diff --git a/.github/workflows/test-services.yaml b/.github/workflows/test-services.yaml index 5a9a530f7..622f7afc1 100644 --- a/.github/workflows/test-services.yaml +++ b/.github/workflows/test-services.yaml @@ -77,6 +77,9 @@ jobs: uses: ./.github/actions/aws-ecr-auth with: role-to-assume: ${{ secrets.CCV_IAM_ROLE }} + # Services tests use only locally built images plus docker hub/ghcr pulls, + # so secretless Dependabot/fork PR runs may skip ECR authentication. + skip-when-missing-role: ${{ github.event_name == 'pull_request' && (github.actor == 'dependabot[bot]' || github.event.pull_request.head.repo.fork == true) }} aws-region: us-east-1 registry-type: public diff --git a/.github/workflows/test-smoke.yaml b/.github/workflows/test-smoke.yaml index 9e17c2b38..0518c401f 100644 --- a/.github/workflows/test-smoke.yaml +++ b/.github/workflows/test-smoke.yaml @@ -37,12 +37,17 @@ jobs: CCV_IAM_ROLE: ${{ secrets.CCV_IAM_ROLE }} JD_REGISTRY: ${{ secrets.JD_REGISTRY }} JD_IMAGE: ${{ secrets.JD_IMAGE }} + # Dependabot and fork PR runs get no repo secrets; every other run is trusted. + SECRETLESS_RUN: ${{ github.event_name == 'pull_request' && (github.actor == 'dependabot[bot]' || github.event.pull_request.head.repo.fork == true) }} run: | if [[ -n "$CCV_IAM_ROLE" && -n "$JD_REGISTRY" && -n "$JD_IMAGE" ]]; then echo "e2e_runnable=true" >> "$GITHUB_OUTPUT" - else + elif [[ -z "$CCV_IAM_ROLE" && -z "$JD_REGISTRY" && -z "$JD_IMAGE" && "$SECRETLESS_RUN" == "true" ]]; then echo "e2e_runnable=false" >> "$GITHUB_OUTPUT" - echo "CI secrets unavailable; e2e-smoke jobs will be skipped." + echo "Dependabot/fork PR without repo secrets; e2e-smoke jobs will be skipped (the merge queue runs the full suite)." + else + echo "::error::CI secrets incomplete (CCV_IAM_ROLE/JD_REGISTRY/JD_IMAGE); failing closed instead of silently skipping e2e." + exit 1 fi - name: Setup GitHub Token From c73dddcd0f6d2fad00007da0252ed96c0f69304d Mon Sep 17 00:00:00 2001 From: Terry Tata Date: Tue, 6 Oct 2026 11:09:55 -0700 Subject: [PATCH 4/4] wip --- .github/workflows/test-cl-smoke.yaml | 9 ++++++--- .github/workflows/test-coverage-report.yaml | 2 ++ .github/workflows/test-coverage.yaml | 2 ++ .github/workflows/test-smoke.yaml | 4 ++++ 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-cl-smoke.yaml b/.github/workflows/test-cl-smoke.yaml index ab16bacd4..57391cf70 100644 --- a/.github/workflows/test-cl-smoke.yaml +++ b/.github/workflows/test-cl-smoke.yaml @@ -54,7 +54,8 @@ jobs: build-cl-image: needs: [check-changes] - if: needs.check-changes.outputs.run_tests == 'true' + # Fork PRs skip these billable runs-on jobs; free GitHub-hosted jobs still run for feedback. + if: needs.check-changes.outputs.run_tests == 'true' && (github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork) permissions: id-token: write contents: read @@ -93,7 +94,8 @@ jobs: build-docker-images: needs: [check-changes] - if: needs.check-changes.outputs.run_tests == 'true' + # Fork PRs skip these billable runs-on jobs; free GitHub-hosted jobs still run for feedback. + if: needs.check-changes.outputs.run_tests == 'true' && (github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork) permissions: id-token: write contents: read @@ -167,7 +169,8 @@ jobs: build-ccv-cli: name: Build ccv CLI needs: [check-changes] - if: needs.check-changes.outputs.run_tests == 'true' + # Fork PRs skip these billable runs-on jobs; free GitHub-hosted jobs still run for feedback. + if: needs.check-changes.outputs.run_tests == 'true' && (github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork) permissions: id-token: write contents: read diff --git a/.github/workflows/test-coverage-report.yaml b/.github/workflows/test-coverage-report.yaml index b15bf609d..f46e80a3b 100644 --- a/.github/workflows/test-coverage-report.yaml +++ b/.github/workflows/test-coverage-report.yaml @@ -9,6 +9,8 @@ on: jobs: test-coverage-report: + # Fork PRs skip this billable runs-on job; free GitHub-hosted jobs still run for feedback. + if: github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork runs-on: runs-on=${{ github.run_id }}/family=c6i/cpu=32+48/ram=64+96/spot=false/image=ubuntu24-full-x64/extras=s3-cache+tmpfs steps: - name: Checkout code diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml index 1c31d16c9..8b37d5eea 100644 --- a/.github/workflows/test-coverage.yaml +++ b/.github/workflows/test-coverage.yaml @@ -9,6 +9,8 @@ on: jobs: test-coverage: + # Fork PRs skip this billable runs-on job; free GitHub-hosted jobs still run for feedback. + if: github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork runs-on: runs-on=${{ github.run_id }}/family=c6i/cpu=32+48/ram=64+96/spot=false/image=ubuntu24-full-x64/extras=s3-cache+tmpfs env: COVERAGE_THRESHOLD: 37 diff --git a/.github/workflows/test-smoke.yaml b/.github/workflows/test-smoke.yaml index 0518c401f..35bf0963e 100644 --- a/.github/workflows/test-smoke.yaml +++ b/.github/workflows/test-smoke.yaml @@ -14,6 +14,8 @@ concurrency: jobs: build-docker-images: + # Fork PRs skip this billable runs-on job; free GitHub-hosted jobs still run for feedback. + if: github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork permissions: id-token: write contents: read @@ -86,6 +88,8 @@ jobs: build-ccv-cli: name: Build ccv CLI + # Fork PRs skip this billable runs-on job; free GitHub-hosted jobs still run for feedback. + if: github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork permissions: id-token: write contents: read