diff --git a/.github/workflows/project-status-sweep.yml b/.github/workflows/project-status-sweep.yml index 649c5dc9f..85bdcd39c 100644 --- a/.github/workflows/project-status-sweep.yml +++ b/.github/workflows/project-status-sweep.yml @@ -20,7 +20,13 @@ name: Project status sweep # Repository: Issues, Pull requests, Metadata read. No webhook. Install it # on every repo whose issues or PRs are on the board (today: extenddb). # 2. Environment "project-board", deployment branches: main only. -# In it: variable PROJECT_APP_CLIENT_ID and secret PROJECT_APP_PRIVATE_KEY. +# In it: variable PROJECT_APP_CLIENT_ID. No secret: the App's private key +# is in AWS Secrets Manager as JSON {"private_key": ""} and is read +# at run time through the OIDC role in the steps below, which trusts only +# this environment. Build that JSON with +# `jq -n --rawfile k app.pem '{private_key: $k}'`, which keeps the PEM's +# line breaks. To rotate the key, generate a new one for the App, store +# it in the secret, then delete the old key in the App's settings. # 3. Board workflows: keep "Item closed" and "Pull request merged" (they set # Done). Turn off every other workflow that sets Status; the sweep warns # while any is on. @@ -55,11 +61,14 @@ jobs: if: github.repository == 'ExtendDB/extenddb' runs-on: ubuntu-latest timeout-minutes: 10 - # Secrets live in this environment, which only main can use. + # The OIDC role trusts only this environment, which only main can use. # deployment: false keeps that, without a deployment record every run. environment: name: project-board deployment: false + permissions: + contents: read + id-token: write # OIDC role that reads the App key from Secrets Manager steps: - name: Check out sweep script uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -67,12 +76,27 @@ jobs: sparse-checkout: .github/scripts persist-credentials: false + - name: Assume the App-key role via OIDC + uses: aws-actions/configure-aws-credentials@e6de054238d6b7531b4efff3b6587d9aade6a06c # v6.2.3 + with: + role-to-assume: arn:aws:iam::975306274793:role/ExtendDBProjectBoardApp + role-session-name: extenddb-project-sweep-${{ github.run_id }} + role-duration-seconds: 900 # one secret read; the minimum session + aws-region: us-east-1 + + - name: Read the App private key from Secrets Manager + # Masked in the log, line by line as well as whole. + uses: aws-actions/aws-secretsmanager-get-secrets@2297f9a879480a9e3af9b293ed15c70caf8e1c88 # v3.0.2 + with: + secret-ids: PROJECT_APP,extenddb/project-board-app + parse-json-secrets: true + - name: Mint App token id: app-token uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0 with: client-id: ${{ vars.PROJECT_APP_CLIENT_ID }} - private-key: ${{ secrets.PROJECT_APP_PRIVATE_KEY }} + private-key: ${{ env.PROJECT_APP_PRIVATE_KEY }} # No repositories list: the token covers the repos the App is # installed on, so cards from a newly added repo work once it is. owner: ExtendDB @@ -80,6 +104,22 @@ jobs: permission-issues: read permission-pull-requests: read + - name: Drop the App key and the AWS credentials from the job environment + # Both are exported for every later step. The sweep needs only the + # one-hour installation token, so every variable the secrets action + # exported (it lists them in SECRETS_LIST_CLEAN_UP) and the credentials + # that can read the secret are cleared before the sweep script runs. + # A later step can still request an OIDC token; the sweep script is + # under the same code-owner review as this file. + run: | + set -euo pipefail + { + jq -r '.[] | . + "="' <<< "${SECRETS_LIST_CLEAN_UP:-[]}" + echo "AWS_ACCESS_KEY_ID=" + echo "AWS_SECRET_ACCESS_KEY=" + echo "AWS_SESSION_TOKEN=" + } >> "$GITHUB_ENV" + - name: Sweep board uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: