From 2416cdaa2fe458444da598aa2734d730531d8a55 Mon Sep 17 00:00:00 2001 From: Michael Grosse Huelsewiesche Date: Thu, 9 Jul 2026 18:04:04 -0400 Subject: [PATCH] Harden CI: Artifactory OIDC, fork-aware workflows, SHA-pinned actions - Add Artifactory OIDC composite action (sets GOPROXY to virtual-go-thirdparty) - Replace ci.yml: fork-aware runner selection, Go 1.22-1.24 matrix, SHA-pinned - Update e2e-tests.yml + publish-e2e-cli.yml: remove E2E_TESTS_TOKEN, fork-aware --- .github/actions/artifactory-oidc/action.yml | 65 ++++++++++++++++++ .github/workflows/ci.yml | 76 ++++++++++++++++++--- .github/workflows/e2e-tests.yml | 21 ++++-- .github/workflows/publish-e2e-cli.yml | 16 ++++- 4 files changed, 160 insertions(+), 18 deletions(-) create mode 100644 .github/actions/artifactory-oidc/action.yml diff --git a/.github/actions/artifactory-oidc/action.yml b/.github/actions/artifactory-oidc/action.yml new file mode 100644 index 0000000..342fc9f --- /dev/null +++ b/.github/actions/artifactory-oidc/action.yml @@ -0,0 +1,65 @@ +name: "Artifactory OIDC Auth" +description: "Exchange GitHub OIDC token for Artifactory access token and configure GOPROXY" + +inputs: + artifactory-url: + description: "Base Artifactory platform URL. Falls back to ARTIFACTORY_URL env var." + required: false + default: "" + oidc-provider-name: + description: "OIDC provider name configured in Artifactory" + required: false + default: "github-actions" + go-repo: + description: "Artifactory virtual Go repository name" + required: false + default: "virtual-go-thirdparty" + +runs: + using: "composite" + steps: + - name: Exchange GitHub OIDC token for Artifactory token + shell: bash + env: + INPUT_ARTIFACTORY_URL: ${{ inputs.artifactory-url }} + OIDC_PROVIDER_NAME: ${{ inputs.oidc-provider-name }} + GO_REPO: ${{ inputs.go-repo }} + run: | + set -euo pipefail + ARTIFACTORY_URL="${INPUT_ARTIFACTORY_URL:-${ARTIFACTORY_URL:-}}" + if [ -z "${ARTIFACTORY_URL}" ]; then + echo "::error::ARTIFACTORY_URL is not set (pass as input or set as env var)"; exit 1 + fi + + OIDC_JWT=$(curl -sS \ + "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=${ARTIFACTORY_URL}" \ + -H "Authorization: Bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" | jq -r '.value') + + if [ -z "$OIDC_JWT" ] || [ "$OIDC_JWT" = "null" ]; then + echo "::error::Failed to obtain GitHub OIDC token"; exit 1 + fi + + RESP=$(curl -sS "${ARTIFACTORY_URL}/access/api/v1/oidc/token" \ + -H 'Content-Type: application/json' \ + -d "{\"grant_type\":\"urn:ietf:params:oauth:grant-type:token-exchange\", + \"subject_token_type\":\"urn:ietf:params:oauth:token-type:id_token\", + \"subject_token\":\"${OIDC_JWT}\", + \"provider_name\":\"${OIDC_PROVIDER_NAME}\"}") + + ART_TOKEN=$(echo "$RESP" | jq -r '.access_token // empty') + + if [ -z "$ART_TOKEN" ]; then + echo "::error::OIDC token exchange failed." + echo "$RESP" | jq 'if .access_token then .access_token="" else . end' 2>/dev/null || echo "$RESP" + exit 1 + fi + echo "::add-mask::$ART_TOKEN" + + HOST=$(echo "${ARTIFACTORY_URL}" | sed -E 's#^https?://##') + GOPROXY_URL="https://:${ART_TOKEN}@${HOST}/artifactory/api/go/${GO_REPO},direct" + + echo "::add-mask::${GOPROXY_URL}" + echo "GOPROXY=${GOPROXY_URL}" >> "$GITHUB_ENV" + echo "GONOSUMDB=*" >> "$GITHUB_ENV" + echo "GONOSUMCHECK=*" >> "$GITHUB_ENV" + echo "Configured GOPROXY to resolve through Artifactory (${GO_REPO})" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5854c87..2d86ab2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,31 +6,63 @@ on: pull_request: branches: [v3.0] +permissions: + id-token: write + contents: read + +env: + ARTIFACTORY_URL: ${{ vars.ARTIFACTORY_URL }} + jobs: + vet: + name: Vet & Lint + runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || 'ubuntu-x64' }} + + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + + - name: Setup Go + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 + with: + go-version: "1.24" + + - name: Authenticate to Artifactory + if: ${{ !github.event.pull_request.head.repo.fork }} + uses: ./.github/actions/artifactory-oidc + + - name: Download dependencies + run: go mod download + + - name: Vet + run: go vet ./... + test: - runs-on: ubuntu-latest + name: Test (Go ${{ matrix.go-version }}) + runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || 'ubuntu-x64' }} strategy: fail-fast: false matrix: - go-version: ['1.21', '1.22', '1.23'] + go-version: ["1.22", "1.23", "1.24"] steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Setup Go ${{ matrix.go-version }} - uses: actions/setup-go@v5 + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 with: go-version: ${{ matrix.go-version }} - - name: Download dependencies - run: go get -v -t ./... + - name: Authenticate to Artifactory + if: ${{ !github.event.pull_request.head.repo.fork }} + uses: ./.github/actions/artifactory-oidc - - name: Vet - run: go vet ./... + - name: Download dependencies + run: go mod download - name: Test - run: go test -race -coverprofile=cover.out . + run: go test -race -coverprofile=cover.out ./... - name: Upload coverage uses: actions/upload-artifact@v4 @@ -38,3 +70,29 @@ jobs: name: coverage-go${{ matrix.go-version }} path: cover.out retention-days: 7 + + build: + name: Build Verification + runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || 'ubuntu-x64' }} + + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + + - name: Setup Go + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 + with: + go-version: "1.24" + + - name: Authenticate to Artifactory + if: ${{ !github.event.pull_request.head.repo.fork }} + uses: ./.github/actions/artifactory-oidc + + - name: Download dependencies + run: go mod download + + - name: Verify module + run: go mod verify + + - name: Build + run: go build ./... diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index d65d77b..6a7bdea 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -12,27 +12,33 @@ on: required: false default: 'main' +permissions: + id-token: write + contents: read + +env: + ARTIFACTORY_URL: ${{ vars.ARTIFACTORY_URL }} + jobs: e2e-tests: - if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} - runs-on: ubuntu-latest + if: ${{ !github.event.pull_request.head.repo.fork }} + runs-on: ubuntu-x64 steps: - name: Checkout SDK - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: path: sdk - name: Checkout sdk-e2e-tests - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: repository: segmentio/sdk-e2e-tests ref: ${{ inputs.e2e_tests_ref || 'main' }} - token: ${{ secrets.E2E_TESTS_TOKEN }} path: sdk-e2e-tests - name: Setup Go - uses: actions/setup-go@v5 + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 with: go-version-file: sdk/go.mod @@ -41,6 +47,9 @@ jobs: with: node-version: '20' + - name: Authenticate to Artifactory + uses: ./sdk/.github/actions/artifactory-oidc + - name: Build e2e-cli working-directory: sdk/e2e-cli run: go build -o e2e-cli-bin ./... diff --git a/.github/workflows/publish-e2e-cli.yml b/.github/workflows/publish-e2e-cli.yml index 9e9e590..11635ba 100644 --- a/.github/workflows/publish-e2e-cli.yml +++ b/.github/workflows/publish-e2e-cli.yml @@ -12,18 +12,28 @@ on: - cron: '0 0 1 * *' workflow_dispatch: +permissions: + id-token: write + contents: read + +env: + ARTIFACTORY_URL: ${{ vars.ARTIFACTORY_URL }} + jobs: publish: - runs-on: ubuntu-latest + runs-on: ubuntu-x64 steps: - name: Checkout SDK - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Setup Go - uses: actions/setup-go@v5 + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 with: go-version-file: go.mod + - name: Authenticate to Artifactory + uses: ./.github/actions/artifactory-oidc + - name: Build e2e-cli working-directory: e2e-cli run: go build -o e2e-cli-bin ./...