Skip to content
Phylax
Integration guides

CI/CD Pipelines

Automate artifact verification and policy enforcement in your build and release workflows.

  1. Supported pipelines

    Phylax integrates with the most common CI/CD systems.

  2. Create a secret

    Store your Phylax API token as a secret in your CI platform.

    KeyValue
    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.

  3. GitHub Actions example

    Add verification to your workflow.

    .github/workflows/verify.yml
    name: Verify artifacts with Phylax
    on:
    push:
    branches: [main]
    pull_request:
    permissions:
    contents: read
    security-events: write
    jobs:
    phylax-verify:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
    uses: actions/checkout@v4
    - name: Verify artifacts
    uses: praxi-labs/phylax-action@v0
    with:
    api-token: ${{ secrets.PHYLAX_API_TOKEN }}
    artifact-path: dist/
    fail-on: block
    format: sarif
    - name: Upload SARIF
    if: always()
    uses: github/codeql-action/upload-sarif@v3
    with:
    sarif_file: phylax.sarif
  4. Pipeline verdicts

    Your pipeline outcome is determined by the strictest verdict.

    VerdictDescriptionPipeline behavior
    ALLOWArtifact complies with all active policies.Passes. Continue the pipeline.
    WARNNon-blocking issues found.Passes with warning. Review recommended.
    BLOCKArtifact violates one or more blocking policies.Fails the job. Stop the pipeline.
  5. GitLab CI example

    Add a Phylax verification step to .gitlab-ci.yml.

    .gitlab-ci.yml
    verify:
    image: node:22-alpine
    stage: verify
    script:
    - npm install -g @phyi/cli
    - phylax verify path ./dist --format sarif --output phylax.sarif --fail-on block
    variables:
    PHYLAX_API_TOKEN: $PHYLAX_API_TOKEN
    artifacts:
    reports:
    sast: phylax.sarif
    when: always
    allow_failure: false
  6. Best practices

    Fail on block

    Set fail-on: block to prevent risky releases. Warnings keep your pipeline informative.

    Verify early

    Run verification in the earliest stage possible to save time and compute.

    Trend verdicts

    Export 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.

Jenkinsfile
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.

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, a BLOCK fails 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:

FindingSuggested action
Leaked secret, malicious package, failed provenanceBlock. These are never a false alarm worth shipping past.
New CVE in an unchanged dependencyWarn, and track the trend.
Policy drift, license changeWarn 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.

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.

Did this page help you?