CI/CD Pipelines
Automate artifact verification and policy enforcement in your build and release workflows.
-
Supported pipelines
Phylax integrates with the most common CI/CD systems.
-
Create a secret
Store your Phylax API token as a secret in your CI platform.
Key Value PHYLAX_API_TOKENphx_live_••••••••••••••••The token grants read-only access to verdicts and policies. It cannot publish attestations or change policy, so a leak from a build log is recoverable by rotation alone.
-
GitHub Actions example
Add verification to your workflow.
.github/workflows/verify.yml name: Verify artifacts with Phylaxon:push:branches: [main]pull_request:permissions:contents: readsecurity-events: writejobs:phylax-verify:runs-on: ubuntu-lateststeps:- name: Checkoutuses: actions/checkout@v4- name: Verify artifactsuses: praxi-labs/phylax-action@v0with:api-token: ${{ secrets.PHYLAX_API_TOKEN }}artifact-path: dist/fail-on: blockformat: sarif- name: Upload SARIFif: always()uses: github/codeql-action/upload-sarif@v3with:sarif_file: phylax.sarif -
Pipeline verdicts
Your pipeline outcome is determined by the strictest verdict.
Verdict Description Pipeline behavior ALLOW Artifact complies with all active policies. Passes. Continue the pipeline. WARN Non-blocking issues found. Passes with warning. Review recommended. BLOCK Artifact violates one or more blocking policies. Fails the job. Stop the pipeline. -
GitLab CI example
Add a Phylax verification step to
.gitlab-ci.yml..gitlab-ci.yml verify:image: node:22-alpinestage: verifyscript:- npm install -g @phyi/cli- phylax verify path ./dist --format sarif --output phylax.sarif --fail-on blockvariables:PHYLAX_API_TOKEN: $PHYLAX_API_TOKENartifacts:reports:sast: phylax.sarifwhen: alwaysallow_failure: false -
Best practices
Fail on blockSet
fail-on: blockto prevent risky releases. Warnings keep your pipeline informative.Verify earlyRun verification in the earliest stage possible to save time and compute.
Trend verdictsExport SARIF and track trends over time to improve supply chain posture.
Jenkins
Jenkins has no first-party action, so call the CLI directly and let the exit code fail the stage.
pipeline { agent any stages { stage('Verify') { steps { withCredentials([string(credentialsId: 'phylax-api-token', variable: 'PHYLAX_API_TOKEN')]) { sh 'npm install -g @phyi/cli' sh 'phylax verify path ./dist --format sarif --output phylax.sarif --fail-on block' } } post { always { archiveArtifacts artifacts: 'phylax.sarif', allowEmptyArchive: true } } } }}Two things that will bite you
These are the failure modes that account for most “the scan isn’t running” reports, and neither is obvious from a working example.
Pull requests from forks get no secrets
GitHub does not pass repository secrets to workflows triggered by pull_request from a fork.
secrets.PHYLAX_API_TOKEN arrives empty and the step fails or silently skips, which means
outside contributions are exactly the pull requests you are not scanning.
The safe fix is to verify forks in a separate workflow triggered by pull_request_target,
which does receive secrets, and to check out the base commit rather than the fork’s head so
untrusted code never runs with a token in scope.
pull_request_target runs with write permissions and access to secrets. Checking out the
pull request’s head there hands both to arbitrary code from a stranger. Verify build outputs
or lockfiles, not the fork’s scripts.
SARIF upload needs a permission you probably do not have
github/codeql-action/upload-sarif requires security-events: write. Repositories that
default the GITHUB_TOKEN to read-only will fail the upload with a 403, so the permissions:
block in the example above is not optional.
Two more upload notes:
if: always()matters. Without it, aBLOCKfails the verify step and the upload never runs, so you lose the findings in exactly the case you most wanted to read them.- CodeQL default setup rejects third-party SARIF. If a repository has code scanning’s default setup enabled, uploads from other tools are refused. Switch that repository to the advanced configuration.
Choosing what blocks
The instinct is to block on everything. That is how a security check ends up disabled.
New CVEs are published daily against dependencies you did not change, so a pipeline that fails on every finding fails on days when nothing about your code moved. The distinction worth drawing is between findings that are your fault and findings that are the world’s:
| Finding | Suggested action |
|---|---|
| Leaked secret, malicious package, failed provenance | Block. These are never a false alarm worth shipping past. |
| New CVE in an unchanged dependency | Warn, and track the trend. |
| Policy drift, license change | Warn first, block once the baseline is clean. |
Start with fail-on: block and a policy that blocks only the first row. Tighten once you know
what your baseline looks like, rather than tightening on day one and turning the check off in
week two.
Related guides
Gate the pull request itself with GitHub, gate execution at runtime with the Agent Runtime Gate, or see every CLI flag and exit code on the Phylax CLI page.
Both pieces are open source: the Action at praxi-labs/phylax-action, and the reusable workflows that wrap it at praxi-labs/phylax-workflows.