draft: C04 bounded child results and authenticated recovery - #1168
draft: C04 bounded child results and authenticated recovery#1168sethkarten wants to merge 9 commits into
Conversation
| safeText(value.summary, MAX_SUMMARY_CHARS, MAX_SUMMARY_BYTES, "summary"); | ||
| safeText(value.preview, MAX_PREVIEW_CHARS, MAX_PREVIEW_BYTES, "preview"); |
There was a problem hiding this comment.
🟡 Medium core/rlm-child-results.ts:1335
assertReference calls safeText on value.summary, value.preview, and value.error.message but discards the returned sanitized strings, so the original unsanitized text stays on the object. As a result, a projection containing control characters, absolute paths, or API secrets passes validation and gets serialized and persisted by canonicalJson, defeating the redaction that safeText is supposed to enforce. Consider assigning the sanitized results back: value.summary = safeText(...), value.preview = safeText(...), and value.error.message = safeText(...).
- safeText(value.summary, MAX_SUMMARY_CHARS, MAX_SUMMARY_BYTES, "summary");
- safeText(value.preview, MAX_PREVIEW_CHARS, MAX_PREVIEW_BYTES, "preview");
+ value.summary = safeText(value.summary, MAX_SUMMARY_CHARS, MAX_SUMMARY_BYTES, "summary");
+ value.preview = safeText(value.preview, MAX_PREVIEW_CHARS, MAX_PREVIEW_BYTES, "preview");🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @packages/coding-agent/src/core/rlm-child-results.ts around lines 1335-1336:
`assertReference` calls `safeText` on `value.summary`, `value.preview`, and `value.error.message` but discards the returned sanitized strings, so the original unsanitized text stays on the object. As a result, a projection containing control characters, absolute paths, or API secrets passes validation and gets serialized and persisted by `canonicalJson`, defeating the redaction that `safeText` is supposed to enforce. Consider assigning the sanitized results back: `value.summary = safeText(...)`, `value.preview = safeText(...)`, and `value.error.message = safeText(...)`.
588eb41 to
02a5f93
Compare
| const { root } = parse(absolute); | ||
| let current = root; | ||
| for (const part of relative(root, absolute).split(/[/\\]/).filter(Boolean)) { |
There was a problem hiding this comment.
🟠 High core/rlm-child-results.ts:1270
canonicalDirectoryNoSymlinks resolves the requested path with realpathSync before walking its ancestors, so the ancestor walk only inspects the canonical (symlink-free) path. When the original requested path contains a symlink component (e.g. /state-link/session-artifacts/id where /state-link is a symlink), the function returns absolute without ever rejecting that symlink. This defeats the stated no-symlink binding check and lets a redirected path pass the C04 filesystem safety boundary that should reject it. Walk the ancestors of the requested path (or check each requested ancestor with lstatSync before resolving) so symlink components in the original path are detected.
const absolute = realpathSync(requested);
const { root } = parse(absolute);
let current = root;
+ const requestedParts = relative(root, requested).split(/[/\\]/).filter(Boolean);
+ let requestedCurrent = root;
+ for (const part of requestedParts) {
+ requestedCurrent = join(requestedCurrent, part);
+ const rst = lstatSync(requestedCurrent);
+ if (!rst.isDirectory() || rst.isSymbolicLink()) throw new Error("C04 rejects symlink/non-directory ancestor");
+ }
for (const part of relative(root, absolute).split(/[/\\]/).filter(Boolean)) {🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @packages/coding-agent/src/core/rlm-child-results.ts around lines 1270-1272:
`canonicalDirectoryNoSymlinks` resolves the requested path with `realpathSync` before walking its ancestors, so the ancestor walk only inspects the canonical (symlink-free) path. When the original requested path contains a symlink component (e.g. `/state-link/session-artifacts/id` where `/state-link` is a symlink), the function returns `absolute` without ever rejecting that symlink. This defeats the stated no-symlink binding check and lets a redirected path pass the C04 filesystem safety boundary that should reject it. Walk the ancestors of the *requested* path (or check each requested ancestor with `lstatSync` before resolving) so symlink components in the original path are detected.
C04 bounded child results — validation/security review draft
Draft only: this is not merge-ready. Validation and security review continue through the 1 / 100 / 500 gates.
Scope
Safety and rollback
Exact integration
perf/c03-durable-terminal-deliveryatd2776b2d62e87e2ba01675aa1d613f32f8ebd51d(PR C03: durable terminal delivery #1166 current head)perf/c04-bounded-child-resultsat02a5f939f11697de1e0163be3fda461dcf7a939242afc919f0e43ded880aa8a2d7088f31b264da95onto the C03 head. No rebase conflicts occurred.Validation
git diff --checkpassed.npx tsgo --noEmitpassed.c04-producer-sink,rlm-child-results, anddaemon-c03-real-production.Note
Add C04 bounded child result storage with authenticated recovery and artifact streaming
rlm-child-resultsmodule implementing immutable, owner-bound terminal child result storage with MAC-authenticated reservation journals, artifact streaming, quota enforcement, and capability-based reads.createOrGetTerminalChildResultto atomically publish or idempotently retrieve a terminal child result, with strict ownership validation, inode/digest TOCTOU guards, and reconciliation of abandoned reservations from dead processes.C04ProducerSinkinagent-session.ts, a bounded 128 KiB async iterable sink that captures text deltas during child agent runs and feeds the artifact writer; overflow rejects the consumer iterator.AgentSessionsubagent spawning: on completion/cancellation under a fenced assignment, the parent now receives a canonical C04 result projection instead of a plaincompleted_without_replynotice.getC04ParentRecoveryAuthoritytoSessionManagerto materialize a 32-byte recovery key under the session artifact directory using atomiclink(2)and strict 0600 permissions.📊 Macroscope summarized 2482983. 3 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted
🗂️ Filtered Issues
No issues evaluated.