Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions .github/workflows/ecr-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ on:
required: true
type: string

permissions:
contents: read
id-token: write
Comment on lines +11 to +13

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actions: write is not required here. BuildKit’s type=gha backend uses the GitHub-provided ACTIONS_RUNTIME_TOKEN, and docker/build-push-action automatically supplies the cache URL and token. We also have the same contents: read + id-token: write configuration running successfully with GHA cache import/export in context7parser. Keeping the current permissions preserves least privilege.


jobs:
build-and-push:
runs-on: ubuntu-latest
Expand All @@ -19,9 +23,11 @@ jobs:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v6
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
role-to-assume: ${{ secrets.AWS_ECR_ROLE_ARN }}
aws-region: ${{ secrets.AWS_REGION }}
allowed-account-ids: ${{ secrets.AWS_ACCOUNT_ID }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

allowed-account-ids fails open when this secret is empty, so the guardrail can silently disappear.

In configure-aws-credentials@v6 the input is parsed as getInput('allowed-account-ids').split(','), and the check bails out early when the first element is an empty string:

// src/helpers.ts:169
export function validateAccountId(expectedAccountIds: string[] | undefined, account: string | undefined): void {
  if (!expectedAccountIds || expectedAccountIds.length === 0 || expectedAccountIds[0] === '') {
    return;
  }
  ...
}

An unset, renamed, or typo'd AWS_ACCOUNT_ID therefore turns the account check into a no-op with no warning and no failure — the deploy just proceeds unguarded. The secret does exist today, so this works as intended right now; it's a latent trap for whenever secrets get rotated or renamed.

The earlier revision of this PR had the literal allowed-account-ids: "640168447591", which can't go missing. The account ID isn't really a secret either — it's already embedded in the role ARN and in the ECR registry hostname — so a literal or a repo variable would be a safer home for it than a secret.

Related nit on the next line: mask-aws-account-id: true is redundant when the ID comes from a secret (GitHub already masks it), and its main effect is to render the guardrail's own failure message as does not match any of the expected account IDs: *** — which is exactly the message you want readable when it trips.

mask-aws-account-id: true
role-session-name: context7-ecr-${{ github.run_id }}

- name: Login to Amazon ECR
id: login-ecr
Expand Down