ci: integrate SafeDep PMG into GitHub Actions workflows - #35
ci: integrate SafeDep PMG into GitHub Actions workflows#35vanshika-verma-rzp wants to merge 3 commits into
Conversation
Route CI package installs through SafeDep PMG's persistent proxy to block malicious packages before they run. Per job, following the SafeDep PMG GitHub Actions doc: - add permissions: contents: read - start PMG in server-mode after checkout (safedep/pmg@v1) - enforce policy with 'pmg proxy stop --fail-on-violation' (if: always()) Uses secrets PMG_PUBLIC_REPOS_TOKEN (api-key) and PMG_TENANT_ID (tenant-id). Applied to: crud_app, ingressroute_configurator, secret_cloner, sqs_app, sqs_configurator, semgrep. Skipped genesis.yml (Analysis job) - it calls a reusable workflow, which cannot contain steps or a job-level permissions block.
|
Semgrep found 6
GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. ⚪️ This finding does not block your pull request. |
Brings this repo onto the same integration used in ai-playbook and i18nify, with the enforcement fix from blade. - Setup step renamed to "Setup PMG proxy" and given `id: pmg-setup`, so the enforce step can tell whether setup actually ran. - Enforce step runs `--fail-on-violation` only when setup succeeded. With a bare `if: always()`, any failure before the PMG step makes GitHub skip setup while still running enforce, which then dies with `pmg: command not found` (exit 127) and buries the real error. - Removed additions that are not part of the reference integration: `permissions:` blocks, workflow comments, pinned action SHAs and non-standard step names. - Added pmg-test.yml, byte-identical to the copy in ai-playbook and i18nify, which demonstrates the proxy blocking a known-malicious package and syncing the event to SafeDep Cloud. The workflow files are now the master versions plus the two PMG steps and nothing else: 75 lines added, none removed or modified. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Setup PMG proxy | ||
| uses: safedep/pmg@v1 |
There was a problem hiding this comment.
GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608.
🧼 Removed in commit fcbd981 🧼
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Setup PMG proxy | ||
| uses: safedep/pmg@v1 |
There was a problem hiding this comment.
GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608.
🧹 Removed in commit fcbd981 🧹
| run: | | ||
| curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash | ||
| export NVM_DIR="$HOME/.nvm" | ||
| [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" | ||
| nvm install 20 | ||
| echo "$NVM_DIR/versions/node/$(nvm version 20)/bin" >> $GITHUB_PATH | ||
|
|
There was a problem hiding this comment.
A run: step pipes the output of curl or wget directly into a shell interpreter. This is the "curl | bash" install pattern — if the remote server is compromised or the URL is hijacked, an attacker can execute arbitrary code in your CI runner. Consider downloading the file first, verifying its checksum or signature, and then executing it.
🎉 Removed in commit fcbd981 🎉
| run: | | ||
| curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash | ||
| export NVM_DIR="$HOME/.nvm" | ||
| [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" | ||
| nvm install 20 | ||
| echo "$NVM_DIR/versions/node/$(nvm version 20)/bin" >> $GITHUB_PATH | ||
|
|
There was a problem hiding this comment.
A run: step pipes the output of curl or wget directly into a shell interpreter. This is the "curl | bash" install pattern — if the remote server is compromised or the URL is hijacked, an attacker can execute arbitrary code in your CI runner. Consider downloading the file first, verifying its checksum or signature, and then executing it.
🧁 Removed in commit fcbd981 🧁
pmg-test.yml was added alongside the PMG integration purely to prove the proxy behaves correctly inside this repository's own CI environment. It ran two jobs: one installing a known-clean package to confirm PMG does not block legitimate traffic, and one installing the deliberately-flagged safedep-test-pkg@0.1.3 to confirm the block is caught and `pmg proxy stop --fail-on-violation` fails the job as intended. That validation is now complete across every repository in this rollout, so the workflow has served its purpose. Leaving it in place would mean a permanent CI job that installs a deliberately-flagged package on every push and pull request - burning runner time and producing a red check that is expected-to-fail, which is exactly the kind of noise that trains people to ignore CI signal. The PMG integration itself is untouched. The safedep/pmg setup steps and the `pmg proxy stop --fail-on-violation` enforcement steps in this repository's real build and test workflows remain exactly as they were. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
What
Integrate SafeDep PMG (Package Manager Guard) into the repo's GitHub Actions so CI package installs are routed through PMG's persistent proxy, which blocks malicious packages before any code runs.
PMG step lifecycle added to each job (per the SafeDep doc)
permissions: contents: readblockuses: safedep/pmg@v1withserver-mode: true, placed after checkout, before install/build stepspmg proxy stop --fail-on-violationwithif: always()— fails the job on a block and flushes eventsDelta from the doc: uses secrets
PMG_PUBLIC_REPOS_TOKEN(api-key) andPMG_TENANT_ID(tenant-id) instead ofSAFEDEP_API_KEY/SAFEDEP_TENANT_ID.Jobs integrated (6)
ircircseccircsqscsemgreprazorpay/checkout-action; PMG placed right after itJobs skipped (1)
Analysisuses: razorpay/genesis/.github/workflows/quality-checks.yml@master+secrets: inherit). Such a job cannot containsteps:or a job-level permissions block, so PMG can't be added without breaking it. Left untouched.Scope guarantees
on:/name/metadata changes.genesis.ymlhas zero diff.if: always()).Notes / recommendations
PMG_PUBLIC_REPOS_TOKENandPMG_TENANT_ID. (PMG still blocks via community intelligence without them; thewith:values just resolve empty and cloud sync won't occur until set.)docker build(Buildkit) and don't route through the runner proxy env, so PMG is present-but-nominal there. Making it effective for those would require installing PMG inside the Dockerfiles (system-install) — a separate, out-of-scope change. Added everywhere as requested; harmless where nominal.pmg-test.yml: not added (recommended). Nothing installs packages on the runner in a way a test workflow would meaningfully exercise, so it would add no real value for this repo today. Worth revisiting if PMG is later added inside the Dockerfiles.Discussion thread: Slack