Skip to content

Commit d950f6c

Browse files
committed
feat: fetch GitHub App credentials from AWS Secrets Manager via OIDC
Replace org-secret lookups with OIDC + Secrets Manager in all reusable consumer-facing workflows. Each affected job now: 1. Assumes the docker-agent-action IAM role via OIDC (id-token: write) 2. Fetches { app_id, private_key, org_membership_token } from the docker-agent-action/github-app Secrets Manager secret 3. Passes those values to downstream steps instead of inherited secrets Affected workflows: - review-pr.yml (auto-review, manual-review, reply-to-feedback jobs) - reply-to-feedback.yml (reply job) - pr-describe.yml (generate-description job) - security-scan.yml (security-scan job) - self-review-pr.yml (auto-review, manual-review jobs) HAS_APP_SECRETS env var changed from dynamic secret check to hardcoded 'true' — credentials are always available via Secrets Manager. Existing secrets: declarations on workflow_call kept as required: false for backward compatibility with consumer repos not yet migrated. TODO_ROLE_ARN must be replaced with the actual IAM role ARN after the Terraform in docker/infra-terraform is applied. Assisted-By: docker-agent refactor: remove HAS_APP_SECRETS — credentials are always available via OIDC Assisted-By: docker-agent
1 parent f954a4b commit d950f6c

5 files changed

Lines changed: 247 additions & 48 deletions

File tree

.github/workflows/pr-describe.yml

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,37 @@ jobs:
1212
# Only run if comment contains /describe and is on a PR
1313
if: ${{ (github.event.issue.pull_request && contains(github.event.comment.body, '/describe')) }}
1414
runs-on: ubuntu-latest
15-
env:
16-
HAS_APP_SECRETS: ${{ secrets.CAGENT_REVIEWER_APP_ID != '' }}
1715
permissions:
1816
contents: read
1917
pull-requests: write
2018
issues: write
2119
checks: write
20+
id-token: write
2221
steps:
22+
- name: Configure AWS credentials
23+
uses: aws-actions/configure-aws-credentials@v4
24+
with:
25+
role-to-assume: TODO_ROLE_ARN
26+
aws-region: us-east-1
27+
28+
- name: Fetch GitHub App credentials from Secrets Manager
29+
id: app-credentials
30+
shell: bash
31+
run: |
32+
SECRET=$(aws secretsmanager get-secret-value \
33+
--secret-id docker-agent-action/github-app \
34+
--query SecretString --output text)
35+
APP_ID=$(echo "$SECRET" | jq -r .app_id)
36+
ORG_TOKEN=$(echo "$SECRET" | jq -r .org_membership_token)
37+
PRIVATE_KEY=$(echo "$SECRET" | jq -r .private_key)
38+
echo "::add-mask::$APP_ID"
39+
echo "::add-mask::$ORG_TOKEN"
40+
echo "::add-mask::$PRIVATE_KEY"
41+
echo "app-id=$APP_ID" >> $GITHUB_OUTPUT
42+
echo "org-membership-token=$ORG_TOKEN" >> $GITHUB_OUTPUT
43+
DELIM="$(openssl rand -hex 8)"
44+
{ echo "private-key<<$DELIM"; echo "$PRIVATE_KEY"; echo "$DELIM"; } >> $GITHUB_OUTPUT
45+
2346
- name: Check out Git repository
2447
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
2548

@@ -48,12 +71,11 @@ jobs:
4871
# Generate GitHub App token so actions appear as the custom app (optional - falls back to github.token)
4972
- name: Get GitHub App token
5073
id: app-token
51-
if: env.HAS_APP_SECRETS == 'true'
5274
continue-on-error: true # Don't fail workflow if token generation fails
5375
uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2
5476
with:
55-
app_id: ${{ secrets.CAGENT_REVIEWER_APP_ID }}
56-
private_key: ${{ secrets.CAGENT_REVIEWER_APP_PRIVATE_KEY }}
77+
app_id: ${{ steps.app-credentials.outputs.app-id }}
78+
private_key: ${{ steps.app-credentials.outputs.private-key }}
5779

5880
- name: Validate PR and add reaction
5981
id: validate_pr

.github/workflows/reply-to-feedback.yml

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,45 @@ permissions:
1919
pull-requests: write
2020
issues: write
2121
actions: read # Required to download artifacts from the triggering run
22+
id-token: write
2223

