Commit Graph

3 Commits

Author SHA1 Message Date
45f1925917 #302: configurable pond start page, created with every new pond
Some checks failed
CI / Lint, typecheck, test (pull_request) Successful in 6m28s
CI / Import/export fidelity gate (pull_request) Has been skipped
CI / Auth e2e pack (pull_request) Failing after 4m1s
CI / Build container images (pull_request) Successful in 4m3s
Opening a pond landed on whatever sorted first in the sidebar — stable,
but a rule nobody could see, and one whose target moved as soon as
someone added a page ahead of it. New ponds landed on the empty-pond hint
instead of anything useful.

- `startPageId` joins the pond settings. No migration: `Pond.settings` is
  already jsonb. It stores an id, not a slug, so renaming or moving the
  page keeps it working.
- `PondHomePage` prefers it, but only when the page is in this user's
  page list. That list already holds just what they may see, so a start
  page hidden by a page-scoped grant — or trashed — falls back silently
  instead of landing them on a 404, and it costs no extra request.
- Both creation paths give the pond a start page, titled from the
  creator's stored locale. It happens after the creating transaction
  commits: the owner's grant is written inside it and permissions cache
  per pond, so creating the page any earlier would ask about rights the
  grant has not published yet. A failure is logged, not fatal — a pond
  without a start page still works.

`PagesModule` imported `PondsModule` without using it. Removing that
vestigial edge let PondsModule depend on PagesModule in the honest
direction instead of tying the two together with forwardRef.

Every pond created through the api now owns a page, which broke eight
suites whose teardown deleted ponds directly — `Page.pond` deliberately
has no cascade, because a real purge removes contents explicitly and
audits it. A shared `deletePondsWhere` helper deletes pages first. Two
tests that counted pages now account for the start page rather than
pretending the pond began empty.
2026-08-01 08:06:35 +02:00
05a979bac3 #222: read-access trail for classified pages
Some checks failed
CI / Lint, typecheck, test (pull_request) Successful in 6m25s
CI / Build container images (pull_request) Successful in 2m58s
CI / Auth e2e pack (pull_request) Successful in 8m35s
CI / Import/export fidelity gate (pull_request) Successful in 1m7s
CD / Deploy to Test (push) Blocked by required conditions
CD / Smoke tests against Test (push) Blocked by required conditions
CD / Promote to Int (push) Blocked by required conditions
CI / Auth e2e pack (push) Blocked by required conditions
CI / Import/export fidelity gate (push) Blocked by required conditions
CI / Build container images (push) Blocked by required conditions
CI / Lint, typecheck, test (push) Has been cancelled
CD / Build and push images (push) Has been cancelled
Instrument every full-content read channel for pages with
classification = vs_nfd (ADR 0023, variant A): SPA state fetch and read
rendering, public JSON content, no-JS shell, expanded embeds, public API
GET (incl. the MCP read_page path and write echoes), attachment download
under the #212 effective classification, all export shapes (markdown,
pond ZIP, account data export, queued docx/odt/pdf at enqueue), and
collab-token issuance as the api-side proxy for the WS join.

Events land in the new read_events table (no FKs — evidence survives
page purges and hard user deletions) with actor, session key
(session:/token:/job:/anon), page, pond, channel and the classification
at read time. Recording failures are NOT swallowed: a failed write
aborts the read (hard failure, the deliberate contrast to AuditService —
decision recorded in ADR 0023 and security.md §Logging, together with
the recorded residuals: content fragments and feeds).

One e2e test per channel proves both the event and its absence for
unclassified pages, plus the hard-failure semantics.

Refs #222.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AUtYMxwTCMHG9mVHnwbFg8
2026-07-31 12:12:55 +02:00
74970f6073 #199: SHA-256 integrity hashes for attachments
Some checks failed
CI / Lint, typecheck, test (pull_request) Successful in 6m12s
CI / Build container images (pull_request) Successful in 3m4s
CI / Auth e2e pack (pull_request) Successful in 8m35s
CI / Import/export fidelity gate (pull_request) Successful in 1m2s
CI / Import/export fidelity gate (push) Blocked by required conditions
CD / Build and push images (push) Successful in 29s
CD / Deploy to Test (push) Successful in 12s
CD / Smoke tests against Test (push) Successful in 1m35s
CD / Promote to Int (push) Successful in 12s
CI / Lint, typecheck, test (push) Successful in 6m10s
CI / Build container images (push) Has been skipped
CI / Auth e2e pack (push) Has been cancelled
Every upload stores the SHA-256 of its bytes, computed from the
in-memory buffer that is written — never by re-reading disk. Every
download re-hashes the stored object BEFORE the first byte leaves
(memory bounded by the max_file_bytes quota that gated the upload) and
fails closed on mismatch with attachment_integrity_failure; the
mismatch lands in the audit trail as file.integrity_failed with both
hashes. Detection of payload manipulation is the one integrity duty
par. 52 VSA leaves with the application — only it knows what the file
should be.

Pre-#199 rows are hashed by a bounded, idempotent backfill that rides
the existing nightly orphan-file-sweep job (no new scheduler job, job
fence untouched); unreadable files are logged and retried, never
silently skipped, and null-hash rows are served unverified only until
the backfill reaches them. Operator runbook note in security.md
(restore from backup, re-download, audit entry carries both hashes).

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