diff --git a/.github/workflows/pr-describe.yml b/.github/workflows/pr-describe.yml index 30ad370..dde070c 100644 --- a/.github/workflows/pr-describe.yml +++ b/.github/workflows/pr-describe.yml @@ -12,14 +12,67 @@ jobs: # Only run if comment contains /describe and is on a PR if: ${{ (github.event.issue.pull_request && contains(github.event.comment.body, '/describe')) }} runs-on: ubuntu-latest - env: - HAS_APP_SECRETS: ${{ secrets.CAGENT_REVIEWER_APP_ID != '' }} permissions: contents: read pull-requests: write issues: write checks: write + id-token: write steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: TODO_ROLE_ARN + aws-region: us-east-1 + + - name: Fetch GitHub App credentials from Secrets Manager + id: app-credentials + shell: bash + run: | + set -euo pipefail + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id docker-agent-action/github-app \ + --query SecretString --output text) + APP_ID=$(echo "$SECRET" | jq -r .app_id) + ORG_TOKEN=$(echo "$SECRET" | jq -r .org_membership_token) + PRIVATE_KEY=$(echo "$SECRET" | jq -r .private_key) + + if [ -z "$APP_ID" ] || [ "$APP_ID" = "null" ]; then + echo "::error::Failed to extract app_id from secret docker-agent-action/github-app" + exit 1 + fi + if [ -z "$ORG_TOKEN" ] || [ "$ORG_TOKEN" = "null" ]; then + echo "::error::Failed to extract org_membership_token from secret docker-agent-action/github-app" + exit 1 + fi + if [ -z "$PRIVATE_KEY" ] || [ "$PRIVATE_KEY" = "null" ]; then + echo "::error::Failed to extract private_key from secret docker-agent-action/github-app" + exit 1 + fi + + echo "::add-mask::$APP_ID" + echo "::add-mask::$ORG_TOKEN" + echo "::add-mask::$PRIVATE_KEY" + echo "app-id=$APP_ID" >> $GITHUB_OUTPUT + echo "org-membership-token=$ORG_TOKEN" >> $GITHUB_OUTPUT + DELIM="$(openssl rand -hex 8)" + { echo "private-key<<$DELIM"; echo "$PRIVATE_KEY"; echo "$DELIM"; } >> $GITHUB_OUTPUT + + - name: Fetch AI API keys from Secrets Manager + id: ai-api-keys + shell: bash + run: | + set -euo pipefail + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id docker-agent-action/ai-api-keys \ + --query SecretString --output text) + ANTHROPIC_KEY=$(echo "$SECRET" | jq -r '.anthropic_api_key // ""') + OPENAI_KEY=$(echo "$SECRET" | jq -r '.openai_api_key // ""') + [ -n "$ANTHROPIC_KEY" ] && echo "::add-mask::$ANTHROPIC_KEY" + [ -n "$OPENAI_KEY" ] && echo "::add-mask::$OPENAI_KEY" + echo "anthropic-api-key=$ANTHROPIC_KEY" >> $GITHUB_OUTPUT + echo "openai-api-key=$OPENAI_KEY" >> $GITHUB_OUTPUT + - name: Check out Git repository uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 @@ -48,12 +101,11 @@ jobs: # Generate GitHub App token so actions appear as the custom app (optional - falls back to github.token) - name: Get GitHub App token id: app-token - if: env.HAS_APP_SECRETS == 'true' continue-on-error: true # Don't fail workflow if token generation fails uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2 with: - app_id: ${{ secrets.CAGENT_REVIEWER_APP_ID }} - private_key: ${{ secrets.CAGENT_REVIEWER_APP_PRIVATE_KEY }} + app_id: ${{ steps.app-credentials.outputs.app-id }} + private_key: ${{ steps.app-credentials.outputs.private-key }} - name: Validate PR and add reaction id: validate_pr @@ -180,7 +232,7 @@ jobs: **Diff:** $(cat pr.diff) - anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} + anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY || steps.ai-api-keys.outputs.anthropic-api-key }} github-token: ${{ steps.app-token.outputs.token || github.token }} timeout: 300 # 5 minutes diff --git a/.github/workflows/reply-to-feedback.yml b/.github/workflows/reply-to-feedback.yml index aae4671..db81674 100644 --- a/.github/workflows/reply-to-feedback.yml +++ b/.github/workflows/reply-to-feedback.yml @@ -19,16 +19,75 @@ permissions: pull-requests: write issues: write actions: read # Required to download artifacts from the triggering run + id-token: write jobs: reply: # Only run if the triggering workflow succeeded (artifact was uploaded) if: github.event.workflow_run.conclusion == 'success' runs-on: ubuntu-latest - env: - HAS_APP_SECRETS: ${{ secrets.CAGENT_REVIEWER_APP_ID != '' }} + permissions: + contents: read + pull-requests: write + issues: write + actions: read + id-token: write steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: TODO_ROLE_ARN + aws-region: us-east-1 + + - name: Fetch GitHub App credentials from Secrets Manager + id: app-credentials + shell: bash + run: | + set -euo pipefail + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id docker-agent-action/github-app \ + --query SecretString --output text) + APP_ID=$(echo "$SECRET" | jq -r .app_id) + ORG_TOKEN=$(echo "$SECRET" | jq -r .org_membership_token) + PRIVATE_KEY=$(echo "$SECRET" | jq -r .private_key) + + if [ -z "$APP_ID" ] || [ "$APP_ID" = "null" ]; then + echo "::error::Failed to extract app_id from secret docker-agent-action/github-app" + exit 1 + fi + if [ -z "$ORG_TOKEN" ] || [ "$ORG_TOKEN" = "null" ]; then + echo "::error::Failed to extract org_membership_token from secret docker-agent-action/github-app" + exit 1 + fi + if [ -z "$PRIVATE_KEY" ] || [ "$PRIVATE_KEY" = "null" ]; then + echo "::error::Failed to extract private_key from secret docker-agent-action/github-app" + exit 1 + fi + + echo "::add-mask::$APP_ID" + echo "::add-mask::$ORG_TOKEN" + echo "::add-mask::$PRIVATE_KEY" + echo "app-id=$APP_ID" >> $GITHUB_OUTPUT + echo "org-membership-token=$ORG_TOKEN" >> $GITHUB_OUTPUT + DELIM="$(openssl rand -hex 8)" + { echo "private-key<<$DELIM"; echo "$PRIVATE_KEY"; echo "$DELIM"; } >> $GITHUB_OUTPUT + + - name: Fetch AI API keys from Secrets Manager + id: ai-api-keys + shell: bash + run: | + set -euo pipefail + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id docker-agent-action/ai-api-keys \ + --query SecretString --output text) + ANTHROPIC_KEY=$(echo "$SECRET" | jq -r '.anthropic_api_key // ""') + OPENAI_KEY=$(echo "$SECRET" | jq -r '.openai_api_key // ""') + [ -n "$ANTHROPIC_KEY" ] && echo "::add-mask::$ANTHROPIC_KEY" + [ -n "$OPENAI_KEY" ] && echo "::add-mask::$OPENAI_KEY" + echo "anthropic-api-key=$ANTHROPIC_KEY" >> $GITHUB_OUTPUT + echo "openai-api-key=$OPENAI_KEY" >> $GITHUB_OUTPUT + # ---------------------------------------------------------------- # Download artifact from the triggering workflow run # ---------------------------------------------------------------- @@ -157,7 +216,7 @@ jobs: env: USERNAME: ${{ steps.meta.outputs.author }} with: - github-token: ${{ secrets.CAGENT_ORG_MEMBERSHIP_TOKEN }} + github-token: ${{ secrets.CAGENT_ORG_MEMBERSHIP_TOKEN || steps.app-credentials.outputs.org-membership-token }} script: | const org = 'docker'; const username = process.env.USERNAME; @@ -301,13 +360,13 @@ jobs: ref: refs/pull/${{ steps.meta.outputs.pr_number }}/head - name: Generate GitHub App token - if: steps.meta.outputs.proceed == 'true' && steps.auth.outputs.authorized == 'true' && env.HAS_APP_SECRETS == 'true' + if: steps.meta.outputs.proceed == 'true' && steps.auth.outputs.authorized == 'true' id: app-token continue-on-error: true uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2 with: - app_id: ${{ secrets.CAGENT_REVIEWER_APP_ID }} - private_key: ${{ secrets.CAGENT_REVIEWER_APP_PRIVATE_KEY }} + app_id: ${{ steps.app-credentials.outputs.app-id }} + private_key: ${{ steps.app-credentials.outputs.private-key }} - name: Run reply if: steps.meta.outputs.proceed == 'true' && steps.auth.outputs.authorized == 'true' && steps.checkout.outcome == 'success' && steps.thread.outcome == 'success' @@ -317,8 +376,8 @@ jobs: with: thread-context: ${{ steps.thread.outputs.prompt }} comment-id: ${{ steps.meta.outputs.comment_id }} - anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} - openai-api-key: ${{ secrets.OPENAI_API_KEY }} + anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY || steps.ai-api-keys.outputs.anthropic-api-key }} + openai-api-key: ${{ secrets.OPENAI_API_KEY || steps.ai-api-keys.outputs.openai-api-key }} google-api-key: ${{ secrets.GOOGLE_API_KEY }} aws-bearer-token-bedrock: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }} xai-api-key: ${{ secrets.XAI_API_KEY }} diff --git a/.github/workflows/review-pr.yml b/.github/workflows/review-pr.yml index 8466abd..eda52c3 100644 --- a/.github/workflows/review-pr.yml +++ b/.github/workflows/review-pr.yml @@ -124,12 +124,69 @@ jobs: inputs.pr-number != '' ) runs-on: ubuntu-latest - env: - HAS_APP_SECRETS: ${{ secrets.CAGENT_REVIEWER_APP_ID != '' }} + permissions: + contents: read + pull-requests: write + issues: write + id-token: write outputs: exit-code: ${{ steps.run-review.outputs.exit-code }} steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: TODO_ROLE_ARN + aws-region: us-east-1 + + - name: Fetch GitHub App credentials from Secrets Manager + id: app-credentials + shell: bash + run: | + set -euo pipefail + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id docker-agent-action/github-app \ + --query SecretString --output text) + APP_ID=$(echo "$SECRET" | jq -r .app_id) + ORG_TOKEN=$(echo "$SECRET" | jq -r .org_membership_token) + PRIVATE_KEY=$(echo "$SECRET" | jq -r .private_key) + + if [ -z "$APP_ID" ] || [ "$APP_ID" = "null" ]; then + echo "::error::Failed to extract app_id from secret docker-agent-action/github-app" + exit 1 + fi + if [ -z "$ORG_TOKEN" ] || [ "$ORG_TOKEN" = "null" ]; then + echo "::error::Failed to extract org_membership_token from secret docker-agent-action/github-app" + exit 1 + fi + if [ -z "$PRIVATE_KEY" ] || [ "$PRIVATE_KEY" = "null" ]; then + echo "::error::Failed to extract private_key from secret docker-agent-action/github-app" + exit 1 + fi + + echo "::add-mask::$APP_ID" + echo "::add-mask::$ORG_TOKEN" + echo "::add-mask::$PRIVATE_KEY" + echo "app-id=$APP_ID" >> $GITHUB_OUTPUT + echo "org-membership-token=$ORG_TOKEN" >> $GITHUB_OUTPUT + DELIM="$(openssl rand -hex 8)" + { echo "private-key<<$DELIM"; echo "$PRIVATE_KEY"; echo "$DELIM"; } >> $GITHUB_OUTPUT + + - name: Fetch AI API keys from Secrets Manager + id: ai-api-keys + shell: bash + run: | + set -euo pipefail + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id docker-agent-action/ai-api-keys \ + --query SecretString --output text) + ANTHROPIC_KEY=$(echo "$SECRET" | jq -r '.anthropic_api_key // ""') + OPENAI_KEY=$(echo "$SECRET" | jq -r '.openai_api_key // ""') + [ -n "$ANTHROPIC_KEY" ] && echo "::add-mask::$ANTHROPIC_KEY" + [ -n "$OPENAI_KEY" ] && echo "::add-mask::$OPENAI_KEY" + echo "anthropic-api-key=$ANTHROPIC_KEY" >> $GITHUB_OUTPUT + echo "openai-api-key=$OPENAI_KEY" >> $GITHUB_OUTPUT + - name: Get PR number id: get-pr shell: bash @@ -167,7 +224,7 @@ jobs: PR_DRAFT: ${{ steps.pr-info.outputs.draft }} PR_AUTHOR: ${{ steps.pr-info.outputs.author }} with: - github-token: ${{ secrets.CAGENT_ORG_MEMBERSHIP_TOKEN }} + github-token: ${{ secrets.CAGENT_ORG_MEMBERSHIP_TOKEN || steps.app-credentials.outputs.org-membership-token }} script: | const org = '${{ inputs.auto-review-org }}'; @@ -216,13 +273,13 @@ jobs: # Generate GitHub App token for custom app identity (optional - falls back to github.token) - name: Generate GitHub App token - if: steps.membership.outputs.is_member == 'true' && env.HAS_APP_SECRETS == 'true' + if: steps.membership.outputs.is_member == 'true' id: app-token continue-on-error: true # Don't fail workflow if token generation fails uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2 with: - app_id: ${{ secrets.CAGENT_REVIEWER_APP_ID }} - private_key: ${{ secrets.CAGENT_REVIEWER_APP_PRIVATE_KEY }} + app_id: ${{ steps.app-credentials.outputs.app-id }} + private_key: ${{ steps.app-credentials.outputs.private-key }} - name: Run PR Review if: steps.membership.outputs.is_member == 'true' @@ -235,8 +292,8 @@ jobs: add-prompt-files: ${{ inputs.add-prompt-files }} model: ${{ inputs.model }} github-token: ${{ steps.app-token.outputs.token || github.token }} - anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} - openai-api-key: ${{ secrets.OPENAI_API_KEY }} + anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY || steps.ai-api-keys.outputs.anthropic-api-key }} + openai-api-key: ${{ secrets.OPENAI_API_KEY || steps.ai-api-keys.outputs.openai-api-key }} google-api-key: ${{ secrets.GOOGLE_API_KEY }} aws-bearer-token-bedrock: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }} xai-api-key: ${{ secrets.XAI_API_KEY }} @@ -254,17 +311,74 @@ jobs: startsWith(github.event.comment.body, '/review') && (github.event.comment.user.type != 'Bot' || github.event.comment.user.login == 'docker-agent[bot]') runs-on: ubuntu-latest - env: - HAS_APP_SECRETS: ${{ secrets.CAGENT_REVIEWER_APP_ID != '' }} + permissions: + contents: read + pull-requests: write + issues: write + id-token: write outputs: exit-code: ${{ steps.run-review.outputs.exit-code }} steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: TODO_ROLE_ARN + aws-region: us-east-1 + + - name: Fetch GitHub App credentials from Secrets Manager + id: app-credentials + shell: bash + run: | + set -euo pipefail + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id docker-agent-action/github-app \ + --query SecretString --output text) + APP_ID=$(echo "$SECRET" | jq -r .app_id) + ORG_TOKEN=$(echo "$SECRET" | jq -r .org_membership_token) + PRIVATE_KEY=$(echo "$SECRET" | jq -r .private_key) + + if [ -z "$APP_ID" ] || [ "$APP_ID" = "null" ]; then + echo "::error::Failed to extract app_id from secret docker-agent-action/github-app" + exit 1 + fi + if [ -z "$ORG_TOKEN" ] || [ "$ORG_TOKEN" = "null" ]; then + echo "::error::Failed to extract org_membership_token from secret docker-agent-action/github-app" + exit 1 + fi + if [ -z "$PRIVATE_KEY" ] || [ "$PRIVATE_KEY" = "null" ]; then + echo "::error::Failed to extract private_key from secret docker-agent-action/github-app" + exit 1 + fi + + echo "::add-mask::$APP_ID" + echo "::add-mask::$ORG_TOKEN" + echo "::add-mask::$PRIVATE_KEY" + echo "app-id=$APP_ID" >> $GITHUB_OUTPUT + echo "org-membership-token=$ORG_TOKEN" >> $GITHUB_OUTPUT + DELIM="$(openssl rand -hex 8)" + { echo "private-key<<$DELIM"; echo "$PRIVATE_KEY"; echo "$DELIM"; } >> $GITHUB_OUTPUT + + - name: Fetch AI API keys from Secrets Manager + id: ai-api-keys + shell: bash + run: | + set -euo pipefail + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id docker-agent-action/ai-api-keys \ + --query SecretString --output text) + ANTHROPIC_KEY=$(echo "$SECRET" | jq -r '.anthropic_api_key // ""') + OPENAI_KEY=$(echo "$SECRET" | jq -r '.openai_api_key // ""') + [ -n "$ANTHROPIC_KEY" ] && echo "::add-mask::$ANTHROPIC_KEY" + [ -n "$OPENAI_KEY" ] && echo "::add-mask::$OPENAI_KEY" + echo "anthropic-api-key=$ANTHROPIC_KEY" >> $GITHUB_OUTPUT + echo "openai-api-key=$OPENAI_KEY" >> $GITHUB_OUTPUT + - name: Check if commenter is org member id: membership uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: - github-token: ${{ secrets.CAGENT_ORG_MEMBERSHIP_TOKEN }} + github-token: ${{ secrets.CAGENT_ORG_MEMBERSHIP_TOKEN || steps.app-credentials.outputs.org-membership-token }} script: | const org = '${{ inputs.auto-review-org }}'; const username = context.payload.comment.user.login; @@ -303,13 +417,13 @@ jobs: # Generate GitHub App token first so the check run is created under the app's identity # (prevents GitHub from nesting it under unrelated pull_request-triggered workflows) - name: Generate GitHub App token - if: steps.membership.outputs.is_member == 'true' && env.HAS_APP_SECRETS == 'true' + if: steps.membership.outputs.is_member == 'true' id: app-token continue-on-error: true # Don't fail workflow if token generation fails uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2 with: - app_id: ${{ secrets.CAGENT_REVIEWER_APP_ID }} - private_key: ${{ secrets.CAGENT_REVIEWER_APP_PRIVATE_KEY }} + app_id: ${{ steps.app-credentials.outputs.app-id }} + private_key: ${{ steps.app-credentials.outputs.private-key }} - name: Create check run if: steps.membership.outputs.is_member == 'true' @@ -358,9 +472,9 @@ jobs: add-prompt-files: ${{ inputs.add-prompt-files }} model: ${{ inputs.model }} github-token: ${{ steps.app-token.outputs.token || github.token }} - trusted-bot-app-id: ${{ secrets.CAGENT_REVIEWER_APP_ID }} - anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} - openai-api-key: ${{ secrets.OPENAI_API_KEY }} + trusted-bot-app-id: ${{ steps.app-credentials.outputs.app-id }} + anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY || steps.ai-api-keys.outputs.anthropic-api-key }} + openai-api-key: ${{ secrets.OPENAI_API_KEY || steps.ai-api-keys.outputs.openai-api-key }} google-api-key: ${{ secrets.GOOGLE_API_KEY }} aws-bearer-token-bedrock: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }} xai-api-key: ${{ secrets.XAI_API_KEY }} @@ -455,10 +569,67 @@ jobs: github.event.comment.in_reply_to_id && github.event.comment.user.type != 'Bot' runs-on: ubuntu-latest - env: - HAS_APP_SECRETS: ${{ secrets.CAGENT_REVIEWER_APP_ID != '' }} + permissions: + contents: read + pull-requests: write + issues: write + id-token: write steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: TODO_ROLE_ARN + aws-region: us-east-1 + + - name: Fetch GitHub App credentials from Secrets Manager + id: app-credentials + shell: bash + run: | + set -euo pipefail + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id docker-agent-action/github-app \ + --query SecretString --output text) + APP_ID=$(echo "$SECRET" | jq -r .app_id) + ORG_TOKEN=$(echo "$SECRET" | jq -r .org_membership_token) + PRIVATE_KEY=$(echo "$SECRET" | jq -r .private_key) + + if [ -z "$APP_ID" ] || [ "$APP_ID" = "null" ]; then + echo "::error::Failed to extract app_id from secret docker-agent-action/github-app" + exit 1 + fi + if [ -z "$ORG_TOKEN" ] || [ "$ORG_TOKEN" = "null" ]; then + echo "::error::Failed to extract org_membership_token from secret docker-agent-action/github-app" + exit 1 + fi + if [ -z "$PRIVATE_KEY" ] || [ "$PRIVATE_KEY" = "null" ]; then + echo "::error::Failed to extract private_key from secret docker-agent-action/github-app" + exit 1 + fi + + echo "::add-mask::$APP_ID" + echo "::add-mask::$ORG_TOKEN" + echo "::add-mask::$PRIVATE_KEY" + echo "app-id=$APP_ID" >> $GITHUB_OUTPUT + echo "org-membership-token=$ORG_TOKEN" >> $GITHUB_OUTPUT + DELIM="$(openssl rand -hex 8)" + { echo "private-key<<$DELIM"; echo "$PRIVATE_KEY"; echo "$DELIM"; } >> $GITHUB_OUTPUT + + - name: Fetch AI API keys from Secrets Manager + id: ai-api-keys + shell: bash + run: | + set -euo pipefail + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id docker-agent-action/ai-api-keys \ + --query SecretString --output text) + ANTHROPIC_KEY=$(echo "$SECRET" | jq -r '.anthropic_api_key // ""') + OPENAI_KEY=$(echo "$SECRET" | jq -r '.openai_api_key // ""') + [ -n "$ANTHROPIC_KEY" ] && echo "::add-mask::$ANTHROPIC_KEY" + [ -n "$OPENAI_KEY" ] && echo "::add-mask::$OPENAI_KEY" + echo "anthropic-api-key=$ANTHROPIC_KEY" >> $GITHUB_OUTPUT + echo "openai-api-key=$OPENAI_KEY" >> $GITHUB_OUTPUT + - name: Check if reply is to agent comment id: check shell: bash @@ -526,7 +697,7 @@ jobs: id: auth shell: bash env: - GH_TOKEN: ${{ secrets.CAGENT_ORG_MEMBERSHIP_TOKEN }} + GH_TOKEN: ${{ secrets.CAGENT_ORG_MEMBERSHIP_TOKEN || steps.app-credentials.outputs.org-membership-token }} ORG: ${{ inputs.auto-review-org }} USERNAME: ${{ github.event.comment.user.login }} run: | @@ -682,13 +853,13 @@ jobs: # Generate GitHub App token for custom app identity (optional - falls back to github.token) - name: Generate GitHub App token - if: steps.check.outputs.is_agent == 'true' && steps.auth.outputs.authorized == 'true' && env.HAS_APP_SECRETS == 'true' + if: steps.check.outputs.is_agent == 'true' && steps.auth.outputs.authorized == 'true' id: app-token continue-on-error: true uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2 with: - app_id: ${{ secrets.CAGENT_REVIEWER_APP_ID }} - private_key: ${{ secrets.CAGENT_REVIEWER_APP_PRIVATE_KEY }} + app_id: ${{ steps.app-credentials.outputs.app-id }} + private_key: ${{ steps.app-credentials.outputs.private-key }} - name: Run reply if: steps.check.outputs.is_agent == 'true' && steps.auth.outputs.authorized == 'true' @@ -697,8 +868,8 @@ jobs: with: thread-context: ${{ steps.thread.outputs.prompt }} comment-id: ${{ github.event.comment.id }} - anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} - openai-api-key: ${{ secrets.OPENAI_API_KEY }} + anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY || steps.ai-api-keys.outputs.anthropic-api-key }} + openai-api-key: ${{ secrets.OPENAI_API_KEY || steps.ai-api-keys.outputs.openai-api-key }} google-api-key: ${{ secrets.GOOGLE_API_KEY }} aws-bearer-token-bedrock: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }} xai-api-key: ${{ secrets.XAI_API_KEY }} diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml index 93a6cbb..7607b96 100644 --- a/.github/workflows/security-scan.yml +++ b/.github/workflows/security-scan.yml @@ -19,12 +19,65 @@ jobs: security-scan: name: Security Scan with Docker Agent runs-on: ubuntu-latest - env: - HAS_APP_SECRETS: ${{ secrets.CAGENT_REVIEWER_APP_ID != '' }} permissions: contents: read issues: write + id-token: write steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: TODO_ROLE_ARN + aws-region: us-east-1 + + - name: Fetch GitHub App credentials from Secrets Manager + id: app-credentials + shell: bash + run: | + set -euo pipefail + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id docker-agent-action/github-app \ + --query SecretString --output text) + APP_ID=$(echo "$SECRET" | jq -r .app_id) + ORG_TOKEN=$(echo "$SECRET" | jq -r .org_membership_token) + PRIVATE_KEY=$(echo "$SECRET" | jq -r .private_key) + + if [ -z "$APP_ID" ] || [ "$APP_ID" = "null" ]; then + echo "::error::Failed to extract app_id from secret docker-agent-action/github-app" + exit 1 + fi + if [ -z "$ORG_TOKEN" ] || [ "$ORG_TOKEN" = "null" ]; then + echo "::error::Failed to extract org_membership_token from secret docker-agent-action/github-app" + exit 1 + fi + if [ -z "$PRIVATE_KEY" ] || [ "$PRIVATE_KEY" = "null" ]; then + echo "::error::Failed to extract private_key from secret docker-agent-action/github-app" + exit 1 + fi + + echo "::add-mask::$APP_ID" + echo "::add-mask::$ORG_TOKEN" + echo "::add-mask::$PRIVATE_KEY" + echo "app-id=$APP_ID" >> $GITHUB_OUTPUT + echo "org-membership-token=$ORG_TOKEN" >> $GITHUB_OUTPUT + DELIM="$(openssl rand -hex 8)" + { echo "private-key<<$DELIM"; echo "$PRIVATE_KEY"; echo "$DELIM"; } >> $GITHUB_OUTPUT + + - name: Fetch AI API keys from Secrets Manager + id: ai-api-keys + shell: bash + run: | + set -euo pipefail + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id docker-agent-action/ai-api-keys \ + --query SecretString --output text) + ANTHROPIC_KEY=$(echo "$SECRET" | jq -r '.anthropic_api_key // ""') + OPENAI_KEY=$(echo "$SECRET" | jq -r '.openai_api_key // ""') + [ -n "$ANTHROPIC_KEY" ] && echo "::add-mask::$ANTHROPIC_KEY" + [ -n "$OPENAI_KEY" ] && echo "::add-mask::$OPENAI_KEY" + echo "anthropic-api-key=$ANTHROPIC_KEY" >> $GITHUB_OUTPUT + echo "openai-api-key=$OPENAI_KEY" >> $GITHUB_OUTPUT + - name: Check out Git repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: @@ -33,12 +86,11 @@ jobs: # Generate GitHub App token so issues appear as the custom app (optional - falls back to github.token) - name: Get GitHub App token id: app-token - if: env.HAS_APP_SECRETS == 'true' continue-on-error: true # Don't fail workflow if token generation fails uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2 with: - app_id: ${{ secrets.CAGENT_REVIEWER_APP_ID }} - private_key: ${{ secrets.CAGENT_REVIEWER_APP_PRIVATE_KEY }} + app_id: ${{ steps.app-credentials.outputs.app-id }} + private_key: ${{ steps.app-credentials.outputs.private-key }} - name: Get commits from past week id: commits @@ -125,7 +177,7 @@ jobs: with: agent: agentcatalog/github-action-security-scanner prompt: ${{ steps.commits.outputs.prompt }} - anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} + anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY || steps.ai-api-keys.outputs.anthropic-api-key }} timeout: 300 # 5 minutes - name: Validate reported file paths diff --git a/.github/workflows/self-review-pr.yml b/.github/workflows/self-review-pr.yml index 49602b9..0d3b92e 100644 --- a/.github/workflows/self-review-pr.yml +++ b/.github/workflows/self-review-pr.yml @@ -22,6 +22,7 @@ permissions: issues: write checks: write actions: read + id-token: write jobs: # ========================================================================== @@ -45,10 +46,62 @@ jobs: github.event.workflow_run.head_repository.full_name != github.repository ) runs-on: ubuntu-latest - env: - HAS_APP_SECRETS: ${{ secrets.CAGENT_REVIEWER_APP_ID != '' }} steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: TODO_ROLE_ARN + aws-region: us-east-1 + + - name: Fetch GitHub App credentials from Secrets Manager + id: app-credentials + shell: bash + run: | + set -euo pipefail + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id docker-agent-action/github-app \ + --query SecretString --output text) + APP_ID=$(echo "$SECRET" | jq -r .app_id) + ORG_TOKEN=$(echo "$SECRET" | jq -r .org_membership_token) + PRIVATE_KEY=$(echo "$SECRET" | jq -r .private_key) + + if [ -z "$APP_ID" ] || [ "$APP_ID" = "null" ]; then + echo "::error::Failed to extract app_id from secret docker-agent-action/github-app" + exit 1 + fi + if [ -z "$ORG_TOKEN" ] || [ "$ORG_TOKEN" = "null" ]; then + echo "::error::Failed to extract org_membership_token from secret docker-agent-action/github-app" + exit 1 + fi + if [ -z "$PRIVATE_KEY" ] || [ "$PRIVATE_KEY" = "null" ]; then + echo "::error::Failed to extract private_key from secret docker-agent-action/github-app" + exit 1 + fi + + echo "::add-mask::$APP_ID" + echo "::add-mask::$ORG_TOKEN" + echo "::add-mask::$PRIVATE_KEY" + echo "app-id=$APP_ID" >> $GITHUB_OUTPUT + echo "org-membership-token=$ORG_TOKEN" >> $GITHUB_OUTPUT + DELIM="$(openssl rand -hex 8)" + { echo "private-key<<$DELIM"; echo "$PRIVATE_KEY"; echo "$DELIM"; } >> $GITHUB_OUTPUT + + - name: Fetch AI API keys from Secrets Manager + id: ai-api-keys + shell: bash + run: | + set -euo pipefail + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id docker-agent-action/ai-api-keys \ + --query SecretString --output text) + ANTHROPIC_KEY=$(echo "$SECRET" | jq -r '.anthropic_api_key // ""') + OPENAI_KEY=$(echo "$SECRET" | jq -r '.openai_api_key // ""') + [ -n "$ANTHROPIC_KEY" ] && echo "::add-mask::$ANTHROPIC_KEY" + [ -n "$OPENAI_KEY" ] && echo "::add-mask::$OPENAI_KEY" + echo "anthropic-api-key=$ANTHROPIC_KEY" >> $GITHUB_OUTPUT + echo "openai-api-key=$OPENAI_KEY" >> $GITHUB_OUTPUT + # For workflow_run events (fork PRs), download the artifact saved by pr-review-trigger.yml # to get the PR number. For pull_request events, read it directly from the event payload. - name: Get PR number @@ -91,7 +144,7 @@ jobs: id: membership uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: - github-token: ${{ secrets.CAGENT_ORG_MEMBERSHIP_TOKEN }} + github-token: ${{ secrets.CAGENT_ORG_MEMBERSHIP_TOKEN || steps.app-credentials.outputs.org-membership-token }} script: | const org = 'docker'; @@ -153,13 +206,13 @@ jobs: # Generate GitHub App token for custom app identity (optional - falls back to github.token) - name: Generate GitHub App token - if: steps.membership.outputs.is_member == 'true' && env.HAS_APP_SECRETS == 'true' + if: steps.membership.outputs.is_member == 'true' id: app-token continue-on-error: true # Don't fail workflow if token generation fails uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2 with: - app_id: ${{ secrets.CAGENT_REVIEWER_APP_ID }} - private_key: ${{ secrets.CAGENT_REVIEWER_APP_PRIVATE_KEY }} + app_id: ${{ steps.app-credentials.outputs.app-id }} + private_key: ${{ steps.app-credentials.outputs.private-key }} - name: Run PR Review if: steps.membership.outputs.is_member == 'true' @@ -169,8 +222,8 @@ jobs: with: pr-number: ${{ steps.get-pr.outputs.pr-number }} github-token: ${{ steps.app-token.outputs.token || github.token }} - anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} - openai-api-key: ${{ secrets.OPENAI_API_KEY }} + anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY || steps.ai-api-keys.outputs.anthropic-api-key }} + openai-api-key: ${{ secrets.OPENAI_API_KEY || steps.ai-api-keys.outputs.openai-api-key }} google-api-key: ${{ secrets.GOOGLE_API_KEY }} aws-bearer-token-bedrock: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }} xai-api-key: ${{ secrets.XAI_API_KEY }} @@ -188,15 +241,67 @@ jobs: startsWith(github.event.comment.body, '/review') && (github.event.comment.user.type != 'Bot' || github.event.comment.user.login == 'docker-agent[bot]') runs-on: ubuntu-latest - env: - HAS_APP_SECRETS: ${{ secrets.CAGENT_REVIEWER_APP_ID != '' }} steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: TODO_ROLE_ARN + aws-region: us-east-1 + + - name: Fetch GitHub App credentials from Secrets Manager + id: app-credentials + shell: bash + run: | + set -euo pipefail + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id docker-agent-action/github-app \ + --query SecretString --output text) + APP_ID=$(echo "$SECRET" | jq -r .app_id) + ORG_TOKEN=$(echo "$SECRET" | jq -r .org_membership_token) + PRIVATE_KEY=$(echo "$SECRET" | jq -r .private_key) + + if [ -z "$APP_ID" ] || [ "$APP_ID" = "null" ]; then + echo "::error::Failed to extract app_id from secret docker-agent-action/github-app" + exit 1 + fi + if [ -z "$ORG_TOKEN" ] || [ "$ORG_TOKEN" = "null" ]; then + echo "::error::Failed to extract org_membership_token from secret docker-agent-action/github-app" + exit 1 + fi + if [ -z "$PRIVATE_KEY" ] || [ "$PRIVATE_KEY" = "null" ]; then + echo "::error::Failed to extract private_key from secret docker-agent-action/github-app" + exit 1 + fi + + echo "::add-mask::$APP_ID" + echo "::add-mask::$ORG_TOKEN" + echo "::add-mask::$PRIVATE_KEY" + echo "app-id=$APP_ID" >> $GITHUB_OUTPUT + echo "org-membership-token=$ORG_TOKEN" >> $GITHUB_OUTPUT + DELIM="$(openssl rand -hex 8)" + { echo "private-key<<$DELIM"; echo "$PRIVATE_KEY"; echo "$DELIM"; } >> $GITHUB_OUTPUT + + - name: Fetch AI API keys from Secrets Manager + id: ai-api-keys + shell: bash + run: | + set -euo pipefail + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id docker-agent-action/ai-api-keys \ + --query SecretString --output text) + ANTHROPIC_KEY=$(echo "$SECRET" | jq -r '.anthropic_api_key // ""') + OPENAI_KEY=$(echo "$SECRET" | jq -r '.openai_api_key // ""') + [ -n "$ANTHROPIC_KEY" ] && echo "::add-mask::$ANTHROPIC_KEY" + [ -n "$OPENAI_KEY" ] && echo "::add-mask::$OPENAI_KEY" + echo "anthropic-api-key=$ANTHROPIC_KEY" >> $GITHUB_OUTPUT + echo "openai-api-key=$OPENAI_KEY" >> $GITHUB_OUTPUT + - name: Check if commenter is org member id: membership uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: - github-token: ${{ secrets.CAGENT_ORG_MEMBERSHIP_TOKEN }} + github-token: ${{ secrets.CAGENT_ORG_MEMBERSHIP_TOKEN || steps.app-credentials.outputs.org-membership-token }} script: | const org = 'docker'; const username = context.payload.comment.user.login; @@ -235,13 +340,13 @@ jobs: # Generate GitHub App token first so the check run is created under the app's identity # (prevents GitHub from nesting it under unrelated pull_request-triggered workflows) - name: Generate GitHub App token - if: steps.membership.outputs.is_member == 'true' && env.HAS_APP_SECRETS == 'true' + if: steps.membership.outputs.is_member == 'true' id: app-token continue-on-error: true # Don't fail workflow if token generation fails uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2 with: - app_id: ${{ secrets.CAGENT_REVIEWER_APP_ID }} - private_key: ${{ secrets.CAGENT_REVIEWER_APP_PRIVATE_KEY }} + app_id: ${{ steps.app-credentials.outputs.app-id }} + private_key: ${{ steps.app-credentials.outputs.private-key }} - name: Create check run if: steps.membership.outputs.is_member == 'true' @@ -287,9 +392,9 @@ jobs: pr-number: ${{ github.event.issue.number }} comment-id: ${{ github.event.comment.id }} github-token: ${{ steps.app-token.outputs.token || github.token }} - trusted-bot-app-id: ${{ secrets.CAGENT_REVIEWER_APP_ID }} - anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} - openai-api-key: ${{ secrets.OPENAI_API_KEY }} + trusted-bot-app-id: ${{ steps.app-credentials.outputs.app-id }} + anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY || steps.ai-api-keys.outputs.anthropic-api-key }} + openai-api-key: ${{ secrets.OPENAI_API_KEY || steps.ai-api-keys.outputs.openai-api-key }} google-api-key: ${{ secrets.GOOGLE_API_KEY }} aws-bearer-token-bedrock: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }} xai-api-key: ${{ secrets.XAI_API_KEY }}