2324
jobs:
2425
reply:
2526
# Only run if the triggering workflow succeeded (artifact was uploaded)
2627
if: github.event.workflow_run.conclusion == 'success'
2728
runs-on: ubuntu-latest
28-
env:
29-
HAS_APP_SECRETS: ${{ secrets.CAGENT_REVIEWER_APP_ID != '' }}
29+
permissions:
30+
contents: read
31+
pull-requests: write
32+
issues: write
33+
actions: read
34+
id-token: write
3035

3136
steps:
37+
- name: Configure AWS credentials
38+
uses: aws-actions/configure-aws-credentials@v4
39+
with:
40+
role-to-assume: TODO_ROLE_ARN
41+
aws-region: us-east-1
42+
43+
- name: Fetch GitHub App credentials from Secrets Manager
44+
id: app-credentials
45+
shell: bash
46+
run: |
47+
SECRET=$(aws secretsmanager get-secret-value \
48+
--secret-id docker-agent-action/github-app \
49+
--query SecretString --output text)
50+
APP_ID=$(echo "$SECRET" | jq -r .app_id)
51+
ORG_TOKEN=$(echo "$SECRET" | jq -r .org_membership_token)
52+
PRIVATE_KEY=$(echo "$SECRET" | jq -r .private_key)
53+
echo "::add-mask::$APP_ID"
54+
echo "::add-mask::$ORG_TOKEN"
55+
echo "::add-mask::$PRIVATE_KEY"
56+
echo "app-id=$APP_ID" >> $GITHUB_OUTPUT
57+
echo "org-membership-token=$ORG_TOKEN" >> $GITHUB_OUTPUT
58+
DELIM="$(openssl rand -hex 8)"
59+
{ echo "private-key<<$DELIM"; echo "$PRIVATE_KEY"; echo "$DELIM"; } >> $GITHUB_OUTPUT
60+
3261
# ----------------------------------------------------------------
3362
# Download artifact from the triggering workflow run
3463
# ----------------------------------------------------------------
@@ -157,7 +186,7 @@ jobs:
157186
env:
158187
USERNAME: ${{ steps.meta.outputs.author }}
159188
with:
160-
github-token: ${{ secrets.CAGENT_ORG_MEMBERSHIP_TOKEN }}
189+
github-token: ${{ steps.app-credentials.outputs.org-membership-token }}
161190
script: |
162191
const org = 'docker';
163192
const username = process.env.USERNAME;
@@ -301,13 +330,13 @@ jobs:
301330
ref: refs/pull/${{ steps.meta.outputs.pr_number }}/head
302331

303332
- name: Generate GitHub App token
304-
if: steps.meta.outputs.proceed == 'true' && steps.auth.outputs.authorized == 'true' && env.HAS_APP_SECRETS == 'true'
333+
if: steps.meta.outputs.proceed == 'true' && steps.auth.outputs.authorized == 'true'
305334
id: app-token
306335
continue-on-error: true
307336
uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2
308337
with:
309-
app_id: ${{ secrets.CAGENT_REVIEWER_APP_ID }}
310-
private_key: ${{ secrets.CAGENT_REVIEWER_APP_PRIVATE_KEY }}
338+
app_id: ${{ steps.app-credentials.outputs.app-id }}
339+
private_key: ${{ steps.app-credentials.outputs.private-key }}
311340

312341
- name: Run reply
313342
if: steps.meta.outputs.proceed == 'true' && steps.auth.outputs.authorized == 'true' && steps.checkout.outcome == 'success' && steps.thread.outcome == 'success'

.github/workflows/review-pr.yml

Lines changed: 100 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,39 @@ jobs:
124124
inputs.pr-number != ''
125125
)
126126
runs-on: ubuntu-latest
127-
env:
128-
HAS_APP_SECRETS: ${{ secrets.CAGENT_REVIEWER_APP_ID != '' }}
127+
permissions:
128+
contents: read
129+
pull-requests: write
130+
issues: write
131+
id-token: write
129132
outputs:
130133
exit-code: ${{ steps.run-review.outputs.exit-code }}
131134

