Skip to content

Commit 1cdb8b9

Browse files
feat(ci): migrate 6 workflows from SA key auth to Workload Identity Federation
Replace GCS_CREDENTIALS service account key with WIF (google-github-actions/auth@v2 + workload_identity_provider) across all GCP-authenticated workflows. Removes inline key file creation and gcloud activate-service-account patterns. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 0c5ccf8 commit 1cdb8b9

File tree

7 files changed

+52
-42
lines changed

7 files changed

+52
-42
lines changed

.github/workflows/ci-tests.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ jobs:
2626
runs-on: ubuntu-latest
2727
permissions:
2828
contents: read
29+
id-token: write # Required for Workload Identity Federation
2930

3031
env:
3132
ENVIRONMENT: test
@@ -85,11 +86,12 @@ jobs:
8586
if: steps.check.outputs.should_test == 'true'
8687
run: uv sync --extra test
8788

88-
- name: Setup GCP authentication
89+
- name: Authenticate to GCP
8990
if: steps.check.outputs.should_test == 'true'
90-
uses: google-github-actions/auth@v3
91+
uses: google-github-actions/auth@v2
9192
with:
92-
credentials_json: ${{ secrets.GCS_CREDENTIALS }}
93+
project_id: anyplot
94+
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
9395

9496
- name: Start Cloud SQL Proxy
9597
if: steps.check.outputs.should_test == 'true'

.github/workflows/impl-generate.yml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -511,28 +511,28 @@ jobs:
511511
# ========================================================================
512512
# Upload to GCS Staging
513513
# ========================================================================
514+
- name: Authenticate to GCP
515+
if: steps.pr.outputs.pr_exists == 'true'
516+
uses: google-github-actions/auth@v2
517+
with:
518+
project_id: anyplot
519+
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
520+
521+
- name: Set up Cloud SDK
522+
if: steps.pr.outputs.pr_exists == 'true'
523+
uses: google-github-actions/setup-gcloud@v2
524+
514525
- name: Upload to GCS Staging
515526
id: gcs
516527
if: steps.pr.outputs.pr_exists == 'true'
517528
env:
518-
GCS_CREDENTIALS: ${{ secrets.GCS_CREDENTIALS }}
519529
SPEC_ID: ${{ steps.inputs.outputs.specification_id }}
520530
LIBRARY: ${{ steps.inputs.outputs.library }}
521531
run: |
522532
IMPL_DIR="plots/${SPEC_ID}/implementations"
523533
STAGING_PATH="gs://anyplot-images/staging/${SPEC_ID}/${LIBRARY}"
524534
PUBLIC_URL="https://storage.googleapis.com/anyplot-images/staging/${SPEC_ID}/${LIBRARY}"
525535
526-
if [ -z "$GCS_CREDENTIALS" ]; then
527-
echo "::warning::GCS_CREDENTIALS not configured - skipping upload"
528-
echo "uploaded=false" >> $GITHUB_OUTPUT
529-
exit 0
530-
fi
531-
532-
# Authenticate
533-
echo "$GCS_CREDENTIALS" > /tmp/gcs-key.json
534-
gcloud auth activate-service-account --key-file=/tmp/gcs-key.json
535-
536536
# Upload all plot images (original + responsive variants)
537537
if [ -f "$IMPL_DIR/plot.png" ]; then
538538
gsutil -m -h "Cache-Control:public, max-age=604800" cp "$IMPL_DIR"/plot*.png "$IMPL_DIR"/plot*.webp "${STAGING_PATH}/"

.github/workflows/impl-merge.yml

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ jobs:
2222
pull-requests: write
2323
issues: write
2424
actions: write # Required for gh workflow run sync-postgres.yml
25+
id-token: write # Required for Workload Identity Federation
2526

2627
steps:
2728
- name: Check conditions
@@ -182,21 +183,23 @@ jobs:
182183
# Note: quality_score is now set by impl-review.yml before merge
183184
# The PR already contains the updated metadata when merged
184185

186+
- name: Authenticate to GCP
187+
if: steps.check.outputs.should_run == 'true'
188+
uses: google-github-actions/auth@v2
189+
with:
190+
project_id: anyplot
191+
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
192+
193+
- name: Set up Cloud SDK
194+
if: steps.check.outputs.should_run == 'true'
195+
uses: google-github-actions/setup-gcloud@v2
196+
185197
- name: Promote GCS images to production
186198
if: steps.check.outputs.should_run == 'true'
187199
env:
188-
GCS_CREDENTIALS: ${{ secrets.GCS_CREDENTIALS }}
189200
SPEC_ID: ${{ steps.extract.outputs.specification_id }}
190201
LIBRARY: ${{ steps.extract.outputs.library }}
191202
run: |
192-
if [ -z "$GCS_CREDENTIALS" ]; then
193-
echo "::warning::GCS_CREDENTIALS not configured - skipping promotion"
194-
exit 0
195-
fi
196-
197-
echo "$GCS_CREDENTIALS" > /tmp/gcs-key.json
198-
gcloud auth activate-service-account --key-file=/tmp/gcs-key.json
199-
200203
STAGING="gs://anyplot-images/staging/${SPEC_ID}/${LIBRARY}"
201204
PRODUCTION="gs://anyplot-images/plots/${SPEC_ID}/${LIBRARY}"
202205

