fix(ci): grant required permissions to reusable workflow callers#21
Conversation
Every push to develop and main has failed with startup_failure since the permission hardening on May 20 (7b5fe03). GitHub validates a called reusable workflow's declared permissions against the caller job's grant at plan time; any shortfall kills the run before jobs are scheduled, which is why no logs were produced and no releases were cut. Align each caller job's permissions with what the shared workflows at v1.33.0 declare: go-pr-analysis needs pull-requests and security-events write (CodeQL SARIF upload and PR comments), pr-validation needs pull-requests and issues write, and pr-security-scan needs actions read, id-token write, and pull-requests write. Permissions stay scoped at the job level so the least-privilege intent of the hardening is preserved. X-Lerian-Ref: 0x1
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughJob-level GitHub token permissions are expanded in four workflows: ChangesWorkflow Job Permission Scoping
Comment |
🔍 PR Validation Summary✅ PR Mergeable — no blocking failures
|
The shared pr-security-scan workflow logs into docker.io during prepare_matrix, which requires registry credentials from org secrets. The May 20 hardening removed secrets: inherit from the caller, so the login step failed with 'Username and password required'. Restore inheritance; permissions remain scoped at the job level. X-Lerian-Ref: 0x1
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
📊 Unit Test Coverage Report:
|
| Metric | Value |
|---|---|
| Overall Coverage | 82.6% ✅ PASS |
| Threshold | 80% |
Coverage by Package
| Package | Coverage |
|---|---|
github.com/LerianStudio/lib-streaming/internal/cloudevents |
92.1% |
github.com/LerianStudio/lib-streaming/internal/config |
83.7% |
github.com/LerianStudio/lib-streaming/internal/contract |
81.1% |
github.com/LerianStudio/lib-streaming/internal/emitter |
100.0% |
github.com/LerianStudio/lib-streaming/internal/manifest |
83.0% |
github.com/LerianStudio/lib-streaming/internal/producer |
85.6% |
github.com/LerianStudio/lib-streaming/internal/transport/eventbridge |
87.3% |
github.com/LerianStudio/lib-streaming/internal/transport/kafka |
60.1% |
github.com/LerianStudio/lib-streaming/internal/transport/rabbitmq |
93.2% |
github.com/LerianStudio/lib-streaming/internal/transport/sqs |
84.4% |
github.com/LerianStudio/lib-streaming/internal/transport |
95.0% |
github.com/LerianStudio/lib-streaming/streamingtest |
90.7% |
github.com/LerianStudio/lib-streaming |
63.4% |
Generated by Go PR Analysis workflow
🔒 Security Scan Results —
|
| Stage | Status | Blocking? |
|---|---|---|
| Filesystem Scan | ✅ Clean | — |
| Docker Image Scan | ➖ Skipped | — |
| Docker Hub Health Score | ➖ Skipped | — |
| Pre-release Version Check | ✅ Clean | — |
Trivy
Filesystem Scan
✅ No vulnerabilities or secrets found.
Pre-release Version Check
✅ No unstable version pins found.
The shared release workflow mints a GitHub App token from LERIAN_STUDIO_MIDAZ_PUSH_BOT_APP_ID/_PRIVATE_KEY org secrets, which never reach the called workflow without secrets: inherit on the caller job. The May 20 hardening kept inheritance on pre-release-validation but dropped it from the release job, so semantic-release failed with an empty client-id before publishing anything. X-Lerian-Ref: 0x1
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/pr-security-scan.yml:
- Line 43: The shared workflow runs docker/login-action unconditionally in the
prepare_matrix and security_scan jobs causing forked PRs to fail; modify the
steps that call docker/login-action to include an if guard so the login only
runs when secrets are available or the run is not a forked pull_request (e.g.
add an if: condition that checks secrets.DOCKER_USERNAME and
secrets.DOCKERHUB_IMAGE_PULL_TOKEN are set or use an if: that allows execution
only when github.event_name != 'pull_request' or when github.repository ==
github.event.pull_request.head.repo.full_name), updating both occurrences of
docker/login-action to use this guard.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 7467a28a-63f8-41ca-a882-37948a96dd75
📒 Files selected for processing (1)
.github/workflows/pr-security-scan.yml
| uses: LerianStudio/github-actions-shared-workflows/.github/workflows/pr-security-scan.yml@v1.33.0 | ||
| with: | ||
| enable_docker_scan: false | ||
| secrets: inherit |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
tmp="$(mktemp)"
curl -fsSL \
https://raw.githubusercontent.com/LerianStudio/github-actions-shared-workflows/v1.33.0/.github/workflows/pr-security-scan.yml \
-o "$tmp"
echo "== Relevant lines from shared workflow =="
rg -n -i -C3 'docker\.io|docker/login-action|username|password|secrets\.|if:' "$tmp" || true
echo
echo "== First 260 lines for manual inspection =="
nl -ba "$tmp" | sed -n '1,260p'Repository: LerianStudio/lib-streaming
Length of output: 8368
🏁 Script executed:
#!/bin/bash
set -euo pipefail
tmp="$(mktemp)"
curl -fsSL \
https://raw.githubusercontent.com/LerianStudio/github-actions-shared-workflows/v1.33.0/.github/workflows/pr-security-scan.yml \
-o "$tmp"
echo "== Login steps (context) =="
awk 'NR>=110 && NR<=190 {printf "%5d:%s\n", NR, $0}' "$tmp"
echo
echo "== Search for guards around docker/login-action / docker hub creds =="
rg -n -i 'docker/login-action|DOCKERHUB_IMAGE_PULL_TOKEN|DOCKER_USERNAME|if:.*DOCKER|if:.*docker|secrets\.DOCKER_' "$tmp" || trueRepository: LerianStudio/lib-streaming
Length of output: 4552
Fork PRs may still fail due to unguarded Docker Hub login in the shared workflow
In LerianStudio/github-actions-shared-workflows v1.33.0, docker/login-action runs unconditionally in both prepare_matrix and security_scan using username: ${{ secrets.DOCKER_USERNAME }} and password: ${{ secrets.DOCKERHUB_IMAGE_PULL_TOKEN }} with no if: guard. Forked pull_request runs won’t have those secrets even with secrets: inherit at Line 43, so the workflow can still fail at the login step.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/pr-security-scan.yml at line 43, The shared workflow runs
docker/login-action unconditionally in the prepare_matrix and security_scan jobs
causing forked PRs to fail; modify the steps that call docker/login-action to
include an if guard so the login only runs when secrets are available or the run
is not a forked pull_request (e.g. add an if: condition that checks
secrets.DOCKER_USERNAME and secrets.DOCKERHUB_IMAGE_PULL_TOKEN are set or use an
if: that allows execution only when github.event_name != 'pull_request' or when
github.repository == github.event.pull_request.head.repo.full_name), updating
both occurrences of docker/login-action to use this guard.
What
Restores CI/CD on this repository. Every push to
developandmainhas failed withstartup_failuresince the permission hardening of May 20 (7b5fe03) — including the Release workflow, which is why no release has been cut sincev1.5.1.Why it broke
GitHub validates a called reusable workflow's declared permissions against the caller job's grant at plan time. Any shortfall kills the entire run in ~1s, before any job is scheduled — no logs, just
startup_failure. The hardening dropped caller grants below what the shared workflows atv1.33.0declare.Fix
Align each caller job's permissions with the corresponding shared workflow declaration, keeping grants at the job level (least-privilege intent preserved):
release.yml(pre-release-validation)pull-requests: write,security-events: writego-combined-analysis.ymlcontents: read,pull-requests: write,security-events: write(job-level)pr-validation.ymlpull-requests: write,issues: writepr-security-scan.ymlactions: read,id-token: write,pull-requests: writeImpact
Merging to
mainre-triggers the Release workflow, which will pick up everything unreleased sincev1.5.1(root API facade, MongoDB driver v2, dependency bumps) and cut the next release.