132135
steps:
136+
- name: Configure AWS credentials
137+
uses: aws-actions/configure-aws-credentials@v4
138+
with:
139+
role-to-assume: TODO_ROLE_ARN
140+
aws-region: us-east-1
141+
142+
- name: Fetch GitHub App credentials from Secrets Manager
143+
id: app-credentials
144+
shell: bash
145+
run: |
146+
SECRET=$(aws secretsmanager get-secret-value \
147+
--secret-id docker-agent-action/github-app \
148+
--query SecretString --output text)
149+
APP_ID=$(echo "$SECRET" | jq -r .app_id)
150+
ORG_TOKEN=$(echo "$SECRET" | jq -r .org_membership_token)
151+
PRIVATE_KEY=$(echo "$SECRET" | jq -r .private_key)
152+
echo "::add-mask::$APP_ID"
153+
echo "::add-mask::$ORG_TOKEN"
154+
echo "::add-mask::$PRIVATE_KEY"
155+
echo "app-id=$APP_ID" >> $GITHUB_OUTPUT
156+
echo "org-membership-token=$ORG_TOKEN" >> $GITHUB_OUTPUT
157+
DELIM="$(openssl rand -hex 8)"
158+
{ echo "private-key<<$DELIM"; echo "$PRIVATE_KEY"; echo "$DELIM"; } >> $GITHUB_OUTPUT
159+
133160
- name: Get PR number
134161
id: get-pr
135162
shell: bash
@@ -167,7 +194,7 @@ jobs:
167194
PR_DRAFT: ${{ steps.pr-info.outputs.draft }}
168195
PR_AUTHOR: ${{ steps.pr-info.outputs.author }}
169196
with:
170-
github-token: ${{ secrets.CAGENT_ORG_MEMBERSHIP_TOKEN }}
197+
github-token: ${{ steps.app-credentials.outputs.org-membership-token }}
171198
script: |
172199
const org = '${{ inputs.auto-review-org }}';
173200
@@ -216,13 +243,13 @@ jobs:
216243

217244
# Generate GitHub App token for custom app identity (optional - falls back to github.token)
218245
- name: Generate GitHub App token
219-
if: steps.membership.outputs.is_member == 'true' && env.HAS_APP_SECRETS == 'true'
246+
if: steps.membership.outputs.is_member == 'true'
220247
id: app-token
221248
continue-on-error: true # Don't fail workflow if token generation fails
222249
uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2
223250
with:
224-
app_id: ${{ secrets.CAGENT_REVIEWER_APP_ID }}
225-
private_key: ${{ secrets.CAGENT_REVIEWER_APP_PRIVATE_KEY }}
251+
app_id: ${{ steps.app-credentials.outputs.app-id }}
252+
private_key: ${{ steps.app-credentials.outputs.private-key }}
226253

227254
- name: Run PR Review
228255
if: steps.membership.outputs.is_member == 'true'
@@ -254,17 +281,44 @@ jobs:
254281
startsWith(github.event.comment.body, '/review') &&
255282
(github.event.comment.user.type != 'Bot' || github.event.comment.user.login == 'docker-agent[bot]')
256283
runs-on: ubuntu-latest
257-
env:
258-
HAS_APP_SECRETS: ${{ secrets.CAGENT_REVIEWER_APP_ID != '' }}
284+
permissions:
285+
contents: read
286+
pull-requests: write
287+
issues: write
288+
id-token: write
259289
outputs:
260290
exit-code: ${{ steps.run-review.outputs.exit-code }}
261291

