Turn your licence policy into an enforceable build rule.
Give WardenKit your software-component list and your licence rules. It validates SPDX licence evidence locally and fails CI when a component breaks your policy—without uploading your repository to a heavyweight SCA platform.
Local-first · SPDX-native · Deterministic · CI-ready
npm install @wardenkit/open-source-licence-policyUsing GitHub? Add WardenKit to GitHub Actions →
- Try it free: 60-second local evaluation — no account, email, card or licence key.
- Runnable example:
examples/basic/— the SDK and the CLI over a sample policy and six component records. - CI: GitHub Actions workflow · any other CI
- Real results: what the example prints on
0.1.2 - Production and Platform / Agency: what the paid plans add · pricing — Production $49/month; Platform / Agency $149/month.
- Docs: Documentation and quickstart · Guides
- Package:
@wardenkit/open-source-licence-policy· CLI:wardenkit-licence-policy
Boundaries. This repository holds public documentation and examples; the SDK is distributed through npm. It is not SCA: no dependency discovery, no license detection and no telemetry. It evaluates the component records and policy you supply and gives no legal advice.
Runnable examples and reference material for the WardenKit Open-Source Licence Policy SDK — open source license policy as code: a local Node.js SDK and CLI that validates and normalizes SPDX license expressions against a pinned SPDX License List baseline, evaluates a policy you author over component records you supply, and returns reproducible, CI-consumable JSON. Everything runs in your own process; there is no hosted evaluator.
Version. The examples and reference in this repository are written against the public surface of
@wardenkit/open-source-licence-policyversion0.1.2. This repository contains documentation and examples only; the SDK source is not distributed here.
Most teams already know which licenses they are willing to ship. What they lack is a deterministic, reviewable way to state that decision and enforce it in CI:
- a license policy that lives in the repository as code, is versioned, and is hashed into every result;
- SPDX license expressions (
MIT,Apache-2.0 OR MIT,GPL-3.0-only WITH Classpath-exception-2.0,LicenseRef-acme-internal) validated against a published SPDX List release rather than by string comparison; - one command in CI that exits non-zero when the policy says the release must stop;
- output you can attach to a release as evidence, reproducible byte for byte.
This SDK does exactly that and nothing more. It never tells you which licenses to allow or deny, and it produces no legal advice, permission, obligation or compatibility opinion.
npm install @wardenkit/open-source-licence-policySupported runtimes: Node.js 22.x and 24.x.
No account, no email address, no license key, no network call.
git clone https://github.com/wardenkit/open-source-licence-policy.git
cd open-source-licence-policy/examples/basic
npm install @wardenkit/open-source-licence-policy
node check-licences.mjsThe run exits 1 on purpose: the sample policy blocks two of the six sample components. See
Real policy results for the exact output.
Or with the CLI directly:
npx wardenkit-licence-policy validate-policy --policy licence-policy.json --json
npx wardenkit-licence-policy evaluate \
--components components.json \
--policy licence-policy.json \
--jsonTwo inputs, both yours:
licence-policy.json — your policy, as code:
{
"policySchemaVersion": 1,
"policyId": "example-licence-policy",
"policyVersion": "1.0.0",
"defaultOutcome": "review-required",
"complexExpressionTreatment": "review-required",
"deprecatedIdTreatment": "review-required",
"ciFailureOutcomes": ["policy-denied", "invalid-unsupported"],
"rules": [
{ "ruleId": "allow-mit", "match": { "type": "exact-license-id", "licenseId": "MIT" }, "outcome": "policy-allowed" }
]
}components.json — the license evidence you already have:
[
{ "id": "left-pad", "version": "1.3.0", "licenseExpression": "MIT" },
{ "id": "copyleft-tool", "version": "2.0.0", "licenseExpression": "AGPL-3.0-only" }
]The license identifiers in every example are illustrations of a customer-authored policy. Which licenses your organization allows, denies or sends to review is your decision.
Unedited output of node check-licences.mjs in examples/basic/ with
@wardenkit/open-source-licence-policy 0.1.2 on Node.js 22 and 24 (identical on both):
policy example-basic-licence-policy@1.0.0 hash b52e45c0d66243c50f20b4e3434212c913fd35843228b61c73961e11b924c318
policy-allowed acme-http (Apache-2.0 OR MIT) decided by rule
policy-allowed acme-internal-utils (LicenseRef-acme-internal) decided by rule
policy-denied copyleft-tool (AGPL-3.0-only) decided by rule
policy-allowed left-pad (MIT) decided by rule
review-required legacy-lib (LGPL-2.1) decided by deprecatedIdTreatment
EXPR_DEPRECATED_ID: SPDX licence identifier "LGPL-2.1" is deprecated.
invalid-unsupported mystery-lib (mystery-lib) decided by grammar
EXPR_UNKNOWN_ID: Unknown SPDX licence identifier "Totally-Made-Up-1.0".
aggregate: invalid-unsupported over 6 components
counts: {"policy-allowed":3,"policy-denied":1,"review-required":1,"invalid-unsupported":1}
product 0.1.2 · reference spdx-license-list-3.28.0/snapshot-1
SPDX List 3.28.0 · spec 3.0.1
licence policy: blocking outcome
Exit code 1: this sample policy lists policy-denied and invalid-unsupported in its own
ciFailureOutcomes. The same inputs through
npx wardenkit-licence-policy evaluate --components components.json --policy licence-policy.json --output licence-policy-result.json --json
write a JSON result. An excerpt:
{
"aggregate": {
"outcome": "invalid-unsupported",
"componentCount": 6,
"ciBlocking": true,
"counts": { "policy-allowed": 3, "policy-denied": 1, "review-required": 1, "invalid-unsupported": 1 }
},
"components": [
{
"id": "copyleft-tool",
"normalizedExpression": "AGPL-3.0-only",
"shape": "listed-id",
"outcome": "policy-denied",
"decidedBy": "rule",
"matchedRuleId": "deny-agpl-3.0-only"
}
],
"provenance": {
"productVersion": "0.1.2",
"policyId": "example-basic-licence-policy",
"policyHash": "b52e45c0d66243c50f20b4e3434212c913fd35843228b61c73961e11b924c318",
"reference": { "referenceVersion": "spdx-license-list-3.28.0/snapshot-1", "spdxLicenseListVersion": "3.28.0" }
}
}These are results of a sample, customer-authored policy over sample component records, not a recommendation about which licenses to allow.
Per component, the policy produces exactly one of four outcomes. The policy- prefix means "the
result of your configured policy" — never a legal permission or prohibition.
| Outcome | Meaning |
|---|---|
policy-allowed |
Your policy allows this normalized expression. |
policy-denied |
Your policy denies it, by an explicit rule or by your defaultOutcome. |
review-required |
Your policy routes it to human review. |
invalid-unsupported |
The expression is malformed, unknown, or uses an unsupported construct. It never silently passes. |
aggregate.ciBlocking is derived from your own ciFailureOutcomes list, and the CLI exit code
mirrors it. Every result carries a provenance block — product version, schema versions, your
policyId, policyVersion and policyHash, a hash of the component input, and the exact SPDX
reference version — so identical inputs reproduce byte-identical output.
Expressions are parsed against SPDX Specification 3.0.1, Annex B and resolved against a pinned SPDX License List 3.28.0 baseline.
| Expression | Normalized | Shape |
|---|---|---|
mit |
MIT |
listed-id |
apache-2.0 or mit |
Apache-2.0 OR MIT |
complex |
MIT AND (Apache-2.0 OR BSD-3-Clause) |
(Apache-2.0 OR BSD-3-Clause) AND MIT |
complex |
gpl-3.0-only WITH Classpath-exception-2.0 |
GPL-3.0-only WITH Classpath-exception-2.0 |
complex |
LicenseRef-Acme-Internal |
LicenseRef-acme-internal |
license-ref |
- Operators
AND,OR,WITHare matched case-sensitively (lowercase forms are also accepted); identifiers are matched case-insensitively and re-emitted in canonical List case. ANDandORare commutative, so operands are ordered canonically: two engineers writing the same choice differently get the same normalized expression.- Deprecated identifiers are preserved exactly and reported with an
EXPR_DEPRECATED_IDdiagnostic. No successor identifier is ever substituted for you. LicenseRef-<id>andAdditionRef-<id>are supported as opaque customer-defined references with no legal meaning attached.DocumentRef-qualified references are unsupported in this version and produceEXPR_DOCUMENTREF_UNSUPPORTED.
SPDX is referenced as a technical standard family. WardenKit is not affiliated with, endorsed by or operated by SPDX or the Linux Foundation.
The package root exposes exactly six runtime exports:
import {
LicencePolicyError,
PRODUCT_VERSION,
createEvaluator,
createManagedProductionEvaluator,
getEntitlementStatus,
validatePolicy,
} from "@wardenkit/open-source-licence-policy";
const evaluator = createEvaluator(); // synchronous, deterministic, zero-network
const result = evaluator.evaluate({ policy, components });
validatePolicy(policy);
getEntitlementStatus(); // local entitlement state, no network
// Production only: managed authorization refreshed on evaluate activity
const managed = await createManagedProductionEvaluator();
const outcome = await managed.evaluate({ policy, components });
managed.status().state; // AUTHORIZATION_ACTIVE | AUTHORIZATION_REFRESH_DUE | ...createEvaluator never touches the network. createManagedProductionEvaluator is the only
network-capable SDK entry point: it performs a bounded HTTPS authorization refresh against the
WardenKit perimeter on evaluate activity and still evaluates locally.
Six commands. JSON on stdout, diagnostics on stderr. Of the CLI commands only activate and
refresh use the network.
| Command | Flags |
|---|---|
evaluate |
--components, --policy, --reference-pack, --output |
validate-policy |
--policy |
reference |
--reference-pack |
status |
— |
activate |
--activation-code, --activation-file |
refresh |
— |
Global flags: --json, --state-dir.
| Exit code | Meaning |
|---|---|
0 |
Success; for evaluate, an outcome that is not CI-blocking. |
1 |
Evaluation completed and the aggregate outcome is CI-blocking under your policy. |
2 |
Usage error, malformed input document or invalid policy. |
3 |
Production authorization required, not yet valid, or expired. |
4 |
Local trust state or reference pack rejected. |
5 |
Network request to the WardenKit service failed. |
6 |
The WardenKit perimeter rejected the request. |
| Path | What it shows |
|---|---|
examples/basic/ |
Minimal local SDK evaluation with createEvaluator(), plus the same run through the CLI. |
examples/policies/ |
Customer-authored policy documents: strict allowlist, review-first, and dual-license handling. |
examples/ci/ |
A generic CI shell step that maps every exit code deliberately. |
examples/github-actions/ |
A GitHub Actions workflow that evaluates the policy and uploads the JSON result as an artifact. |
There is no WardenKit GitHub Action and none is required: the CI contract is the CLI exit code plus the JSON result file.
- Documentation: quickstart · CLI reference · reading the result · running in CI · entitlement and activation
- Open-source license policy as code
- Use the WardenKit Licence Policy CLI in GitHub Actions
- Run license policy checks in CI
- Validate SPDX license expressions in Node.js
- SPDX license expression reference
- Component records, policies, dependency names, license evidence and results never leave your process.
- No telemetry. Nothing is counted, metered or reported.
evaluate,validate-policy,reference,statusandcreateEvaluatormake no network request at all.activate,refreshand the managed Production evaluator's authorization refresh exchange only product identity, entitlement identity, tier, an organization subject identifier, an activation credential, timestamps and the product version — over HTTPS to the WardenKit perimeter only. Components, policies, SPDX expressions and evaluation results are never transmitted.
Evaluation use — the full local evaluator against the bundled SPDX evaluation reference snapshot — is free, requires no account and has no time limit. Production use requires a paid entitlement and carries the maintained signed WardenKit Licence Reference Pack. Exact plans are on the product page:
| Plan | Price | Rights |
|---|---|---|
| Evaluation | $0 | Development, testing, CI integration testing and internal non-production evaluation. |
| Production | $49/month | One customer organization, up to 10 repositories, Production / Production-CI rights, maintained signed Licence Reference Pack, managed Production authorization and refresh, compatibility and security releases, documented support boundary. |
| Platform / Agency | $149/month | Up to 5 client organizations, up to 50 repositories aggregate, permitted production use on behalf of clients, the same maintained Production material. |
Each signed production authorization is valid for at most 72 hours. The managed Production evaluator
refreshes it on evaluate activity once 24 hours have passed — no daemon, no background timer, no
traffic while dormant — and the CLI refresh command is a recovery and diagnostic action. Only the
signed deadline is binding and there is no additional grace period. Transient service failures follow
a bounded retry ladder (5 min, 15 min, 1 h, 4 h, 8 h); an authorization that expires while the
service is unreachable performs two bounded recovery attempts and then reports
REVALIDATION_REQUIRED (a technical state, not a revocation), while evaluation of your files against
the bundled snapshot keeps working; a later evaluate() on the same evaluator begins a fresh bounded
recovery cycle, so a dormant or expired eligible installation revalidates automatically on its next
managed Production use and no routine daily manual refresh is required.
managed.status().state reports exactly one of AUTHORIZATION_ACTIVE, AUTHORIZATION_REFRESH_DUE,
AUTHORIZATION_REFRESH_RETRY_SCHEDULED, REVALIDATION_REQUIRED, PAYMENT_RECOVERY or
COMMERCIAL_RIGHTS_ENDED.
A subscription in provider-confirmed payment recovery (past due) keeps refreshing under
PAYMENT_RECOVERY until the payment provider reports a rights-changing event. Ordinary cancellation
keeps paid access through the period already paid for; cancellation, refund and the one-time
30-calendar-day initial-purchase guarantee are described in the
Refund Policy and in the package's LICENSE.md.
- No dependency discovery — you supply the component records.
- No license detection or license-text classification.
- No vulnerability, malware or general SCA scanning.
- No SBOM generation; no SPDX-document or CycloneDX adapters in this version.
- No legal advice, legal permission or obligation determination, compatibility opinion or compliance certification.
- Support: support@wardenkit.com
- Security: see
SECURITY.md - Licence for this repository's documentation and examples:
LICENSE.md. The SDK itself is licensed by the licence file shipped inside the published package.
WardenKit is a product of BRIDGER SERVICES (SMC-PRIVATE) LIMITED. WardenKit provides developer tooling for evaluating and implementing compliance logic; it does not replace professional legal, tax, or accounting judgment.