v1.4.0 — PAdES B-T/B-LT/B-LTA, compare, metadata & manifest pipelines - #40
Merged
Conversation
…ta & manifest pipelines Built on pdfnative 1.7.0. Completes the ROADMAP "Next" section (sign-side LTV) and grows the CLI from 17 to 21 commands. 100% backward-compatible command surface with v1.3.0; support policy moves to Node.js >= 22 (Node 20 EOL 2026-04-30; upstream engines requirement). New commands: - ltv (collect|embed|add) — PAdES B-LT /DSS + /VRI; --online opt-in for network, replayable ltv-data JSON, fully offline embed (air-gapped) - doc-timestamp — PAdES B-LTA /DocTimeStamp revisions (repeatable renewal) - metadata — incremental /Info + XMP updates that keep signatures valid - compare — text/structure diff with CI exit codes (E_CHECK_FAILED) Enhancements: - sign: functional --timestamp (RFC 3161, B-T) + --timestamp-digest/-nonce, multi-signatures (--allow-multiple/--field-name), --profile pkcs7|pades, --digest sha256/384/512, visible placement (--signature-rect/-page), --placeholder-bytes - verify: RSA SHA-384/512, /DocTimeStamp token validation, fieldName + isDocTimestamp per signature - inspect: --signatures inventory, print boxes + /UserUnit, metadata.trapped, --check "signatures>=N" - annotate: --password (encrypted incremental updates) - render: --strict PDF/A diagnostics (+diagnostics[] envelope), image blocks from JSON (src/dataBase64), print production, ICC output intents, viewer print preferences, charts v2 (9 kinds), --chunk-size, params.metadata - batch: --manifest pipelines (@id refs, 14-command whitelist, size/task caps, path-traversal parity, --allow-network gate, --continue-on-error) - Agent surface: E_NETWORK error code, schema subjects 15 -> 19, global --max-inflate-size, completions/manifest/llms.txt for all 21 commands Fixes: - inspect signature/form-field counters were always 0 (PDF name comparison) Security: all new network paths (TSA/OCSP/CRL) are explicit opt-ins through the existing SSRF guard; offline mock PKI (genuine RFC 3161/OCSP/CRL DER) keeps the whole PAdES ladder tested with zero network. SECURITY.md rewritten for the new surface. Release validated by a multi-agent audit chain: double-blind gap analysis, factual + standards reviews, and an arbitration pass (reports summarised in release-notes/draft/PR-v1.4.0.md). Docs: README, KNOWLEDGE_BASE, AGENTS, CHANGELOG, ROADMAP, llms.txt, SECURITY, CITATION.cff, samples/README, release-notes/v1.4.0.md + draft PR; new samples as .sh/.ps1 pairs (offline by default, TSA steps via PDFNATIVE_TSA_URL). Bumps pdfnative ^1.6.0 -> ^1.7.0; version -> 1.4.0; engines >= 22; CI 22/24. 600 tests, npm audit clean.
…es, CI + pre-publish Ports the veraPDF dispositif from pdfnative-mcp (v2: manifested corpus, negative canaries, fail-closed INFRA handling) and makes it BLOCKING from day one like pdfnative (CI + pre-publish gate). - scripts/generate-pdfa-corpus.mjs: drives node dist/cli.cjs over the PDF/A sample specs into test-output/pdfa/ (12 files: 10 positives incl. incremental sign --profile pades and metadata update; 2 negative canaries with expected ISO clauses 19005-2 6.2.11.4.1 and 19005-1 6.3.4). - scripts/validate-pdfa.mjs: faithful port — exit 0 ok/skip, 1 conformance, 2 corpus, 3 INFRA; VERAPDF_REQUIRED=1 fail-closed; VERAPDF_REPORT_DIR; hardened XML parsing; XPASS fatal; coverage + negative-canary guards. - npm scripts: corpus:pdfa, validate:pdfa (zero new dependencies — veraPDF is an external CI tool, never bundled). - .github/workflows/verapdf.yml: blocking, pinned installer 1.30.2 with SHA-256 verified before java -jar, artifacts + job summary. - publish.yml: same hardened gate before npm publish. - samples: run-all.js now renders pdfa/attachments with --font latin --lang latin (previously the PDF/A samples shipped without embedded fonts — not ISO 19005 conformant) and surfaces warnings on success; sample prose and samples/README corrected. - Docs: README PDF/A status, CONTRIBUTING veraPDF section (+Node>=22 and real coverage thresholds), KNOWLEDGE_BASE, AGENTS, CLAUDE.md (network philosophy updated for the 1.4.0 opt-ins), llms.txt, CHANGELOG 1.4.0, release notes + PR draft. Validated locally with veraPDF 1.30.2: 10 PASS + 2 XFAIL (expected clauses), 0 FAIL/XPASS/INFRA, exit 0. 600 tests green, npm audit clean.
…sh node fix) Applies the 5 legitimate findings from the final two-controller + arbiter review of the v1.4.0 release: - CHANGELOG: document the corrected counting basis of `inspect --check signed` (placeholders and /DocTimeStamp revisions no longer count — a placeholder-only PDF passed in 1.3.0 and now fails; correctness fix). - CONTRIBUTING: exact exit-3 semantics of validate-pdfa.mjs (per-file INFRA is always fatal; only "veraPDF absent" is gated by VERAPDF_REQUIRED) and corpus:pdfa does not build (needs a prior npm run build) — same fix in KNOWLEDGE_BASE. - verapdf.yml: trigger paths gain tsup.config.ts + tsconfig.json (the gate validates the tsup-built dist). - ROADMAP: veraPDF gate recorded in the v1.4.0 section; deferred items traced (table-variant font-embedding gap, setup-verapdf composite action, failed-rule regex robustness). Both controllers and the arbiter confirm: publishable, zero breaking change vs 1.3.0, project philosophy respected on all six principles. - publish.yml: node-version '22.x' -> '>=22.14.0' — npm Trusted Publishing (token-less OIDC) requires npm >= 11.5.1, which ships with the newest Node the range resolves to; '22.x' would pin bundled npm 10.9 and break the publish. Mirrors the sibling pdfnative workflow; the floor matches the >= 22 support policy. - release-notes/draft/PR-v1.4.0.md: attribution footer removed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
v1.4.0 — PAdES B-T/B-LT/B-LTA, compare, metadata & manifest pipelines
Summary
sign --timestamp <tsa-url>(RFC 3161, PAdES B-T) is now functional; new
ltv collect|embed|addcommand writes/DSS+/VRI(B-LT, with an air-gapped collect→embed flow); newdoc-timestampcommand appends
/DocTimeStamprevisions (B-LTA).metadata(incremental/Info+ XMP updates that keepsignatures valid) and
compare(text/structure diff with CI exit codes).sign --allow-multiple/--field-name/--profile/ --digest/--signature-rect/--signature-page/--placeholder-bytes, inventoried byinspect --signatures, validated per field byverify(incl. SHA-384/512 and/DocTimeStamptoken validation).batch --manifest tasks.json— declarative multi-command pipelines with@idoutputreferences; network inside a manifest requires
--allow-network.render:--strictPDF/A diagnostics, JSON-usable image blocks (src/dataBase64),print production (bleed/boxes/marks/userUnit/ICC output intent), viewer print
preferences, charts v2 (9 kinds, dual axes, log/time),
--chunk-size,params.metadata(+trapped).E_NETWORK,schemasubjects 15 → 19 (ltv-data,compare,batch-manifest,metadata), global--max-inflate-size, completions +manifest +
llms.txtfor all 21 commands.inspectbug (signature/form-field counters always 0).reference validator — a 12-file CLI-generated corpus (10 positive + 2 negative
canaries) checked in a blocking CI workflow and again pre-publish; local gate
via
npm run validate:pdfa(exit 0 without veraPDF = skip, not a pass). The PDF/Asamples themselves are now rendered actually-conformant (
--font latin --lang latinvia
run-all.js).Changes
package.json
version1.3.0 → 1.4.0;pdfnative^1.6.0→^1.7.0;engines.node>=20→>=22.print-production, …). Security overrides refreshed (
js-yaml ^4.3.1,nanoid ^3.3.18).src/core-bridge/index.ts
signPdfBytesWithTimestamp,estimateContentsSize,collectValidationInfo/embedValidationInfo/addValidationInfo/vriKeyForContents,addDocumentTimestamp,listSignatures,timestamp/revocation provider get/set, RFC 3161 token parsers,
setMaxInflateOutputSize, DER/hash/RSA primitives for the offline mock PKI, and allassociated types (print production, diagnostics, viewer preferences, metadata update,
image blocks).
New commands
src/commands/ltv.ts— collect (network,--onlinemandatory) / embed (offline) / add;serialises
LtvDataas versioned base64 JSON (schema subjectltv-data).src/commands/docTimestamp.ts—doc-timestamp(B-LTA),--urlmandatory opt-in.src/commands/metadata.ts— incrementalupdateMetadata(signatures preserved).src/commands/compare.ts— text/structure diff,E_CHECK_FAILEDon differences.Enhanced commands
sign— functional--timestamp(+--timestamp-digest,--timestamp-nonce),multi-signatures,
--profile,--digest, visible-signature placement, placeholdersizing via
estimateContentsSize(..., { timestamp: true }). No flags → byte-identical1.3.x path.
verify— RSA SHA-384/512 OIDs, per-signer digest for the byte-range hash,/DocTimeStampvalidation (imprint + token signature), additivefieldName/isDocTimestamp.inspect—--signatures, page boxes +/UserUnit,metadata.trapped,--check "signatures>=N"; fixed name-object comparisons in the legacy counters.annotate—--password(encrypted incremental updates).render—--strict+ diagnostics routing, image-block resolution,--chunk-size,ICC
outputIntentrevival from JSON (number[]→ bytes).batch—--manifest/--allow-network/--continue-on-error(validation beforeexecution, whitelist,
@idgraph, fail-fast).--max-inflate-size(src/index.ts, dynamic import keeps startup fast).New / changed utilities
src/utils/tsa.ts—createTsaProvider(url): RFC 3161 POST over the existing SSRFguard (
E_NETWORKon failure, response bodies never echoed).src/utils/ltv-provider.ts—createRevocationProvider(): OCSP POST / CRL GET overthe same guard.
src/utils/manifest.ts— pure manifest parsing/validation/@-resolution/network policy.src/utils/keys.ts— native crypto provider gains per-call digest selection(sha256/384/512).
src/utils/layout.ts— revivesoutputIntent.iccProfilefrom JSON (number[]→bytes) so ICC output intents are reachable from
--layoutfiles.src/utils/cms-verify.ts,src/utils/timestamp-verify.ts— digest agility +verifyDocTimestamp().src/utils/error.ts/agent.ts—E_NETWORK(auto-published inschema manifest).Wiring (single source of truth respected)
src/index.ts— USAGE 17 → 21 (+ 4*_USAGEblocks, help switch,loadCommand).src/commands/completion.ts— 4 new commands + all new flags (drives 4 shells + thecapability manifest).
src/commands/schema.ts— subjects 15 → 19 + extended render/inspect/verify/batch/status schemas.
Samples
.sh+.ps1, offline by default; network steps gated onPDFNATIVE_TSA_URL):sign/06-timestamp(replaces06-timestamp-reserved),sign/08-ltv(full PAdES ladder),sign/09-multiple-signatures,inspect/08-list-signatures,metadata/01-update-metadata,compare/01-compare,batch/03-manifest(+manifest/tasks.json).run-all.js):render/print/01-bleed-marks,render/print/02-viewer-prefs,render/chart/03-stacked-bars,render/chart/04-area-scatter,render/chart/05-time-axis.scripts/ & workflows (veraPDF PDF/A gate)
scripts/generate-pdfa-corpus.mjs— drives the built CLI to write a 12-filePDF/A corpus to
test-output/pdfa/+manifest.json: 10 positive entries(
--strict --font latin --lang latinacross 1b/2b/2u/3b, attachments,headers/footers, outline, opaque watermark, incremental PAdES sign, incremental
metadata) and 2 negative canaries veraPDF must reject (no-fonts render —ISO 19005-2 §6.2.11.4.1;
--variant table— ISO 19005-1 §6.3.4, the table pathcannot embed fonts from the CLI).
scripts/validate-pdfa.mjs— validates each file against its claimed XMP profilewith veraPDF and compares with
expectCompliant. Outcomes PASS/FAIL/XFAIL/XPASS/INFRA/SKIP; exit 0 ok/skip · 1 conformance (incl. fatal XPASS + coverage canary) ·
2 no corpus · 3 INFRA.
VERAPDF_REQUIRED=1fail-closed;VERAPDF_HOME,VERAPDF_REPORT_DIRsupported; Windows.batlauncher handled.package.json— new scriptscorpus:pdfaandvalidate:pdfa..github/workflows/verapdf.yml— blocking (nocontinue-on-error), pinnedveraPDF 1.30.2 installer with SHA-256 verified before
java -jar, report + rawXML uploaded as artifact and rendered in the job summary.
.github/workflows/publish.yml— the same veraPDF gate repeated pre-publish.Docs
Quick Start, 21-command reference, Node ≥ 22), KNOWLEDGE_BASE (§2/4/5/6/8/9/10),
CONTRIBUTING.md (new "PDF/A validation (veraPDF)" section: scripts, exit codes,
skip semantics, install recipes, PR checklist), CLAUDE.md, AGENTS.md, llms.txt, ROADMAP
(v1.4.0 released; Next cleared; deferred items recorded), samples/README,
CHANGELOG, release-notes/v1.4.0.md, CITATION.cff re-synchronised (was 1.2.0 / "six
composable commands"), CI matrix 22/24.
svgblocks were wrongly documented as non-JSON-usable;mathwas missing from therender --fontlist.Tests
tests/helpers/der.ts+tests/helpers/mock-pki.ts— offline mock PKI (root CA,signer with AIA/CRL-DP URLs, TSA, OCSP responder) issuing genuine DER structures,
ported from pdfnative's own unpublished test helper; validated against the library's
parsers.
(digests + DocTimeStamp), inspect/annotate/pagetree (boxes preservation), render
(charts v2 / print / strict / images), metadata, compare, batch manifest, schema.
thresholds (statements 79 / branches 68 / functions 83 / lines 79 — unchanged).
Independent audit (this release)
≤ 1.7.0 public surface vs planned CLI surface. Consensus finding (both auditors):
image blocks were the only generation capability unreachable from the CLI → fixed.
Additional accepted findings: verify/digest coherence,
/DocTimeStampvalidation,annotate --password, print-box inspection, visible-signature flags,--max-inflate-size,render --chunk-size, two documentation corrections. Deferredto ROADMAP: custom TTF loading, link annotations on existing PDFs, doctor language
enumeration.
accuracy of docs vs code; 2026 open-source standards) plus an arbiter judging finding
legitimacy; accepted findings applied. (Reports summarised in this PR's discussion.)
Validation
npm run typecheck:all— clean ·npm run lint— 0 errors ·npm run test:coverage— 600/600, thresholds met ·npm run build— ok ·npm audit --audit-level=high— 0 vulnerabilities.node dist/cli.cjs):--version= 1.4.0,--help,schema manifest(21 commands,E_NETWORK), completions include the new commands,and an end-to-end render → metadata → compare → inspect --signatures round-trip.
node samples/run-all.jsgreen; new.sh/.ps1samples executed offline onGit Bash + PowerShell.
npm run validate:pdfawith veraPDF 1.30.2 installed locally: 10 PASS +2 XFAIL (both negative canaries correctly rejected by the validator), exit 0.
setTimestampProvider/setRevocationProvider, RFC 2606.invalidURLs.Backward compatibility
fields are optional/additive;
signwithout new flags follows the 1.3.x code pathbyte-for-byte.
sign --timestampwas a reserved flag whose error message announced futureavailability — activating it is the documented contract, not a break.
$ids embed the CLI version and moved 1.3.0 → 1.4.0 (expected, pinned bytests).
change.
/ToUnicode, RTL fixes, boxpreservation) are documented in the CHANGELOG.
Out of scope (recorded in ROADMAP)
optimize(linearisation/recompression) — still blocked upstream.compare— no rasteriser upstream.modify—metadatacovers the metadata slice only.render --font-file(custom TTFs), link annotations on existing PDFs, doctorlanguage-pack enumeration, dedicated TSA timeout flags.
Self-review checklist
npm run typecheck:allcleannpm run lint0 errorsnpm run test:coveragegreen, thresholds unchanged and metnpm run build+ built-binary smoke test (node dist/cli.cjs --help, newcommands,
schema manifest)E_*)pdfnativeremains the only one)