262292
steps:
293+
- name: Configure AWS credentials
294+
uses: aws-actions/configure-aws-credentials@v4
295+
with:
296+
role-to-assume: TODO_ROLE_ARN
297+
aws-region: us-east-1
298+
299+
- name: Fetch GitHub App credentials from Secrets Manager
300+
id: app-credentials
301+
shell: bash
302+
run: |
303+
SECRET=$(aws secretsmanager get-secret-value \
304+
--secret-id docker-agent-action/github-app \
305+
--query SecretString --output text)
306+
APP_ID=$(echo "$SECRET" | jq -r .app_id)
307+
ORG_TOKEN=$(echo "$SECRET" | jq -r .org_membership_token)
308+
PRIVATE_KEY=$(echo "$SECRET" | jq -r .private_key)
309+
echo "::add-mask::$APP_ID"
310+
echo "::add-mask::$ORG_TOKEN"
311+
echo "::add-mask::$PRIVATE_KEY"
312+
echo "app-id=$APP_ID" >> $GITHUB_OUTPUT
313+
echo "org-membership-token=$ORG_TOKEN" >> $GITHUB_OUTPUT
314+
DELIM="$(openssl rand -hex 8)"
315+
{ echo "private-key<<$DELIM"; echo "$PRIVATE_KEY"; echo "$DELIM"; } >> $GITHUB_OUTPUT
316+
263317
- name: Check if commenter is org member
264318
id: membership
265319
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
266320
with:
267-
github-token: ${{ secrets.CAGENT_ORG_MEMBERSHIP_TOKEN }}
321+
github-token: ${{ steps.app-credentials.outputs.org-membership-token }}
268322
script: |
269323
const org = '${{ inputs.auto-review-org }}';
270324
const username = context.payload.comment.user.login;
@@ -303,13 +357,13 @@ jobs:
303357
# Generate GitHub App token first so the check run is created under the app's identity
304358
# (prevents GitHub from nesting it under unrelated pull_request-triggered workflows)
305359
- name: Generate GitHub App token
306-
if: steps.membership.outputs.is_member == 'true' && env.HAS_APP_SECRETS == 'true'
360+
if: steps.membership.outputs.is_member == 'true'
307361
id: app-token
308362
continue-on-error: true # Don't fail workflow if token generation fails
309363
uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2
310364
with:
311-
app_id: ${{ secrets.CAGENT_REVIEWER_APP_ID }}
312-
private_key: ${{ secrets.CAGENT_REVIEWER_APP_PRIVATE_KEY }}
365+
app_id: ${{ steps.app-credentials.outputs.app-id }}
366+
private_key: ${{ steps.app-credentials.outputs.private-key }}
313367

314368
- name: Create check run
315369
if: steps.membership.outputs.is_member == 'true'
@@ -358,7 +412,7 @@ jobs:
358412
add-prompt-files: ${{ inputs.add-prompt-files }}
359413
model: ${{ inputs.model }}
360414
github-token: ${{ steps.app-token.outputs.token || github.token }}
361-
trusted-bot-app-id: ${{ secrets.CAGENT_REVIEWER_APP_ID }}
415+
trusted-bot-app-id: ${{ steps.app-credentials.outputs.app-id }}
362416
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
363417
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
364418
google-api-key: ${{ secrets.GOOGLE_API_KEY }}
@@ -455,10 +509,37 @@ jobs:
455509
github.event.comment.in_reply_to_id &&
456510
github.event.comment.user.type != 'Bot'
457511
runs-on: ubuntu-latest
458-
env:
459-
HAS_APP_SECRETS: ${{ secrets.CAGENT_REVIEWER_APP_ID != '' }}
512+
permissions:
513+
contents: read
514+
pull-requests: write
515+
issues: write
516+
id-token: write
460517

461518
steps:
519+
- name: Configure AWS credentials
520+
uses: aws-actions/configure-aws-credentials@v4
521+
with:
522+
role-to-assume: TODO_ROLE_ARN
523+
aws-region: us-east-1
524+
525+
- name: Fetch GitHub App credentials from Secrets Manager
526+
id: app-credentials
527+
shell: bash
528+
run: |
529+
SECRET=$(aws secretsmanager get-secret-value \
530+
--secret-id docker-agent-action/github-app \
531+
--query SecretString --output text)
532+
APP_ID=$(echo "$SECRET" | jq -r .app_id)
533+
ORG_TOKEN=$(echo "$SECRET" | jq -r .org_membership_token)
534+
PRIVATE_KEY=$(echo "$SECRET" | jq -r .private_key)
535+
echo "::add-mask::$APP_ID"
536+
echo "::add-mask::$ORG_TOKEN"
537+
echo "::add-mask::$PRIVATE_KEY"
538+
echo "app-id=$APP_ID" >> $GITHUB_OUTPUT
539+
echo "org-membership-token=$ORG_TOKEN" >> $GITHUB_OUTPUT
540+
DELIM="$(openssl rand -hex 8)"
541+
{ echo "private-key<<$DELIM"; echo "$PRIVATE_KEY"; echo "$DELIM"; } >> $GITHUB_OUTPUT
542+
462543
- name: Check if reply is to agent comment
463544
id: check
464545
shell: bash
@@ -526,7 +607,7 @@ jobs:
526607
id: auth
527608
shell: bash
528609
env:
529-
GH_TOKEN: ${{ secrets.CAGENT_ORG_MEMBERSHIP_TOKEN }}
610+
GH_TOKEN: ${{ steps.app-credentials.outputs.org-membership-token }}
530611
ORG: ${{ inputs.auto-review-org }}
531612
USERNAME: ${{ github.event.comment.user.login }}
532613
run: |
@@ -682,13 +763,13 @@ jobs:
682763

