feat(2245): signed provenance envelope for served tutorials - #2256
Merged
Merged
Conversation
Release 1.25.0 — DEV → main (PROD promotion)
Adds sourceCommit : String(64) to ContentFilesAspect, ContentCurrentAspect, and ContentHistoryAspect in db/_content-shape.cds. Threads the per-slug sourceCommits map from appendHandler in content-store.js through appendToSession in content-publish-session.js, stamping it on the ContentFiles entry and carrying it forward to ContentCurrent/ContentHistory in dualWriteCurrentAndHistory (both HANA SQL and SQLite CQL paths). Generates migration=3 for ContentFiles (ALTER TABLE ADD NVARCHAR(64)).
…finding count to report_ID
Exposes GET /content/tutorials/:slug/provenance (signed JWS envelope) and GET /.well-known/tutorial-provenance/jwks.json (public key set). Both routes are gated by the PROVENANCE_ENVELOPE_ENABLED DB flag. Provenance route registered before the *slug wildcard in server.js to prevent wildcard capture of the /provenance suffix. globalThis bridge added to provenance-keys.js (__setKeyForTest) to fix the Windows served-handler module-duplication issue — matches the established pattern from feature-flags/db-flags.js. srv-qa cp list updated with all five provenance-*.js files.
Extends the ContentCache to carry per-entry advisory metadata and emits X-Freshness-Confidence / X-Content-Provenance headers on both the cache-miss (fresh DB read) and cache-hit branches of serveStoredSlug when the PROVENANCE_ENVELOPE_ENABLED feature flag is ON. Headers are absent when the flag is OFF (fail-open: flag check, loadProvenanceInputs error, and null report all return null advisory → no headers set, serve path unaffected).
Wires ghMeta.lastCommitSha from fetch-tutorials through publish-content into the append POST body so the server can stamp sourceCommit on each ContentCurrent row. - publish-client.ts: extract pure buildAppendBody() helper (unit-testable), add sourceCommits to AppendInput; conditionally spreads it into the POST body — key absent entirely when no SHAs provided (back-compat) - fetch-tutorials.ts: write <slug-lowercase>.commit-sha sidecar to CACHE_DIR in both the cached and fetched branches after ghMeta is obtained - publish-content.ts: add buildSourceCommitsPayload() that reads those sidecars, build sourceCommitsAll alongside sourcesAll, pass sourceCommits: pickEntries(...) in every appendBatch call - test/unit/publish-content-source-commit.test.js: two cases — includes key when SHAs provided; omits key entirely when absent
…velope-spec # Conflicts: # srv/lib/content-store.js
This was referenced Sep 12, 2026
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.
Summary
Implements the signed provenance envelope (#2245) — a cryptographically signed freshness/provenance signal for served tutorials. Feature is DB-gated, default OFF, DEV-first, and fail-open everywhere.
What it adds
PROVENANCE_ENVELOPE_ENABLED— DB config (ImsConfigkeyflag.provenance.envelope), registered in the feature-flags registry (kind:'db'). Never env.jose(existing dep — no hand-rolled crypto). JWS envelope; public JWKS distribution;kid= JWK thumbprint; privatednever leaves the server.@requires/@restrictN/A by design):GET /content/tutorials/:slug/provenance→{ jws, jwks_url }GET /.well-known/tutorial-provenance/jwks.json→ public JWKSX-Freshness-Confidence+X-Content-Provenanceon the HTML serve path when the flag is ON (both cache-miss and warm-cache paths gated).ContentCurrent.sourceCommit(String(64)); migration fromcds build --production.FreshnessReportvia.orderBy('runAt desc').Security / ops
PROVENANCE_SIGNING_KEY(Ed25519 PKCS8 PEM) lives in the BTP Credential Store, surfaced as runtime env; rotation via/admin-ui/#secrets. No key material in source.srv/lib/additions audited against thesrv-qacplist in.deploy/mta.yaml;josepresent ingen/srv-qa/package.json.Testing
cds build --productionclean; migration=3 addssourceCommit NVARCHAR(64).Docs
docs/developers/reference/tutorials-ims-gotchas.md— "Signed provenance envelope (Executable, self-verifying, self-healing tutorials #2245)" section.CLAUDE.mdTop Gotchas pointer;testing-endpoints.mdendpoint rows.Built via subagent-driven development: per-task spec+quality review, whole-branch final review (APPROVED), fix wave for 3 Minor findings.
Closes #2245.