fix(ci): use env scope for secrets in gating if: expressions (#431)
GitHub Actions does not allow `secrets.X` to appear directly in
step-level `if:` expressions — only `env.X` is valid in that context.
Both ci.yml and security-scan.yml had Slack-notify steps gated on
`secrets.SLACK_WEBHOOK_URL != ''`, which made the entire workflow
fail to parse. Result: every push to main produced a 0-second failure
with 0 jobs run, masquerading as a CI signal that wasn't actually
running CI.
Confirmed root cause via:
gh api -X POST repos/.../actions/workflows/167079093/dispatches \
-f ref=main
→ 422 Invalid Argument - failed to parse workflow:
(Line: 315, Col: 11): Unrecognized named-value: 'secrets'
Fix: promote the secret to job-level `env:` so step-level `if:`
references `env.SLACK_WEBHOOK_URL`. The actual secret value still
flows through unchanged for the action's runtime use.
Same pattern applied to security-scan.yml line 406 (the existing
SECURITY_SLACK_WEBHOOK_URL gate).
After this lands, every push to main should produce real CI runs
that actually execute jobs and reflect repo health honestly. The
runs may still fail for *real* reasons (e.g., CI image dependencies,
test gaps), but they will fail visibly with logs instead of in 0s
with no jobs.
This commit is contained in:
parent
5bcb25b2b0
commit
74233cfb23
|
|
@ -310,26 +310,27 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [code-quality, test, rust-tests, performance-test, docker-build, docs]
|
needs: [code-quality, test, rust-tests, performance-test, docker-build, docs]
|
||||||
if: always()
|
if: always()
|
||||||
|
# GitHub Actions does not allow `secrets.X` directly in step-level `if:`
|
||||||
|
# expressions — only `env.X`. Promote the secret to env at job scope so
|
||||||
|
# the gating expression below is parseable.
|
||||||
|
env:
|
||||||
|
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||||
steps:
|
steps:
|
||||||
- name: Notify Slack on success
|
- name: Notify Slack on success
|
||||||
if: ${{ secrets.SLACK_WEBHOOK_URL != '' && needs.code-quality.result == 'success' && needs.test.result == 'success' && needs.docker-build.result == 'success' }}
|
if: ${{ env.SLACK_WEBHOOK_URL != '' && needs.code-quality.result == 'success' && needs.test.result == 'success' && needs.docker-build.result == 'success' }}
|
||||||
uses: 8398a7/action-slack@v3
|
uses: 8398a7/action-slack@v3
|
||||||
with:
|
with:
|
||||||
status: success
|
status: success
|
||||||
channel: '#ci-cd'
|
channel: '#ci-cd'
|
||||||
text: '✅ CI pipeline completed successfully for ${{ github.ref }}'
|
text: '✅ CI pipeline completed successfully for ${{ github.ref }}'
|
||||||
env:
|
|
||||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
||||||
|
|
||||||
- name: Notify Slack on failure
|
- name: Notify Slack on failure
|
||||||
if: ${{ secrets.SLACK_WEBHOOK_URL != '' && (needs.code-quality.result == 'failure' || needs.test.result == 'failure' || needs.docker-build.result == 'failure') }}
|
if: ${{ env.SLACK_WEBHOOK_URL != '' && (needs.code-quality.result == 'failure' || needs.test.result == 'failure' || needs.docker-build.result == 'failure') }}
|
||||||
uses: 8398a7/action-slack@v3
|
uses: 8398a7/action-slack@v3
|
||||||
with:
|
with:
|
||||||
status: failure
|
status: failure
|
||||||
channel: '#ci-cd'
|
channel: '#ci-cd'
|
||||||
text: '❌ CI pipeline failed for ${{ github.ref }}'
|
text: '❌ CI pipeline failed for ${{ github.ref }}'
|
||||||
env:
|
|
||||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
||||||
|
|
||||||
- name: Create GitHub Release
|
- name: Create GitHub Release
|
||||||
if: github.ref == 'refs/heads/main' && needs.docker-build.result == 'success'
|
if: github.ref == 'refs/heads/main' && needs.docker-build.result == 'success'
|
||||||
|
|
|
||||||
|
|
@ -377,6 +377,11 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [sast, dependency-scan, container-scan, iac-scan, secret-scan, license-scan, compliance-check]
|
needs: [sast, dependency-scan, container-scan, iac-scan, secret-scan, license-scan, compliance-check]
|
||||||
if: always()
|
if: always()
|
||||||
|
# Promote secret to env-scope so the gating `if:` on the Slack-notify
|
||||||
|
# step below is parseable (GitHub Actions rejects `secrets.X` in
|
||||||
|
# step-level `if:` expressions).
|
||||||
|
env:
|
||||||
|
SECURITY_SLACK_WEBHOOK_URL: ${{ secrets.SECURITY_SLACK_WEBHOOK_URL }}
|
||||||
steps:
|
steps:
|
||||||
- name: Download all artifacts
|
- name: Download all artifacts
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
|
|
@ -402,8 +407,11 @@ jobs:
|
||||||
name: security-summary
|
name: security-summary
|
||||||
path: security-summary.md
|
path: security-summary.md
|
||||||
|
|
||||||
|
# GitHub Actions does not allow `secrets.X` in step-level `if:` —
|
||||||
|
# use env.X instead. Inherits SECURITY_SLACK_WEBHOOK_URL from the
|
||||||
|
# job-level env block (added below).
|
||||||
- name: Notify security team on critical findings
|
- name: Notify security team on critical findings
|
||||||
if: ${{ secrets.SECURITY_SLACK_WEBHOOK_URL != '' && (needs.sast.result == 'failure' || needs.dependency-scan.result == 'failure' || needs.container-scan.result == 'failure') }}
|
if: ${{ env.SECURITY_SLACK_WEBHOOK_URL != '' && (needs.sast.result == 'failure' || needs.dependency-scan.result == 'failure' || needs.container-scan.result == 'failure') }}
|
||||||
uses: 8398a7/action-slack@v3
|
uses: 8398a7/action-slack@v3
|
||||||
with:
|
with:
|
||||||
status: failure
|
status: failure
|
||||||
|
|
@ -415,7 +423,7 @@ jobs:
|
||||||
Workflow: ${{ github.workflow }}
|
Workflow: ${{ github.workflow }}
|
||||||
Please review the security scan results immediately.
|
Please review the security scan results immediately.
|
||||||
env:
|
env:
|
||||||
SLACK_WEBHOOK_URL: ${{ secrets.SECURITY_SLACK_WEBHOOK_URL }}
|
SLACK_WEBHOOK_URL: ${{ env.SECURITY_SLACK_WEBHOOK_URL }}
|
||||||
|
|
||||||
- name: Create security issue on critical findings
|
- name: Create security issue on critical findings
|
||||||
if: needs.sast.result == 'failure' || needs.dependency-scan.result == 'failure'
|
if: needs.sast.result == 'failure' || needs.dependency-scan.result == 'failure'
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue