Skip to content

Sign articles and routed media with the Encypher provenance module - #1448

Draft
erik-sv wants to merge 18 commits into
IABTechLab:feature/55-scripts-in-cratesfrom
erik-sv:encypher/v2-provenance-module
Draft

erik-sv wants to merge 18 commits into
IABTechLab:feature/55-scripts-in-cratesfrom
erik-sv:encypher/v2-provenance-module

Conversation

@erik-sv

@erik-sv erik-sv commented Oct 24, 2026 •

Copy link
Copy Markdown

Summary

Sign eligible article text, routed media and source-embedded HTML/CSS media through provenance.encypher, with the core kept vendor-neutral. Add opt-in asynchronous prepared signing so a reader never signs, prepares, finalizes or uploads source media on a cache miss.

This contribution remains based on row 55 of the module-architecture stack tracked in #777: #1423, feature/55-scripts-in-crates. Tested candidate 99dee52d4 includes the current target base 1958b971a; it does not target the older module layout on main.

Closes #1456.

Asynchronous prepared mode

  • execution = "synchronous" remains the default. Select execution = "async_prepared" with the preparation table to use a publisher-operated native worker.
  • Readers reuse only completed, publication-verified results for the current content identity. Misses remain unsigned. Optional bounded reader hints cannot authorize signing; warming-only mode emits no hints. There is no synchronous or source-upload fallback.
  • The worker uses durable queue admission, leases and generation fences, retained exact results, quota bounds and a retirement outbox. Publisher warming, publication events and supplied inventory are independent of a publisher's eight-article warming limit. Inventory is not an origin crawler or upload-discovery service.
  • Eligible small and large media are prepared and hashed locally. Large media uses pinned ranges and a complete-source hash outside reader delivery. Existing provenance, source privacy and transformation restrictions remain enforced.
  • Exact text request, policy, title and page-URL binding prevents reuse of legacy coarse text-cache entries. Worker and delivery builds must be upgraded together against the matching API.
  • The real asset cache retains raw source copies. Prepared-result lookup decorates only the matching current copy; async delivery does not put a signed representation into that shared cache.
  • With an asset-cache module selected, asynchronous preparation requires loopback_url = "https://<public_host>". Equivalent trailing-slash and :443 forms are normalized. Another origin is refused so snapshots cannot silently select a different held-copy cache entry from readers. Cache-free local development and synchronous mode retain their existing origin rules.

Current policy/authority network checks remain. This change removes signing from delivery, not every network operation.

Operator documentation

Start the worker with trusted-server-axum preparation-worker --config worker.toml. The ts preparation CLI supplies authenticated warming, inventory registration, retirement and status. Use the documented secret-store/environment references; no credentials are included in this contribution.

The upstream cache-module, permission-policy and adapter contracts are preserved. The stock build does not invent a loading-cache implementation; compositions must select modules they actually register.

Verification on the integrated candidate

All 12 gate groups required by AGENTS.md passed, including:

  • Rust formatting and all eight target-matched clippy aliases.
  • Fastly, reusable Fastly, Axum, Cloudflare and Spin suites; native CLI tests; cross-adapter parity.
  • Native template-digest tests/lint, WASM clock and core platform-name checks.
  • JavaScript build, 1,256 tests and formatting.
  • Documentation lint/format/site build, Markdown formatting outside docs, documentation-proposal shellcheck and test suites.
  • Release Fastly, Spin and Cloudflare WASM builds, each checked for absence of a compiled operator permission policy.

Both final staging modes passed against the matching deployed API and signed probe: reader-trigger with the real cache composition, and warming-only with the stock native edge. They exercise native delivery and the durable worker, not mocked signing. A prior warming run failed the strict transport check; the clean rerun passed without relaxing assertions or changing product code.

  • Text, embedded PNG/SVG, standalone and variant assets verify independently; text and image mutations fail verification.
  • An 8,650,930-byte source completes pinned-range prepared signing with zero source uploads.
  • Readers finish while the signer is held. Warming-only reader misses create no job or hint.
  • Unchanged views/warming add no signatures; a changed image signs only itself.
  • Title/page metadata isolation, restart, empty result-cache recovery without re-signing, ten-target inventory before readers, privacy refusal and retirement survive the tested transitions.
  • Real 51Degrees asset/loading-cache modules pass raw-copy hits, published-result precedence, and authenticated snapshot/warming against the same fresh held copy after the origin changes. The original freshness deadline is not extended: expiry exposes the new unsigned bytes, rejects the old manifest and prepares one replacement.

Evidence limits and rollout

Staging verification used candidate-derived native builds with the existing staging public probe key substituted for the production pin, the existing native-TLS feature, and a supported composition of the real cache modules. Signature verification, release floor, ABI and artifact hashes were unchanged. These disposable builds are not included in this PR or distributed as release artifacts. Unchanged production trust behavior is covered separately.

Staging API transport was authenticated private Railway access. The cache scenario's snapshots traversed an owned public HTTPS gateway to the native HTTP edge with the same Host and scheme as reader requests. The gateway admitted only synthetic GET/HEAD routes; API, control, configuration and status routes were refused. Short-lived, path-bound snapshot capabilities crossed that TLS tunnel; worker/API credentials and publication secrets did not. This is not public API ingress, native edge TLS or deployed Fastly/Cloudflare/Spin proof.

The ten-second staging reader allowance includes SSH-mediated policy calls and is not a production latency claim. Held-signer ordering and zero reader-signing assertions remained enforced.

Coverage remains explicit: direct third-party responses, script-created SVGs and other assets outside configured routed/source surfaces are not automatically intercepted. The earlier whole-page experiment's unsigned direct third-party observations are not claimed fixed by async scheduling. This PR also does not fix the separate cross-block Chrome text-parsing issue.

The API, matching production probe, publisher worker and delivery configuration are separate rollout dependencies. Merging this PR does not activate async mode or update James's deployed Torque configuration.

A stream processor may implement StreamProcessor::async_finish over the
bytes its last process_chunk call returned. StreamProcessor::finish ends
a processor once; a processor made of others ends each in order, so each
is handed what the one before it finished with. Every publisher path that
can await now ends its processor this way: the no-hold pipeline, both
auction-hold loops, the serve pass on a shared template and the lazy
stream. A body read whole takes the same chunk pipeline, and the
synchronous stream_publisher_body path is removed.

A middleware is also told the response status and whether the origin
marked the response as one reader's, read before core writes its own
cache policy.
The Encypher signing integration becomes a serve middleware in
crates/provenance/encypher, selected by [provenance] module = "encypher"
and placed by a [[serve]] entry. Its preparation applies the request gates
with no I/O, and its stream processor signs the article in the
asynchronous finish core now awaits. The worker token is a module secret
setting. The enabled flag and path_prefixes give way to the selection and
the entry's path, and the module is offered on every adapter and the CLI.
…arrow the module's data claims

Adds a regression test that the parser-confirmed auction hold injects bids
into a document a middleware processor held and finished asynchronously.
States that the module skips pages the origin marks private but cannot
detect other personalized pages, so a deployment places it on public
article routes. Applies rustfmt and the docs formatter.
- Bound HTML scanning and canonical text extraction; one metadata pass
  saves the title, head close and manifest presence, and rendering
  allocates the signed output once at its exact size.
- Stop on malformed or absent head elements and empty manifest URLs
  without changing the page.
- Enforce signed-output and API-response limits incrementally in all
  four adapters, and document the Axum KV persistence behaviour.
- Fail open: any signing failure, timeout or private response passes the
  original page through unchanged.

Full repository checks pass (38 commands), plus a rebuilt Axum runtime
smoke of public, private, Set-Cookie and stalled-TLS cases.
Add a generic host for the signed prepared-hash probe release. It verifies
a release against the advertised contract (pinned Ed25519 key, revocation,
ABI 1, floor, 4 MiB artifact, SHA-256, sole env.host_read import, probe ABI
exports, probe_abi and version planner) and runs any operation by name.

Each host_read is checked against the source size and per-read bound in the
wasmi callback, then carried out as a resumable host trap, awaited outside
the interpreter straight into the release's buffer, and resumed, so reads
never block the executor and no operation is replayed. Calls run in fresh
instances bounded by fuel, memory, per-read, total-read and result limits.

Tests drive a WebAssembly-text stand-in with no format logic.
@erik-sv erik-sv changed the title Encypher text provenance as the provenance.encypher module Sign articles and routed media with the Encypher provenance module Oct 27, 2026
@erik-sv

erik-sv commented Oct 27, 2026

Copy link
Copy Markdown
Author

Updated to dde89ab, preserving the existing feature/55-scripts-in-crates base. All 12 required local gates and two independent review rounds are recorded in the PR and spec. The four GitHub workflow runs currently report action_required and need a maintainer to approve this fork contribution. This token has read-only upstream repository permissions, so it cannot approve those runs or merge. Please approve the workflows; the contribution remains subject to their results and normal review. The latest local real-API/browser run verified all 148 edge-served network observations; direct external and script-created media remain outside the coverage claim. This is source publication, not a production deployment.

@erik-sv

erik-sv commented Oct 27, 2026

Copy link
Copy Markdown
Author

The companion API implementation has landed, and its matching production probe release is published. The public verifier is released as v1.8.0.

Real staging signing passed for embedded PNG, detached BMP and large prepared PNG. The large source was 9,184,683 bytes; prepare and finalize uploaded 7,431 bytes, with the source unchanged. Independent public SDK verification checked signatures, hard bindings, supplied-root static trust and tamper refusal.

This staging proof used authenticated private operator transport and the existing signing-canary credential. It does not prove public manifest URL reachability, deployed Fastly behavior or complete page coverage. It does not replace the four upstream workflows still awaiting maintainer approval on this PR.

@erik-sv

erik-sv commented Nov 3, 2026

Copy link
Copy Markdown
Author

The asynchronous prepared-signing work is ready for maintainer review and merge at exact head 99dee52d496f24cce2ebdba2de68c7d2c6dec191.

The companion Encypher API implementation has merged and deployed. The reviewed candidate passed the local Rust/adapter, JavaScript, documentation and release-WASM checks described in the PR body. Both native staging modes passed: warming_only and reader_trigger, including unchanged-content reuse, changed-content preparation, restart recovery and the real 51Degrees cache composition.

This remains opt-in. Enabling the API's media-v2 creation gate and configuring a publisher's worker are separate rollout steps; existing deployments are unchanged. The staging evidence is not a claim of deployed Fastly, Cloudflare or Spin runtime verification, and no upstream CI success is being inferred from the local checks.

This branch has not been deployed

No deployments
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