From 2a7ecdb556c8e4e12d3ec7d3e8ea39dbfd4dac24 Mon Sep 17 00:00:00 2001 From: Sahil Bansal Date: Fri, 26 Jun 2026 16:33:37 +0530 Subject: [PATCH] ci: add E2E for pmg action server-mode (#354) * ci: add E2E for pmg action server-mode Exercises the safedep/pmg action with server-mode enabled: the action starts the proxy daemon and injects HTTP_PROXY + CA env vars, then bare npm/pip installs are intercepted. Asserts benign installs pass, malicious npm/pip installs are blocked, and 'pmg proxy stop --fail-on-violation' fails the job on the blocks. Scoped via paths to action.yml and the proxy server sources so it only runs when relevant. Complements persistent-proxy-e2e.yml, which covers the branch's proxy internals via raw pmg proxy commands. * ci: extract shared proxy E2E assertions into composite action Both the action server-mode E2E and the persistent-proxy E2E run the same benign/malicious install assertions. Factor them into a local composite action (.github/actions/proxy-e2e-assertions) so the assertions live in one place and both workflows exercise the composite itself. Proxy teardown (pmg proxy stop --fail-on-violation) stays inline in each workflow since the setup/teardown differs per binary-under-test (released binary via the action vs. branch build via make). --- .../actions/proxy-e2e-assertions/action.yml | 50 ++++++++++++++++ .github/workflows/persistent-proxy-e2e.yml | 43 +------------- .github/workflows/pmg-action-e2e.yml | 58 +++++++++++++++++++ 3 files changed, 111 insertions(+), 40 deletions(-) create mode 100644 .github/actions/proxy-e2e-assertions/action.yml create mode 100644 .github/workflows/pmg-action-e2e.yml diff --git a/.github/actions/proxy-e2e-assertions/action.yml b/.github/actions/proxy-e2e-assertions/action.yml new file mode 100644 index 0000000..76056b8 --- /dev/null +++ b/.github/actions/proxy-e2e-assertions/action.yml @@ -0,0 +1,50 @@ +name: Proxy E2E Assertions +description: > + Shared assertions for a running PMG persistent proxy. Assumes the proxy is + already started and HTTP_PROXY + CA env vars are exported into the job env. + Runs benign + malicious installs. The caller owns stopping the proxy (e.g. + pmg proxy stop --fail-on-violation) since teardown differs per setup. + +runs: + using: composite + steps: + - name: Verify proxy env is set + shell: bash + run: | + echo "HTTP_PROXY=$HTTP_PROXY" + test -n "$HTTP_PROXY" + + - name: Benign npm install succeeds + shell: bash + run: | + mkdir benign-test && cd benign-test + npm init -y + npm install lodash@4.17.21 + test -d node_modules/lodash + cd .. && rm -rf benign-test + + - name: Malicious npm install is blocked + shell: bash + run: | + mkdir mal-npm && cd mal-npm + npm init -y + # The install MUST fail (proxy blocks it). Assert that, instead of + # continue-on-error which would hide a regression where it succeeds. + if npm --no-cache --prefer-online install safedep-test-pkg@0.1.3; then + echo "ERROR: malicious npm install succeeded but should have been blocked" + exit 1 + fi + echo "OK: malicious npm install was blocked" + cd .. && rm -rf mal-npm + + - name: Malicious pip install is blocked (python3 -m pip) + shell: bash + run: | + python3 -m venv venv && source venv/bin/activate + if python3 -m pip install safedep-test-pkg; then + echo "ERROR: malicious pip install succeeded but should have been blocked" + deactivate + exit 1 + fi + echo "OK: malicious pip install was blocked" + deactivate && rm -rf venv diff --git a/.github/workflows/persistent-proxy-e2e.yml b/.github/workflows/persistent-proxy-e2e.yml index 5d93172..f93f8f2 100644 --- a/.github/workflows/persistent-proxy-e2e.yml +++ b/.github/workflows/persistent-proxy-e2e.yml @@ -24,7 +24,6 @@ jobs: SAFEDEP_API_KEY: ${{ secrets.SAFEDEP_CLOUD_API_KEY }} SAFEDEP_TENANT_ID: ${{ secrets.SAFEDEP_CLOUD_TENANT_DOMAIN}} PMG_CLOUD_ENABLED: "true" - PMG_CLOUD_ENDPOINT_ID: github-actions/${{ github.repository }} defaults: run: shell: bash @@ -60,49 +59,13 @@ jobs: - name: Inject proxy env run: pmg proxy env >> "$GITHUB_ENV" - - name: Verify proxy env is set - run: | - echo "HTTP_PROXY=$HTTP_PROXY" - test -n "$HTTP_PROXY" - - - name: Benign npm install succeeds - run: | - mkdir benign-test && cd benign-test - npm init -y - npm install lodash@4.17.21 - test -d node_modules/lodash - cd .. && rm -rf benign-test - - - name: Malicious npm install is blocked - run: | - mkdir mal-npm && cd mal-npm - npm init -y - # The install MUST fail (proxy blocks it). Assert that, instead of - # continue-on-error which would hide a regression where it succeeds. - if npm --no-cache --prefer-online install safedep-test-pkg@0.1.3; then - echo "ERROR: malicious npm install succeeded but should have been blocked" - exit 1 - fi - echo "OK: malicious npm install was blocked" - cd .. && rm -rf mal-npm - - - name: Malicious pip install is blocked (python3 -m pip) - run: | - python3 -m venv venv && source venv/bin/activate - if python3 -m pip install safedep-test-pkg; then - echo "ERROR: malicious pip install succeeded but should have been blocked" - deactivate - exit 1 - fi - echo "OK: malicious pip install was blocked" - deactivate && rm -rf venv + - name: Run proxy E2E assertions + uses: ./.github/actions/proxy-e2e-assertions - name: Stop proxy and verify it fails on the blocks if: always() + shell: bash run: | - # We blocked packages above, so --fail-on-violation must exit non-zero. - # Assert that (a green test means the gate works), and always run so the - # daemon is stopped even if an earlier step failed. if pmg proxy stop --fail-on-violation; then echo "ERROR: stop should have exited non-zero (packages were blocked)" exit 1 diff --git a/.github/workflows/pmg-action-e2e.yml b/.github/workflows/pmg-action-e2e.yml new file mode 100644 index 0000000..1ff3b7a --- /dev/null +++ b/.github/workflows/pmg-action-e2e.yml @@ -0,0 +1,58 @@ +# .github/workflows/pmg-action-e2e.yml +name: PMG Server Action E2E + +on: + workflow_dispatch: + pull_request: + branches: + - main + paths: + - "action.yml" + - "cmd/proxy/**" + - "internal/proxyserver/**" + - "internal/flows/cert.go" + +permissions: + contents: read + +jobs: + pmg-action-server-e2e: + name: PMG Server Action E2E + runs-on: ubuntu-latest + timeout-minutes: 10 + defaults: + run: + shell: bash + steps: + - name: Checkout Source + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: "24" + + - name: Setup Python + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 + with: + python-version: "3.11" + + - name: Run PMG action in server mode + uses: ./ # action.yml + with: + server-mode: true + api-key: ${{ secrets.SAFEDEP_CLOUD_API_KEY }} + tenant-id: ${{ secrets.SAFEDEP_CLOUD_TENANT_DOMAIN }} + + - name: Run proxy E2E assertions + uses: ./.github/actions/proxy-e2e-assertions + + - name: Stop proxy and verify it fails on the blocks + if: always() + shell: bash + run: | + if pmg proxy stop --fail-on-violation; then + echo "ERROR: stop should have exited non-zero (packages were blocked)" + exit 1 + fi + echo "OK: stop correctly failed on the policy violation"