From 12849901496c7c48aace3a249c5091a00be203ec Mon Sep 17 00:00:00 2001 From: Grant Allen Date: Mon, 9 Mar 2026 11:10:16 -0700 Subject: [PATCH 1/2] Add workflow to test PrivateCIWorkflows role assumption Tests whether a public repo can assume the PrivateCIWorkflows IAM role. This role should only be assumable by private repos due to the repository_visibility=private constraint. Expected results: - Before infra PR merged: "Role does not exist yet" - After infra PR merged: "Access denied" (expected for public repos) Co-Authored-By: Claude Opus 4.5 --- .github/workflows/test-private-ci-role.yml | 77 ++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 .github/workflows/test-private-ci-role.yml diff --git a/.github/workflows/test-private-ci-role.yml b/.github/workflows/test-private-ci-role.yml new file mode 100644 index 0000000..dbffa4e --- /dev/null +++ b/.github/workflows/test-private-ci-role.yml @@ -0,0 +1,77 @@ +name: Test PrivateCIWorkflows Role +on: + pull_request: + workflow_dispatch: + +permissions: + contents: read + id-token: write + +jobs: + test-role-assumption: + runs-on: ubuntu-latest + env: + ROLE_ARN: arn:aws:iam::708167139547:role/PrivateCIWorkflows + steps: + - name: Get OIDC token + id: get-token + run: | + TOKEN=$(curl -s -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ + "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=sts.amazonaws.com" | jq -r '.value') + echo "::add-mask::$TOKEN" + echo "token=$TOKEN" >> "$GITHUB_OUTPUT" + + - name: Attempt to assume role and report result + env: + OIDC_TOKEN: ${{ steps.get-token.outputs.token }} + run: | + echo "===========================================" + echo "Testing PrivateCIWorkflows role assumption" + echo "Role ARN: $ROLE_ARN" + echo "Repository: $GITHUB_REPOSITORY" + echo "Visibility: public" + echo "===========================================" + echo "" + + ERROR_FILE=$(mktemp) + + RESULT=$(aws sts assume-role-with-web-identity \ + --role-arn "$ROLE_ARN" \ + --role-session-name "test-session" \ + --web-identity-token "$OIDC_TOKEN" \ + --duration-seconds 900 2>"$ERROR_FILE") && SUCCESS=true || SUCCESS=false + + if [[ "$SUCCESS" == "true" ]]; then + echo "✅ RESULT: Role assumed successfully" + echo "" + echo "This public repo CAN assume the PrivateCIWorkflows role." + echo "⚠️ WARNING: This is NOT the expected behavior!" + echo "The role should only be assumable by private repos." + echo "" + echo "Caller identity:" + echo "$RESULT" | jq '.AssumedRoleUser' + exit 1 + fi + + ERROR=$(cat "$ERROR_FILE") + echo "Role assumption failed (this may be expected)" + echo "" + + if echo "$ERROR" | grep -q "NoSuchEntity\|does not exist"; then + echo "📋 RESULT: Role does not exist yet" + echo "" + echo "The PrivateCIWorkflows role has not been created." + echo "Action: Merge the infra PR to create the role, then re-run this workflow." + elif echo "$ERROR" | grep -q "Not authorized\|AccessDenied\|not authorized to perform"; then + echo "🔒 RESULT: Access denied (EXPECTED for public repos)" + echo "" + echo "The role exists and correctly rejects this public repository." + echo "The repository_visibility=private constraint is working!" + else + echo "❓ RESULT: Unknown error" + echo "" + echo "Error details:" + echo "$ERROR" + fi + echo "" + echo "===========================================" From 705bf526c27b5f7472c8f44a53f2e116d4ee91a6 Mon Sep 17 00:00:00 2001 From: Grant Allen Date: Mon, 9 Mar 2026 11:15:31 -0700 Subject: [PATCH 2/2] Fix error detection to show raw AWS error and distinguish cases - Print raw error message from AWS for debugging - Detect "Conditions were not met" for trust policy rejections - Distinguish between role not existing vs OIDC issues Co-Authored-By: Claude Opus 4.5 --- .github/workflows/test-private-ci-role.yml | 23 ++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test-private-ci-role.yml b/.github/workflows/test-private-ci-role.yml index dbffa4e..2529e1e 100644 --- a/.github/workflows/test-private-ci-role.yml +++ b/.github/workflows/test-private-ci-role.yml @@ -56,22 +56,33 @@ jobs: ERROR=$(cat "$ERROR_FILE") echo "Role assumption failed (this may be expected)" echo "" + echo "Raw error from AWS:" + echo "$ERROR" + echo "" + + # "does not exist" or "NoSuchEntity" = role not created yet + # "Not authorized" with "Conditions were not met" = trust policy rejected (visibility constraint) + # "Not authorized" without conditions message = OIDC provider issue or role doesn't exist - if echo "$ERROR" | grep -q "NoSuchEntity\|does not exist"; then + if echo "$ERROR" | grep -qi "does not exist"; then echo "📋 RESULT: Role does not exist yet" echo "" echo "The PrivateCIWorkflows role has not been created." echo "Action: Merge the infra PR to create the role, then re-run this workflow." - elif echo "$ERROR" | grep -q "Not authorized\|AccessDenied\|not authorized to perform"; then - echo "🔒 RESULT: Access denied (EXPECTED for public repos)" + elif echo "$ERROR" | grep -qi "Conditions were not met"; then + echo "🔒 RESULT: Access denied - conditions not met (EXPECTED for public repos)" echo "" echo "The role exists and correctly rejects this public repository." echo "The repository_visibility=private constraint is working!" + elif echo "$ERROR" | grep -qi "Not authorized"; then + echo "❓ RESULT: Not authorized (role may not exist or OIDC provider issue)" + echo "" + echo "This could mean:" + echo " 1. The role does not exist yet" + echo " 2. The OIDC provider is not configured for this account" + echo " 3. Some other trust policy issue" else echo "❓ RESULT: Unknown error" - echo "" - echo "Error details:" - echo "$ERROR" fi echo "" echo "==========================================="