.github/workflows/impl-repair.yml

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -170,24 +170,26 @@ jobs:
170170
echo "::notice::Processed images: optimized + responsive variants created"
171171
ls -la "$IMPL_DIR/"
172172
173+
- name: Authenticate to GCP
174+
if: success()
175+
uses: google-github-actions/auth@v2
176+
with:
177+
project_id: anyplot
178+
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
179+
180+
- name: Set up Cloud SDK
181+
if: success()
182+
uses: google-github-actions/setup-gcloud@v2
183+
173184
- name: Upload repaired plot to GCS staging
174185
if: success()
175186
env:
176-
GCS_CREDENTIALS: ${{ secrets.GCS_CREDENTIALS }}
177187
SPEC_ID: ${{ inputs.specification_id }}
178188
LIBRARY: ${{ inputs.library }}
179189
run: |
180190
IMPL_DIR="plots/${SPEC_ID}/implementations"
181191
STAGING_PATH="gs://anyplot-images/staging/${SPEC_ID}/${LIBRARY}"
182192
183-
if [ -z "$GCS_CREDENTIALS" ]; then
184-
echo "::warning::GCS_CREDENTIALS not configured"
185-
exit 0
186-
fi
187-
188-
echo "$GCS_CREDENTIALS" > /tmp/gcs-key.json
189-
gcloud auth activate-service-account --key-file=/tmp/gcs-key.json
190-
191193
# Upload all plot images (original + responsive variants)
192194
if [ -f "$IMPL_DIR/plot.png" ]; then
193195
gsutil -m -h "Cache-Control:public, max-age=604800" cp "$IMPL_DIR"/plot*.png "$IMPL_DIR"/plot*.webp "${STAGING_PATH}/"

.github/workflows/impl-review.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,13 @@ jobs:
8585
echo "display=1" >> $GITHUB_OUTPUT
8686
fi
8787
88-
- name: Setup GCS authentication
88+
- name: Authenticate to GCP
8989
id: gcs
9090
continue-on-error: true
91-
uses: google-github-actions/auth@v3
91+
uses: google-github-actions/auth@v2
9292
with:
93-
credentials_json: ${{ secrets.GCS_CREDENTIALS }}
93+
project_id: anyplot
94+
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
9495

9596
- name: Setup gcloud CLI
9697
if: steps.gcs.outcome == 'success'

.github/workflows/sync-postgres.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ jobs:
2727
runs-on: ubuntu-latest
2828
permissions:
2929
contents: read
30+
id-token: write # Required for Workload Identity Federation
3031

3132
steps:
3233
- uses: actions/checkout@v6
@@ -43,10 +44,11 @@ jobs:
4344
run: |
4445
uv sync
4546
46-
- name: Setup GCP authentication
47-
uses: google-github-actions/auth@v3
47+
- name: Authenticate to GCP
48+
uses: google-github-actions/auth@v2
4849
with:
49-
credentials_json: ${{ secrets.GCS_CREDENTIALS }}
50+
project_id: anyplot
51+
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
5052

5153
- name: Run database migrations
5254
run: |

.serena/memories/project_overview.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
# pyplots - Project Overview
1+
# anyplot - Project Overview
22

33
## Purpose
4-
**pyplots** is an AI-powered platform for Python data visualization that automatically discovers, generates, tests, and maintains plotting examples across 9 major libraries. Community proposes plot ideas via GitHub Issues → AI generates code → AI quality review → Deployed.
4+
**anyplot** is an AI-powered platform for Python data visualization that automatically discovers, generates, tests, and maintains plotting examples across 9 major libraries. Community proposes plot ideas via GitHub Issues → AI generates code → AI quality review → Deployed.
55

66
## Supported Libraries (9)
77
matplotlib, seaborn, plotly, bokeh, altair, plotnine, pygal, highcharts, lets-plot
@@ -16,7 +16,7 @@ matplotlib, seaborn, plotly, bokeh, altair, plotnine, pygal, highcharts, lets-pl
1616

1717
## Directory Structure
1818
```
19-
pyplots/
19+
anyplot/
2020
├── api/ # FastAPI backend
2121
│ ├── main.py # App factory, CORS, lifespan
2222
│ ├── routers/ # health, specs, libraries, images, plots, stats,
@@ -125,4 +125,4 @@ pyplots/
125125
2. `approved` label on Issue → spec merges, gets `spec-ready` label
126126
3. `bulk-generate.yml``impl-generate.yml``impl-review.yml``impl-merge.yml`
127127
4. `sync-postgres.yml` syncs filesystem to PostgreSQL on push to main
128-
5. FastAPI serves data, React frontend displays gallery at pyplots.ai
128+
5. FastAPI serves data, React frontend displays gallery at anyplot.ai

0 commit comments

Comments
 (0)