683764
# Generate GitHub App token for custom app identity (optional - falls back to github.token)
684765
- name: Generate GitHub App token
685-
if: steps.check.outputs.is_agent == 'true' && steps.auth.outputs.authorized == 'true' && env.HAS_APP_SECRETS == 'true'
766+
if: steps.check.outputs.is_agent == 'true' && steps.auth.outputs.authorized == 'true'
686767
id: app-token
687768
continue-on-error: true
688769
uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2
689770
with:
690-
app_id: ${{ secrets.CAGENT_REVIEWER_APP_ID }}
691-
private_key: ${{ secrets.CAGENT_REVIEWER_APP_PRIVATE_KEY }}
771+
app_id: ${{ steps.app-credentials.outputs.app-id }}
772+
private_key: ${{ steps.app-credentials.outputs.private-key }}
692773

693774
- name: Run reply
694775
if: steps.check.outputs.is_agent == 'true' && steps.auth.outputs.authorized == 'true'

.github/workflows/security-scan.yml

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,35 @@ jobs:
1919
security-scan:
2020
name: Security Scan with Docker Agent
2121
runs-on: ubuntu-latest
22-
env:
23-
HAS_APP_SECRETS: ${{ secrets.CAGENT_REVIEWER_APP_ID != '' }}
2422
permissions:
2523
contents: read
2624
issues: write
25+
id-token: write
2726
steps:
27+
- name: Configure AWS credentials
28+
uses: aws-actions/configure-aws-credentials@v4
29+
with:
30+
role-to-assume: TODO_ROLE_ARN
31+
aws-region: us-east-1
32+
33+
- name: Fetch GitHub App credentials from Secrets Manager
34+
id: app-credentials
35+
shell: bash
36+
run: |
37+
SECRET=$(aws secretsmanager get-secret-value \
38+
--secret-id docker-agent-action/github-app \
39+
--query SecretString --output text)
40+
APP_ID=$(echo "$SECRET" | jq -r .app_id)
41+
ORG_TOKEN=$(echo "$SECRET" | jq -r .org_membership_token)
42+
PRIVATE_KEY=$(echo "$SECRET" | jq -r .private_key)
43+
echo "::add-mask::$APP_ID"
44+
echo "::add-mask::$ORG_TOKEN"
45+
echo "::add-mask::$PRIVATE_KEY"
46+
echo "app-id=$APP_ID" >> $GITHUB_OUTPUT
47+
echo "org-membership-token=$ORG_TOKEN" >> $GITHUB_OUTPUT
48+
DELIM="$(openssl rand -hex 8)"
49+
{ echo "private-key<<$DELIM"; echo "$PRIVATE_KEY"; echo "$DELIM"; } >> $GITHUB_OUTPUT
50+
2851
- name: Check out Git repository
2952
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
3053
with:
@@ -33,12 +56,11 @@ jobs:
3356
# Generate GitHub App token so issues appear as the custom app (optional - falls back to github.token)
3457
- name: Get GitHub App token
3558
id: app-token
36-
if: env.HAS_APP_SECRETS == 'true'
3759
continue-on-error: true # Don't fail workflow if token generation fails
3860
uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2
3961
with:
40-
app_id: ${{ secrets.CAGENT_REVIEWER_APP_ID }}
41-
private_key: ${{ secrets.CAGENT_REVIEWER_APP_PRIVATE_KEY }}
62+
app_id: ${{ steps.app-credentials.outputs.app-id }}
63+
private_key: ${{ steps.app-credentials.outputs.private-key }}
4264

4365
- name: Get commits from past week
4466
id: commits

0 commit comments

Comments
 (0)