Skip to content

feat(rawsync): add hosted raw custody core - #1396

Merged
wesm merged 3 commits into
kenn-io:mainfrom
salmonumbrella:feat/hosted-raw-custody-core
Aug 18, 2026
Merged

wesm merged 3 commits into
kenn-io:mainfrom
salmonumbrella:feat/hosted-raw-custody-core

Conversation

@salmonumbrella

@salmonumbrella salmonumbrella commented Aug 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds the storage layer for raw-first hosted sync (#1352): the server keeps the
original agent session files, not just the parsed rows. With the source files
on hand, the server can re-parse after a parser fix or rebuild lost data.

Nothing calls this yet. There is no upload API, no server-side parsing, and no
change to local sync or pg push. Those come in later PRs.

How it works

A client uploads content-addressed objects, then a manifest that lists one
source (for example one Codex session file), its files, and the SHA-256 and
length of every piece.

  • internal/rawsync/manifest.go validates the manifest and produces one
    canonical JSON document. Its SHA-256 is the manifest ID. Tenant and device
    IDs are embedded, so it cannot be replayed under another identity. Unknown
    providers and RemoteSyncExcluded providers (Omnigent, Trae) are rejected.
  • internal/rawsync/object_store*.go stores objects and manifests immutably
    in the existing artifact store under a per-tenant prefix. Same content
    again is a no-op; different content under the same digest is a conflict.
  • internal/postgres/raw_ingest_*.go records verified objects, accepted
    manifests, each source's current head, and a parse job per manifest, all in
    one transaction. Same capture ID returns the same receipt. A manifest must
    name the current head as its parent (compare-and-swap), and every object it
    references must already be verified. Accepted rows are append-only.
  • internal/rawsync/service.go is the single entry point for later upload
    handlers. It rejects excluded providers and oversized objects before
    accepting bytes.

Notes for reviewers

  • Source keys and paths can be 4096 bytes, so unique keys use a SHA-256 of the
    text (see rawIngestDDL).
  • On the schema-current pg push fast path, a role without CREATE skips
    the raw custody DDL with a log line instead of failing the push.
  • End-to-end test: internal/postgres/raw_ingest_custody_pgtest_test.go.

Refs #1352

@roborev-ci

roborev-ci Bot commented Aug 13, 2026

Copy link
Copy Markdown

roborev: Combined Review (4ea6428)

Medium

  • internal/postgres/raw_ingest_schema.go:42: Composite B-tree keys include source_key and path, each permitted up to 4096 bytes. Valid, poorly compressible values can exceed PostgreSQL’s index-entry limit, causing head, manifest, or entry insertion to fail after the canonical manifest has already been stored. Use fixed-size digests in these keys or reduce validation limits to safely fit every composite index. Add an integration test with long, incompressible source keys and paths.

Reviewers: 2 done | Synthesis: codex, 11s | Total: 7m29s

@wesm

wesm commented Aug 16, 2026

Copy link
Copy Markdown
Member

looking at this

@roborev-ci

roborev-ci Bot commented Aug 16, 2026

Copy link
Copy Markdown

roborev: Combined Review (66863c0)

Medium-severity canonical manifest validation issue found.

Medium

  • internal/rawsync/manifest.go:207 — Validation accepts a CanonicalManifest containing a noncanonical Manifest (such as unsorted entries) because it compares only the regenerated ID, JSON, and object set. PostgreSQL may then store entry indexes from the noncanonical struct, diverging from the canonical JSON.
    • Fix: Compare the regenerated canonical Manifest with the supplied manifest, or return and persist the regenerated value.

Reviewers: 2 done | Synthesis: codex, 7s | Total: 4m38s

@wesm

wesm commented Aug 18, 2026

Copy link
Copy Markdown
Member

looking

- fix(rawsync): key raw custody indexes by fixed-size digests
- fix(rawsync): reject noncanonical manifest structs during validation
@wesm
wesm force-pushed the feat/hosted-raw-custody-core branch from 66863c0 to 4b0d043 Compare August 18, 2026 16:33
@roborev-ci

roborev-ci Bot commented Aug 18, 2026

Copy link
Copy Markdown

roborev: Combined Review (4b0d043)

High-risk provider exclusions can be bypassed during raw object uploads; one additional PostgreSQL compatibility issue exists.

High

  • internal/rawsync/service.go:49 — Object uploads lack provider context, allowing RemoteSyncExcluded providers—including sources with authentication secrets—to persist data before manifest validation. Bind uploads to a validated provider/capture and reject excluded providers before accepting bytes; reject their manifests as well.

Medium

  • internal/postgres/sync.go:436 — The schema-current fast path now runs mandatory DDL, breaking existing pg push deployments that use restricted non-CREATE roles. Treat insufficient-privilege errors as a best-effort skip here, consistent with vector schema setup, while preserving privileged bootstrap behavior.

Reviewers: 2 done | Synthesis: codex, 9s | Total: 7m41s

…oles

Reject unknown and RemoteSyncExcluded providers in manifest validation
and require a validated provider on object uploads and missing-object
checks, so excluded stores never reach custody. Skip raw custody DDL on
the schema-current pg push fast path when the role lacks CREATE
(SQLSTATE 42501) instead of failing the push.
@roborev-ci

roborev-ci Bot commented Aug 18, 2026

Copy link
Copy Markdown

roborev: Combined Review (cb0fcc6)

One medium-severity issue found; no material security regression identified.

Medium

  • internal/rawsync/service.go:66 — FinalizeObject persists objects larger than MaxFileBytes, even though no valid manifest can reference them, potentially retaining large orphaned uploads. Reject oversized objects before PutObject and enforce the same limit during missing-object negotiation.

Reviewers: 2 done | Synthesis: codex, 9s | Total: 8m15s

An object longer than MaxFileBytes can never be referenced by an accepted
manifest, so uploads and missing-object negotiation now reject it before
custody instead of retaining an orphan.
@roborev-ci

roborev-ci Bot commented Aug 18, 2026

Copy link
Copy Markdown

roborev: Combined Review (bdbf789)

No issues found.


Reviewers: 2 done | Synthesis: codex | Total: 7m49s

@wesm
wesm merged commit 3439cd0 into kenn-io:main Aug 18, 2026
29 of 30 checks passed
wesm pushed a commit that referenced this pull request Aug 20, 2026
Adds the server-side device authentication boundary for hosted raw custody.

Devices enroll once and keep a random credential; PostgreSQL stores only its
SHA-256 digest. Active devices exchange that credential for short-lived opaque
tokens scoped to negotiation, upload, commit, and status. Authentication derives
tenant and device identity from server-side records, and revocation invalidates
outstanding tokens.

This remains an internal foundation. #1459 does not add HTTP enrollment or
upload routes, the laptop uploader, server parsing, or server embeddings, so the
authenticated raw transport item in #1352 remains incomplete.

The Zensical guide now documents the completed raw custody foundation from
#1396, this authentication boundary, their security guarantees, the current
delivery status, and the unchanged `pg push` workflow.


Co-authored-by: Rusty Shackleford <salmonumbrella@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants