Compare commits

..

1 Commits

Author SHA1 Message Date
7ce6467385 #225: read-trail master switch and written purpose limitation
Some checks failed
CI / Lint, typecheck, test (pull_request) Failing after 5s
CI / Build container images (pull_request) Has been skipped
CI / Auth e2e pack (pull_request) Has been skipped
CI / Import/export fidelity gate (pull_request) Has been skipped
New instance switch readTrail.enabled, default OFF: read logging is
employee monitoring in a works council's eyes — an ordinary instance
must not surveil reads. Off means no event is written ANYWHERE (no row,
no stdout line, verified by test); the api announces the switch position
once per boot, so an eventless trail is never ambiguous — a gap reads
as "was off", never "was lost".

The written purpose limitation ships as section 7 of the VS-NfD
security documentation (#228): what is recorded (no content, no titles,
no IPs, no fingerprinting), why (evidence for reads of marked content
only — variant A is the technical anchor of the promise), who may read
it (Site Admin, API-only), for how long (readTrail.retentionDays,
audited pruning), and what it may NOT be used for (no performance or
behaviour monitoring). The hardening guide's reference configuration
turns the trail on (reference value true) and points to that text; the
existing trail suites now enable the switch explicitly.

Refs #225.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AUtYMxwTCMHG9mVHnwbFg8
2026-07-31 12:33:04 +02:00

View File

@ -86,9 +86,17 @@ export class ReadTrailService {
/** States the switch position once at startup (issue #225): a trail
* without events must be distinguishable from a disabled trail the log
* line makes the gap explainable either way. */
* line makes the gap explainable either way. Must never fail the boot:
* healthz-only environments come up without a reachable database. */
async announceState(): Promise<void> {
if (await this.settings.get('readTrail.enabled')) {
let enabled: boolean;
try {
enabled = await this.settings.get('readTrail.enabled');
} catch {
this.logger.warn('read_trail: switch position unknown at startup (settings unavailable)');
return;
}
if (enabled) {
this.logger.info('read_trail: enabled — reads of classified pages are recorded');
} else {
this.logger.warn(