Skip to content

Review with AWS Bedrock (keyless OIDC)

Use this guide to run lgtmaybe with AWS Bedrock using GitHub's OIDC token — no static AWS credentials stored in secrets.

Contents

How it works

GitHub Actions issues a short-lived OIDC token. AWS STS exchanges that token for temporary IAM credentials scoped to a role you control. The action performs that exchange for you (pass aws_role_arn) and lgtmaybe picks up the ambient credentials automatically — no AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY in your secrets.

One-time AWS setup

This is the human-only part — do it once in your AWS account:

  1. Create an IAM OIDC identity provider for token.actions.githubusercontent.com.
  2. Create an IAM role with a trust policy scoped to your repo (repo:<org>/lgtmaybe:*).
  3. Attach the least-privilege policy below.
  4. Confirm the models you want are enabled in the target region (model access request in the Bedrock console).
  5. Note the role ARN (e.g. arn:aws:iam::123456789012:role/lgtmaybe-bedrock) — it becomes the aws_role_arn action input. No static key is ever stored.

The role needs only:

{
  "Effect": "Allow",
  "Action": [
    "bedrock:InvokeModel",
    "bedrock:InvokeModelWithResponseStream"
  ],
  "Resource": [
    "arn:aws:bedrock:*:<account-id>:inference-profile/*",
    "arn:aws:bedrock:*::foundation-model/*"
  ]
}

Both ARNs are required for the recommended inference-profile model ids (the us./eu./apac.-prefixed ids below). A cross-region inference profile fans the call out to the foundation model in several regions, so the role needs bedrock:InvokeModel* on both the inference-profile/* ARN and the underlying foundation-model/* ARN. Granting only one of them still fails with AccessDeniedException. A bare anthropic.… model id needs only the foundation-model/* ARN, but most current Claude models are invocable only through an inference profile — see the model table below.

Scope each Resource to specific model / inference-profile ARNs for tighter least-privilege once it works, e.g. arn:aws:bedrock:*:<account-id>:inference-profile/us.anthropic.claude-opus-4-8* and arn:aws:bedrock:*::foundation-model/anthropic.claude-opus-4-8*.

Workflow example

The action assumes the role for you — no separate configure-aws-credentials step needed. Store the role ARN in an AWS_ROLE_ARN secret.

name: lgtmaybe

on:
  pull_request_target:
  issue_comment:
    types: [created]

permissions:
  id-token: write          # required for the OIDC token exchange (keyless)
  pull-requests: write     # required to post review comments
  contents: read

jobs:
  review:
    # Only trusted authors (repo owner / org member / collaborator) can trigger
    # a review, so fork PRs and drive-by comments cannot spend your provider
    # budget. A maintainer can still opt in to an external PR with /review.
    if: >-
      (github.event_name == 'pull_request_target' &&
       contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.pull_request.author_association)) ||
      (github.event.issue.pull_request &&
       contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association))
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: MattJColes/lgtmaybe@v1
        with:
          provider: bedrock
          model: us.anthropic.claude-sonnet-4-6
          aws_role_arn: ${{ secrets.AWS_ROLE_ARN }}
          aws_region: us-east-1

Choosing a Bedrock model ID

The model must be a Bedrock model identifier. Bedrock hosts Anthropic Claude, Amazon Nova/Titan, Meta Llama, Mistral, Cohere and others — it does not host OpenAI's GPT models, so an id like openai.gpt-5.5 is rejected with The provided model identifier is invalid. Use one of the Claude ids below (prefixed with a cross-region inference profile — see the note):

Model Inference-profile ID (recommended) Base model ID
Claude Opus 4.8 us.anthropic.claude-opus-4-8 anthropic.claude-opus-4-8
Claude Sonnet 4.6 us.anthropic.claude-sonnet-4-6 anthropic.claude-sonnet-4-6
Claude Haiku 4.5 us.anthropic.claude-haiku-4-5 anthropic.claude-haiku-4-5

Prefer the inference-profile form. Most current Claude models on Bedrock are invocable only through a cross-region inference profile, not via on-demand throughput on the bare model id — so a bare id often fails with the same invalid model identifier (or on-demand throughput isn't supported) error. Prefix with your geography: us. (US), eu. (Europe) or apac. (Asia Pacific), matching aws_region. Use the bare anthropic.… id only where on-demand access to that model is enabled in your region.

Running locally with ambient AWS credentials

If your local shell has AWS credentials (via ~/.aws, SSO, or an assumed role), you can review your current branch's changes with Bedrock. Bedrock signing needs boto3, so install the extra (the Action image already bundles it):

pip install 'lgtmaybe[bedrock]'

lgtmaybe review \
  --provider bedrock \
  --model us.anthropic.claude-sonnet-4-6

lgtmaybe does not require or accept a static API key for Bedrock.

No matching distribution found for lgtmaybe[bedrock] (from versions: none) — this is not a packaging problem; the bedrock extra is published on PyPI. It means pip found no version compatible with your environment. The usual cause is an interpreter older than the required Python 3.11+ (check with python --version); install under 3.11+ (e.g. via pipx/uv). If your Python is fine, your pip can't reach PyPI — check your network/proxy or --index-url.

Troubleshooting

ExpiredTokenException — the OIDC exchange failed or the role session expired. Check that id-token: write permission is present in the workflow and that the IAM trust policy references the correct GitHub repository.

AccessDeniedException — the role lacks bedrock:InvokeModel for the selected model, or the model is not enabled in the Bedrock console for your account and region. For an inference-profile id (us./eu./apac.-prefixed), the policy must also allow the inference-profile/* ARN, not just foundation-model/*.

The provided model identifier is invalid — the model is not a Bedrock model id. Two common causes: (1) it's a non-Bedrock id such as openai.gpt-5.5 or another provider's name — Bedrock hosts Claude / Nova / Llama / Mistral / Cohere, not OpenAI GPT, so pick a Claude id from the table above; (2) the model needs a cross-region inference profile — prefix with us./eu./apac. (e.g. us.anthropic.claude-sonnet-4-6) rather than the bare anthropic.… id.