Skip to content

fix: Add pre-validation for Bedrock and MLflow role permissions #183

fix: Add pre-validation for Bedrock and MLflow role permissions

fix: Add pre-validation for Bedrock and MLflow role permissions #183

Workflow file for this run

name: AI Code Review (Claude on Bedrock)
# Automated PR review using Anthropic's Claude Code Action running on Amazon
# Bedrock (inference stays in-account, CloudTrail-audited, no external API key).
#
# Fork safety: this uses pull_request_target (needed to access the Bedrock role
# and post comments), so it reuses the same collaborator gate as
# pr-checks-master.yml. Collaborator PRs -> `auto-approve` env (runs immediately).
# Fork/external PRs -> `manual-approval` env (a maintainer must approve the run
# before any secret or the Bedrock role is exposed).
on:
pull_request_target:
types: [opened, synchronize, ready_for_review, reopened]
# Scope to the same product directories the other PR checks use, so pure
# docs/example PRs don't trigger a model review. Remove this block to
# review every PR.
paths:
- 'sagemaker-train/**'
- 'sagemaker-serve/**'
- 'sagemaker-mlops/**'
- 'sagemaker-core/**'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.head_ref }}
cancel-in-progress: true
permissions:
id-token: write # OIDC federation to assume the Bedrock role
pull-requests: write # post inline review comments and a summary
contents: read
jobs:
# Identical gate to pr-checks-master.yml: collaborators auto-approve,
# everyone else requires manual approval via the `manual-approval` environment.
collab-check:
runs-on: ubuntu-latest
outputs:
approval-env: ${{ steps.collab-check.outputs.result }}
steps:
- name: Collaborator Check
uses: actions/github-script@v7
id: collab-check
with:
github-token: ${{ secrets.COLLAB_CHECK_TOKEN }}
result-encoding: string
script: |
try {
const res = await github.rest.repos.checkCollaborator({
owner: context.repo.owner,
repo: context.repo.repo,
username: "${{ github.event.pull_request.user.login }}",
});
console.log("Verified ${{ github.event.pull_request.user.login }} is a repo collaborator. Auto approving AI review.")
return res.status == "204" ? "auto-approve" : "manual-approval"
} catch (error) {
console.log("${{ github.event.pull_request.user.login }} is not a collaborator. Requiring manual approval to run AI review.")
return "manual-approval"
}
wait-for-approval:
runs-on: ubuntu-latest
needs: [collab-check]
environment: ${{ needs.collab-check.outputs.approval-env }}
steps:
- run: echo "Approved — starting AI code review."
review:
runs-on: ubuntu-latest
needs: [wait-for-approval]
steps:
# SECURITY: this job runs in the trusted pull_request_target context (it
# holds the Bedrock role + secrets). We therefore check out the BASE repo
# at the PR's base branch — never the fork's head code — so untrusted PR
# code is never executed here ("pwn request" prevention). The PR contents
# are pulled in as a read-only diff below, not as an executable tree.
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.base.sha }}
fetch-depth: 1
# Fetch the PR diff via the API (does not execute any fork code) and store
# it as a static file. This is the ground truth Claude reviews.
- name: Fetch PR diff
id: diff
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}
run: |
set -euo pipefail
gh api "repos/$REPO/pulls/$PR_NUMBER" \
-H "Accept: application/vnd.github.v3.diff" > /tmp/pr.diff
BYTES=$(wc -c < /tmp/pr.diff)
echo "bytes=$BYTES" >> "$GITHUB_OUTPUT"
echo "PR diff: $BYTES bytes"
- name: Configure AWS Credentials
if: steps.diff.outputs.bytes != '0'
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.CODE_REVIEW_ROLE }}
aws-region: us-west-2
- uses: anthropics/claude-code-action@v1
if: steps.diff.outputs.bytes != '0'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
use_bedrock: "true"
track_progress: true
# Don't append "Fix this" deep-links (which open Claude Code) to review
# comments — external contributors can't use them and they add noise.
include_fix_links: false
# Bash is intentionally NOT allowed. The PR diff at /tmp/pr.diff is the
# only ground truth; the model reads it and uses Read/Grep/Glob against
# the trusted base checkout for context. It must not execute commands
# (which could run untrusted PR content) nor re-run git.
claude_args: |
--model us.anthropic.claude-opus-4-8
--allowedTools "Read Grep Glob mcp__github_inline_comment__create_inline_comment"
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}
The complete PR diff is at `/tmp/pr.diff` — read it first with the
Read tool. That file is the ground truth for what this PR changes; do
not run git or any shell commands. For context (callers of changed
functions, existing patterns, project conventions), use Read/Grep/Glob
against the checked-out base repository.
Review this pull request for the SageMaker Python SDK. Focus on:
- Correctness: bugs, incorrect API/argument usage, breaking changes
to public interfaces, backward-incompatibility for SDK consumers
- Python best practices and readability
- Security implications (credential handling, input validation)
- Performance considerations
- Missing or inadequate tests for changed behavior
Post specific issues as inline comments via the
mcp__github_inline_comment__create_inline_comment tool. Skip nits and
style the linters already enforce. If the PR looks clean, say so
briefly.