Use the WardenKit Licence Policy CLI in GitHub Actions
A complete GitHub Actions workflow that runs an open source license policy check on every pull request: installing from the lockfile, validating the policy, evaluating components, uploading the JSON result, and reporting the outcome in the job summary.
Task: Add a licence policy check to a GitHub repository that blocks a pull request on a denied licence. · Uses @wardenkit/open-source-licence-policy · Product overview · Documentation
What the repository needs first
- licence-policy.json — the policy you authored and committed.
- components.json — the component records, either committed or generated by an earlier step in the job.
- @wardenkit/open-source-licence-policy in devDependencies and in the lockfile, so npm ci installs the exact reviewed version.
There is no WardenKit action to add from the GitHub Marketplace, and none is needed. The CLI is the supported integration: it is a normal dev dependency invoked with npx --no-install.
The workflow
name: licence-policy
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
licence-policy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
# Pipeline defect if the policy document itself is invalid.
- name: Validate the licence policy document
run: |
npx --no-install wardenkit-licence-policy validate-policy \
--policy licence-policy.json \
--json
# Records which SPDX baseline decided this run.
- name: Record the SPDX reference in use
run: npx --no-install wardenkit-licence-policy reference --json
- name: Evaluate the licence policy
id: evaluate
run: |
npx --no-install wardenkit-licence-policy evaluate \
--components components.json \
--policy licence-policy.json \
--output licence-policy-result.json \
--json
- name: Summarise the result
if: always()
run: |
if [ -f licence-policy-result.json ]; then
{
echo '### Licence policy'
echo ''
echo '```json'
node -e "const r=require('./licence-policy-result.json');console.log(JSON.stringify(r.aggregate,null,2))"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
fi
- uses: actions/upload-artifact@v4
if: always()
with:
name: licence-policy-result
path: |
licence-policy-result.json
if-no-files-found: warnWhat each step does, and why it is separate
| Step | Purpose | Failure meaning |
|---|---|---|
| npm ci | Installs the exact evaluator version from the lockfile. | Dependency problem, unrelated to licences. |
| validate-policy | Rejects an invalid policy before anything is evaluated against it. | Exit 2 — your policy document is a pipeline defect. |
| reference | Prints the pinned SPDX List version and snapshot into the job log. | Rarely fails; useful when a result needs explaining later. |
| evaluate | Applies your policy to your component records. | Exit 1 — a CI-blocking outcome under your own policy. Exit 2 — malformed components. |
| Summarise / upload | Puts the aggregate in the job summary and keeps the JSON artefact. | Runs with if: always(), so a blocked run still yields evidence. |
The evaluate step is the only one that can fail for a licence reason, and it fails with exit 1 exactly when your policy's ciFailureOutcomes says it should. Everything else fails as an ordinary engineering problem, which keeps the red build legible.
Note what the job does not need: no secret, no token, no service URL and no network egress for the evaluation itself. Evaluation, policy validation and the reference command are local operations, so the check works unchanged on a self-hosted runner with no outbound access.
Common variations
Generate the component records in the job rather than committing them, by inserting your own inventory step before the evaluate step and uploading its output alongside the result:
- name: Build the component inventory
run: node scripts/build-component-inventory.mjs > components.json
- uses: actions/upload-artifact@v4
if: always()
with:
name: licence-policy-inputs
path: components.jsonReport a blocking outcome without failing the pull request while you are still tuning the policy, by tolerating the exit code and asserting on the aggregate later:
- name: Evaluate the licence policy (report only)
continue-on-error: true
run: |
npx --no-install wardenkit-licence-policy evaluate \
--components components.json \
--policy licence-policy.json \
--output licence-policy-result.json \
--jsonTreat report-only as a migration state with an end date. A check that cannot fail is not enforcement, and a policy that is never enforced drifts from what the organization actually intends.
Run the same workflow on a schedule as well as on pull requests if your component records are generated: the dependency set can change without your repository changing, and a nightly run catches that.
Run this locally
- Try the same workflow locally — Open-Source Licence Policy SDK quickstart
- Learn what the SDK does, its boundaries and its plans — Open-Source Licence Policy SDK
Related guides
- Run License Policy Checks in CI — Fail a build when a dependency's licence is denied by your policy, and keep the JSON evidence for the release.
- Open Source License Policy as Code — Express an existing open source licence policy as a versioned JSON document, validate it, and make its decisions reproducible.
- SPDX License Expression Reference: AND, OR, WITH and LicenseRef — Look up how a specific SPDX expression parses, normalizes and fails, with a runnable example for each case.
Deterministic tooling, professional judgment
WardenKit performs deterministic technical validation, normalization and evaluation of the policy you author, over the records you supply. It does not provide legal advice, determine legal permissions or obligations, opine on licence compatibility, or certify compliance. Which licences your organization allows, denies or reviews remains your decision.
Product overview and pricing · All guides · Docs · Support
Corrections and questions: support@wardenkit.com.