feat(agent): catalog open-serve + members-only sync auth#1175
feat(agent): catalog open-serve + members-only sync auth#1175branarakic wants to merge 1 commit into
Conversation
|
|
||
| if (!needsAuth) { | ||
| const prefix = includeSharedMemory ? `workspace:${contextGraphId}` : contextGraphId; | ||
| const phaseSuffix = phase === 'meta' |
There was a problem hiding this comment.
🔴 Bug: unauthenticated phase: 'catalog' requests are still encoded as the plain cg|offset|limit text form, so the responder parses them as the default data phase instead of the new catalog phase. fetchPublicCatalog() will therefore hit the wrong handler (or an auth denial) instead of the open _catalog path. Add a |catalog suffix here, the same way meta/snapshot are encoded.
| // catalog quads cannot poison the authz-bearing creator/curator/allowlist | ||
| // fields. Mirrors refreshMetaFromCurator's persist+invalidate path. | ||
| if (result.quads.length > 0) { | ||
| await this.store.insert(result.quads); |
There was a problem hiding this comment.
🔴 Bug: this persists every quad returned by fetchSyncPages(), but the generic requester-side filter accepts any graph under did:dkg:context-graph:${contextGraphId}/…, not just <cg>/_catalog. A buggy or malicious peer can use the unauthenticated catalog path to inject _meta, _private, or VM quads into the local store. Before inserting, enforce q.graph === catalogGraph (and ideally the expected subject) for catalog fetches.
| // dct:accessRights — CATALOG_META_PREDICATES), so persisting peer-fetched | ||
| // catalog quads cannot poison the authz-bearing creator/curator/allowlist | ||
| // fields. Mirrors refreshMetaFromCurator's persist+invalidate path. | ||
| if (result.quads.length > 0) { |
There was a problem hiding this comment.
🔴 Bug: partial catalog fetches are treated as success. fetchSyncPages() can return completed: false with a partial page set on timeout, but this branch still inserts the truncated catalog and deletes the checkpoint, so the caller keeps a corrupted local _catalog graph and loses the resume cursor. Only persist/delete the checkpoint after result.completed === true, or surface the timeout as a failure.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
76fcd31 to
ccd5c2f
Compare
3423171 to
5ea5967
Compare
| // (`<source-cg>/_catalog`), the exact graph open-serve reads via | ||
| // `contextGraphCatalogUri`. The previous TARGET-CG data graph left | ||
| // outsiders with an empty `<source-cg>/_catalog`. | ||
| projectionGraph: (id) => contextGraphCatalogUri(id), |
There was a problem hiding this comment.
🔴 Bug: publicProjectionContextGraphId is only acting as an on/off switch here. The projection still gets written to contextGraphCatalogUri(id), and there are no other runtime references to that config, so configuring a separate public projection CG never actually publishes anything into that CG. Either route the write through target or drop the config until the destination behavior exists.
| * forwarded to `buildSyncRequest` so the responder gates it via the strict | ||
| * members-only `isMemberRecoveryAuthorized`). Default false ⇒ normal sync. | ||
| */ | ||
| recovery?: boolean; |
There was a problem hiding this comment.
🔴 Bug: this new recovery plumbing is still dead in production. fetchSyncPages accepts the flag, but DKGAgent.fetchSyncPages() still does not expose/forward it and there are no runtime call sites passing true, so member recovery continues to use the normal auth flow. Please wire the flag through the public fetch helper and the actual recovery caller, or add an end-to-end test that proves the recovery branch is exercised.
| // creator/curator/allowlist fields. Mirrors refreshMetaFromCurator's | ||
| // persist+invalidate path. | ||
| if (catalogQuads.length > 0) { | ||
| await this.store.insert(catalogQuads); |
There was a problem hiding this comment.
🟡 Issue: this refresh path only appends to the local <cg>/_catalog graph. If the remote catalog entry changes, stale triples like the previous dkg:committedRoot remain alongside the new ones, so local readers can observe multiple conflicting versions. Mirror persistCatalogEntry/emitPublicProjectionAfterPublish and replace the subject before inserting.
|
Closing as redundant — superseded by #1203 ( Verified against current No unique unmerged work. Reopen if I've missed something. |
Part 4/5 · base:
feat/public-context-graph-projection.The serve/auth side: cores serve a private CG's public catalog to outsiders, and member-only operations are authorized strictly.
<cg>/_catalogsubgraph to outsiders with no allowlist auth (readCatalogPagein graph-plan, the catalog branch in sync-handler, catalog admission in cg-resolve), keyed on the context-graph DID; all gated data stays members-only.recoveryflag on the sync request makes the responder enforce a hard-deny members-only gate (isMemberRecoveryAuthorized) on the cryptographically-recovered signer against a fresh_metagate, instead of the participant/peer fallback.catalog serve/read + auth tests green. Please do not merge before review / out of order.
🤖 Generated with Claude Code
Depends on #1172 — please merge that first.