Skip to content

Release v5.1.0 - #5

Merged
cavoq merged 13 commits into
masterfrom
development
Oct 14, 2026
Merged

cavoq merged 13 commits into
masterfrom
development

Conversation

@cavoq

@cavoq cavoq commented Oct 14, 2026

Copy link
Copy Markdown
Owner

Release v5.1.0: tools for writing and testing policies, plus cleanup. No breaking changes. See CHANGELOG.md.

Added

  • pcl inspect prints the node tree that policies evaluate, using the same inputs, chain building and projections as a lint run. --paths lists every rule target as path = value (kind), and --output json|yaml emits the same as data.
  • Policy JSON Schema (schemas/policy.schema.json, pcl schema) gives editors completion and validation for fields, operator names and per-operator operands. It is generated from the operator table, and the shipped policies reference it.
  • pcl test runs *.test.yaml suites that lint example inputs at a fixed time and check expected verdicts per input, policy and rule, or an expected error. Example suites are in tests/policy-suites.

Fixed

  • Command errors are printed once, and runtime failures no longer dump the full usage text.
  • .gitignore no longer hides the internal/data package.

Cleanup

  • Lint and inspect share one input-acquisition and evaluator-subject pipeline.
  • ASN.1 character-set checks live in one place.
  • Dead and test-only wrapper code is removed.
  • The README and architecture docs now match the code.

Verification

  • Every path inspect lists resolves back to its node: 16k paths across the fixtures.
  • Schema and Go validators agree on every operand contract case; every repository policy validates; invalid policies are rejected by both schema and parser.
  • Lint results are identical to the published v5.0.0 binary for every policy and fixture (25,979 rule results).
  • go test -race ./... and golangci-lint pass locally.

cavoq added 13 commits October 14, 2026 19:40
Chain, OCSP and CRL each built a node tree and operator context per
input and evaluated the selected policies in the same loop. Split them
into ChainSubjects, OCSPSubjects and CRLSubjects, which return the
tree, context and policies for each input, and Evaluate, which applies
them. Results are unchanged; this lets other commands reuse exactly the
trees that policies see.
Run loaded inputs, built the chain, fetched revocation data and
evaluated policies in one flow split across processCertificates and the
CRL/OCSP-only branch. Extract acquireInputs (loading, chain building
and automatic retrieval) and buildSubjects (the evaluator subjects in
output order) so another command can reuse exactly the inputs a lint run
sees. Results are unchanged for every policy and fixture.
Policy authors had to look up target paths in the README. pcl inspect
acquires inputs exactly as a lint run does (same input flags, chain
building, automatic retrieval and evaluator projections such as
revocation and applicationPurpose) and prints each subject's tree.
--paths lists every rule target path as "path = value (kind)", and
--output json|yaml emits the tree or path list as data.

Every listed path resolves back to its node; a test checks this for all
16k paths of the repository's certificate, CRL and OCSP fixtures. The
tree printer now draws branch connectors below the root, and the input
flags are shared between the lint and inspect commands.
Policy authors only learned about unknown operators, invalid severities
or malformed operands when linting. Each built-in operand contract now
carries a JSON Schema fragment next to its validator, every and dateDiff
describe their structured operands, and pcl schema assembles the policy
schema (draft-07) from the registry with the same field enums as policy
validation. Operators sharing a contract share one definition, and
operands are required exactly when the validator rejects an empty list.

The schema is committed as schemas/policy.schema.json and referenced by
the shipped policies through a yaml-language-server modeline, so editors
complete fields and operator names and flag invalid operands.

Tests keep it honest: every operand case of the contract table gets the
same verdict from schema and validator (semantic-only cases such as
regex syntax are listed separately), every repository policy validates,
a set of invalid policies is rejected by both schema and parser, and the
committed file must match the generated schema.
Policy authors had no way to pin the expected behavior of their own
policies; the repository's case harnesses were internal and counted
verdicts per role. pcl test runs *.test.yaml suites: each case lints
example inputs exactly like the lint command, with a fixed evaluation
time so fixtures do not expire, and checks the expected overall verdict
and per-rule verdicts for an input (optionally one policy), or an
expected error. Unknown fields fail the suite, failures name the input,
rule and actual verdict, and the command exits non-zero on any failure.

Linting gains a configurable ValidationTime for this. Example suites in
tests/policy-suites run as part of the test suite.
Every failing command printed its error twice, once from cobra and once
from main, and runtime failures such as missing inputs were preceded by
the full flag listing. Silence cobra's error output so main reports the
error once, and silence usage once flags parsed successfully, so only
flag and argument errors still show usage.
The unanchored data/ pattern, meant for the downloaded PSL directory at
the repository root, also matched internal/data, so new files in that
package were silently left out of commits. Anchor it to /data/.
The PrintableString alphabet was implemented twice (x509asn1 for strict
name decoding, and the validPrintableString operator) and IA5 once more
in the operators, next to test-only DER validators in x509asn1. Export
IsPrintableString and IsIA5String from x509asn1, use them in the
operators, and remove ValidateIA5String, ValidatePrintableString and
EncodingInfo, which nothing outside their tests used. The operator test
tables now exercise the shared functions.
- FetchCRLs, FetchForChain, HasIssuingDistributionPoint,
  HasCriticalExtension, Loader.GetPSL, Loader.IsICANNDomain and
  DecodeFreshestCRLStrict had no callers at all.
- cert/zcrypto.Loader duplicated PEM parsing for tests only.
- aia.ToStdCert was a test-only alias of x509node.ToStdCert.
- evaluator.CRLOnly and OCSPOnly were superseded by the subject API.
- Document notRevokedByAvailableEvidence in the README operator tables;
  it was the only registered operator missing there.
- List the inspect, test and schema subcommands in the quick start.
- Update the operator count and describe the shared acquisition and
  subject pipeline and schema generation in architecture.md.
- JSONSchema (109 lines) builds operand definitions, the rule and
  condition schemas and the policy properties in separate functions;
  the generated schema is unchanged.
- documentValue had a switch case identical to its default.
- Unused cobra handler parameters are unnamed, as in the newer commands.
@cavoq
cavoq merged commit 21e449d into master Oct 14, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant