Repository navigation
v0.2.50.0 feat: credentials in captured values and output read [masked] before the chat or a saved history sees them (Cycle 0057 pt1) - #140
Merged
Conversation
…; VS Code keeps GPT6 Luna until GPT-6.1 Terra is listed (O7) - .coderabbit.yaml: reviews.auto_review.enabled false. CodeRabbit reads the PR branch's file, so this cycle's PRs open with no hosted review. - AGENTS.md: merge no longer waits for a hosted CodeRabbit approval; the local CodeRabbit CLI reviews each PR's final range. The VS Code model rule records the owner's 2026-10-27 choice.
…, 2026-10-27, Issue #139 O3)
…ch inputs (Issue #139) - nodeServerConfigSchema bounds one server run: the entry under packageRoot, the server's own port (1024-65535), one request (method, a path on the server, an optional bounded body with its content type) and the stops. - describeNodeServerConfigurationIssues words every violation with its field path and expectation and names codebook://help/node-server. - resolveNodeServerLaunch checks packageRoot, entry and the repository's own tsx loader by real path before anything spawns; a missing tsx or one linked from outside the repository is NODE_SERVER_SOURCE_REFUSED. - The node-test schema shares its stop schema and its required-value check (addStopInspectionIssues) with the new profile. Internal only: no profile, tool or help exposes node-server yet (pt2).
… port (Issue #139) - listenerToolPath starts lsof only from /usr/sbin/lsof or /usr/bin/lsof, and on Linux without it iproute2's ss from /usr/bin/ss, /bin/ss, /usr/sbin/ss or /sbin/ss; never from the search path, never Homebrew's iproute2mac ss on macOS, none on native Windows. - readPortListeners runs it within 3 s and 1 MiB and reads each listening socket's family, address, port and pid; lsof's silent exit 1 is no listener, while a timeout, a failure, a missing tool or an unreadable line is an unknown reading that never passes for 'no listener'. Internal only; the node-server run uses it in pt2.
…d credential-shaped values in browser and node-test captures, output, causes and diagnostics
…t and Stop v2's close order (Issue #139) - launchNodeServer starts node --inspect-brk=127.0.0.1:0 [--import <the repository's tsx loader>] <entry> in packageRoot, in its own process group, and waits for the announced inspector (45 s). - buildNodeServerEnvironment passes the node-test allowlist plus certificate locations only: no NODE_ENV, CI or proxy variables; the server's own .env is never read by Codebook. - The start journal names argv and paths relative to <workspace>, the inherited variable names (never values), the Node version and secretEnvironmentInherited: false. - close() detaches the debugger first, then SIGTERM, SIGKILL after 5 s (Stop v2: a server handling SIGTERM waits for an attached debugger). - Both launchers share watchOwnedProcess and captureProcessOutput, which redact each channel (task 8) before the tail and event split. - A test-only fixture server (src/tests/fixtures/node-server) drives the real-process tests; package.test.mjs asserts it never ships. Test change: package.test.mjs's no-fixture check now also matches a plural 'fixtures' folder and the node-server fixture's file names.
…range (Issue #139) - inspectNodeTestVariables masks its display through redactInspectedValue (now generic over the value), removing a nested ternary. - redactSecretText's docs link the real caller (redactInspectedValue). - resolveNodeServerLaunch refuses a path removed between its realpath and its stat with NODE_SERVER_SOURCE_REFUSED instead of a raw error. - The node-server start journal writes the repository root as <workspace>, not <workspace>/.
…rent's value preview (CodeRabbit, Issue #139) The debug adapter previews an expandable value with its members ({apiKey: 'x', host: 'y'}); the snapshot saved that preview for the parent while masking the apiKey child, and a node-test fact of the object kept it. redactValuePreview masks the value of every secret-named key (object and map previews, nested, quoted or bare) before the credential shapes, in debugger snapshots and in inspected values of both profiles. Red: the three new redactionContract tests failed against the unmasked preview; they pass now with the existing replay and inspection tests.
… in constants.ts (CodeRabbit, Issue #139)
…me, so the secret scan sees no literal credential (Issue #139) The pre-gate secret scan (gstack-pregate stage 1) flagged the redaction corpus's literal JWT, ghp_ token, private-key header and database URLs, a README example and a docs example. The tests now assemble them at run time with the same values; the README and redactSecretText's example use a scheme the scan does not read as a credential; the planted variable of the launcher test no longer has a secret-shaped name. No behaviour changes.
…v6 (Issue #139) An older ss prints IPv6 local addresses unbracketed (:::4100, ::1:4100); the family came from a leading bracket only, so an owned IPv6 listener read as IPv4. The family now comes from the address itself (a colon, or '*'). Found by the /ship Step 7 coverage audit; the new readPortListeners test failed before the fix. The same file also gains the audit's two tests for bracketed/zone-scoped IPv6 and malformed listener answers.
… capture and secret paths (Issue #139) - captureProcessOutput: a stalled or throwing delivery fails with the caller's words; an event never splits a surrogate pair; output past 32 KiB keeps the first 32 KiB raw and the last 32 KiB as the tail. - redactionContract: an inspected path through brackets, quotes or optional chaining to a secret name reads [masked].
- [CRITICAL, security] The secret-name rule masks keys named for a secret use (secretAccessKey, AWS_SECRET_ACCESS_KEY, signingKey, clientKey...), passphrase/pwd/pass/jwt/sid and session ids; publicKey, primaryKey and cacheKey stay visible. - [CRITICAL, red team] The repository-browser dev server's log is redacted statefully per channel before the application.closed journal and the readiness failure messages carry it (the raw tail stays internal for origin detection). - Provider keys: Stripe sk_/rk_ live/test, Slack xox?-, Google AIza, npm_, AWS ASIA. - The output redactor's fail-closed trigger matches anchored secret shapes only (no longer any :// or task- word), and an oversized private key block ends at the next line break after 16 KiB without its END. - Named constants: TCP_PORT_MAX, and the existing NANOSECONDS_PER_MILLISECOND reused for every hrtime reading. - README 'Masked values' names the widened rules. Test change: redactionContract's inspected-path row items[0].sessionId becomes items[0].publicKey, since sessionId is now a secret name by the security finding.
- [CRITICAL, security] The output redactor's oversized private-key drop counts only fresh text (the kept END-search tail was counted again on every chunk) and ends the block only at a line break of the fresh chunk past the 16 KiB limit, so a key in small chunks never releases its body. - [CRITICAL, QA] A line that follows an oversized key block in the same chunk is released (the overflowing text is the block's first dropped chunk); found by a real-process probe, replayed before repair. - The dev server's published log is trimmed lazily and cut at a UTF-8 character boundary (keepUtf8Tail, also used by captureProcessOutput). - DEVELOPMENT_SERVER_MAX_PORT and the debug proxy schema use TCP_PORT_MAX. - Tests: the dev server's stderr and stream-end flush; every provider prefix fails closed in streamed output; a token drop pending at stream end; the UTF-8 tail cut. The accepted >16 KiB key limit is documented.
… cells (Issue #139) Last-round findings of the third review pass (state machines), fixed under the owner's ship review limit: a stream that ends while an oversized private key is being dropped releases nothing more; an oversized token keeps being dropped across a chunk without whitespace and the output resumes after it. Tests only; no behaviour change.
…der the ship review limit (Issue #139) Last-round findings after the third review pass (owner: fix every last-round finding, Minor and below included): - Redactor: only a trailing run that may still become a secret waits for the next chunk (a secret start, two or more of its first characters, or a URL scheme); plain text is released at once, so output keeps its arrival order and time around a debugger stop (Codex structured P2). - Private-key labels and URL schemes are bounded, so crafted label runs or long runs cannot make the search quadratic (native Medium; a 12 MiB run stays linear). - After the 16 KiB drop limit an unterminated key resumes only at a line no key body can be (one with punctuation): a key padded with spaces no longer releases its body (Codex P1, reproduced with an Ed25519 key). - Block mode opens only for a private-key header; any other long token is dropped to the next whitespace (native minor). - A URL whose authority has not ended counts as a secret start, so a password after a long username is never released (Codex High). - The AWS key anchor matches redactSecretText's (Codex Medium). - The carry never splits a surrogate pair (Codex Medium). - A token start still held at a stream's end is masked, not released. - The dev server flushes each channel once, before application.closed is written as well as at the stream's end (Codex Medium). - A type inspection's kept variable carries a masked value (Codex P1). - A secret member previewed with a type or length prefix is masked with its body (Codex P1). Test changes: redactionContract's two post-limit tests resume at a punctuated line (a plain-words line after an unterminated key now stays dropped as possible key body); the 'trailing partial word is held' test becomes 'a trailing plain word is released at once while a URL waiting for its password is held', since plain words no longer wait.
…ng and output order (Issue #139) Two behaviours the 0.2.50.0 CHANGELOG names get their README sentence, as AGENTS.md requires: a type inspection keeps no real value (also for a member previewed with a length or type prefix), and only text that may still be a secret waits, so output keeps its order around a debugger stop.
Co-Authored-By: Claude <noreply@anthropic.com>
…heme at run time, so the secret scan sees no literal URL password (Issue #139)
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the
|
…ch Node itself passes to a child while coverage is collected (Issue #139) The exact-HEAD gate's `pnpm health` (c8) and CI test shard 13/14 (coverage upload) failed "an owned server announces its loopback inspector...": Node's spawn copies NODE_V8_COVERAGE into the env object of every child while the parent collects coverage, so the launcher's journal truthfully lists it among the inherited variable names. Test change: the allowlist assertion also accepts NODE_V8_COVERAGE, only when this test process itself has it set. Red: the HEAD test fails 1 of 5 with NODE_V8_COVERAGE set; green: 5 of 5 with it set and unset. No product change.
…ist, so pnpm health scores them (Issue #139) The exact-HEAD gate's `pnpm health` reported the request schema's anonymous superRefine arrow (cyclomatic 7) at CRAP 56: Fallow matched no Istanbul coverage to it and its static estimate counts it uncovered. The rules move to describeNodeServerRequestBodyIssues, a rule list (cyclomatic 3) the refinement adds at their fields; messages, order and fields are unchanged (nodeServerConfigSchemas.test.ts passes unchanged). `pnpm health` on the changed tree: exit 0, 7486 tests, 0 failed.
…t the stream's end; README names NODE_SERVER_SOURCE_REFUSED (CodeRabbit, Issue #139) Local CodeRabbit CLI r4 on the final range (3 Minor): - At a stream's end the held run was masked from its URL start, so `listening on http://127.0.0.1:4100` without a line break lost its origin. Now a URL whose numeric port closes its authority (followed by a path, query or fragment, or a loopback/IP host ending the output) is released at the end; what follows is judged again. A URL cut off after a user name (`http://admin:1234`) still reads [masked]. The in-stream hold and its 8 KiB fail-closed release are unchanged (r4's second finding asked to keep them). - extension/README.md's recovery table names NODE_SERVER_SOURCE_REFUSED, which CHANGELOG 0.2.50.0 lists. Tests: red first, the loopback/IP origin and the closed-authority URL tests fail on the previous redactor; the cut-off guard passes before and after.
This was referenced Oct 27, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #139 (Cycle 0057, a feature cycle: first of its three pull requests, per Owner decision O1). pt2 adds the
node-serverprofile through MCP; pt3 adds the skill route and the native trial N57. This PR does not close #139.Refs #139 (Cycle 0057, a feature cycle: first of its three pull requests, per Owner decision O1). pt2 adds the
node-serverprofile through MCP; pt3 adds the skill route and the native trial N57. This PR does not close #139.Summary
When a learner asked the chat to explain a login or a database call, every value Codebook captured went to the chat AI, Output › Codebook and the saved history as it was: a password in a variable, a
Bearerheader, a database URL with its password, a private key a test printed. The product goal says credentials stay out of chat and evidence; nothing enforced it.Now one redaction contract runs before every place Codebook publishes or saves a captured value, in every profile (browser, test, and the coming server profile):
[masked]with everything inside them: names ending in a secret word (password,secret,token,authorization,cookie,credential,session, …), keys named for a secret use (apiKey,AWS_SECRET_ACCESS_KEY,signingKey) andsessionId, also inside an object preview.tokenCount,sortKey,publicKeyandprimaryKeystay visible.[masked]in values, debugger snapshots, test output, the development server's log, failure causes and Output › Codebook: URL passwords, JWTs,Bearertokens, provider keys (sk-, Stripe, GitHub, Slack, Google, npm, AWS) and private-key blocks.The same PR lands the parts the server profile in pt2 builds on, unexposed (no profile, tool or help offers them yet): the
node-serverdeclaration with every refusal rule, the launcher with Part A's Stop v2 close order (detach the debugger, then SIGTERM), and the listener tool that reads which process listens on a port.Blast radius
The redaction sits on the publication paths of the existing browser and test profiles (
captureReplayDebugSnapshot,inspectNodeTestVariables,inspectConfiguredValues,launchNodeTest,launchDevelopmentServer,sanitizeCause,formatCodebookDiagnostic), so a value those runs captured may now read[masked]where it showed before. That is safe for stored data because no reader of saved studies or replays changed (script ran: the full suite, including every existing browser and node-test replay test, passes unchanged atffaf4a5f). The server modules have no caller yet (file:line read: no import outside their tests).Test Coverage
captureProcessOutput.test.ts); the review rounds then added tests in the existing files, each red without its fix.f4cc12be,60b9e018).ssIPv6 family test fails at HEAD beforef4cc12be· passes at base not run (base control off: tsc build) · passes after fixf4cc12be.pnpm testatb2b07d10: 7480 pass, 0 fail, 6 skipped).redactionContract's inspected-path rowitems[0].sessionId→items[0].publicKey(sessionIdbecame a secret name by the pass 1 security finding); two post-limit tests resume at a punctuated line and the "trailing partial word is held" test became "a trailing plain word is released at once while a URL waiting for its password is held" (Step 11 findings,1ff1d2d1); credential-shaped fixtures are joined at run time so the secret scan reads no literal (98233ef2,ffaf4a5f, same values). After/ship:launchNodeServer's allowlist assertion also acceptsNODE_V8_COVERAGE, only when the test process itself has it set — Node'sspawncopies that variable into every child while coverage is collected, so the gate'spnpm healthand CI shard 13/14 failed (d4b12d7b; red 4/5 with it set, green 5/5 with and without).Pre-Landing Review
/shipStep 9 ran three fixing cycles and did not converge (converged:false, the cap). Under the owner's ship review limit (AGENTS.md, 2026-10-23), every finding of the last round (Step 9 pass 3 and Step 11) was fixed, Minor and below included; no Critical or Major defect stays open, so no Issue records one.9270c855(the secret-name rule missed keys such asAWS_SECRET_ACCESS_KEY,signingKey,passphrase,sessionId; the browser profile's dev-server log reached theapplication.closedjournal and failure messages unredacted), plus 4 informational fixed (more provider key prefixes, a narrower fail-closed trigger, named port constants).22c84cf7(the private-key drop counted its kept tail twice, so a key in small chunks could release its body; a line after an oversized key in the same chunk was dropped, found by the QA probe), plus 6 notes fixed (dev-server stderr and end-flush tests, UTF-8-safe tail cut, port constants).ecf0fd09; no behaviour change.1ff1d2d1— a quadratic regex on crafted key labels; a space-padded private key releasing its body after the drop limit (reproduced with an Ed25519 key); a URL password released after a long user name; an AWS key anchor that differed between the two matchers; a carry splitting a surrogate pair; the dev server's held tail lost when the process exits before its stream ends; held output re-stamped out of order; a type inspection's kept variable and a length-prefixed preview left unmasked; block mode opened on any-----BEGIN; the >16 KiB key trade-off./ship, the exact-HEAD gate and the local CodeRabbit CLI on the final range found three more things, all fixed: the launcher test under coverage (d4b12d7b, above);pnpm healthscored the request schema's anonymous body-rule arrow at CRAP 56 because Fallow matched no coverage to it, so the rules became one named rule list with the same messages (22d6ba33); CodeRabbit r4's 3 Minor findings — a server's lasthttp://127.0.0.1:4100without a line break was masked whole at the stream's end, now a URL whose port closes its authority is released there while a URL cut off after a user name stays masked (red first), and the packaged README's recovery table now namesNODE_SERVER_SOURCE_REFUSED(b2b07d10).b2b07d10(results in Test plan).REVIEW_LOOP: passes=3 blocking_found=6 deferred=0 noted=0 fixed=16 scope=frozen
Gate edits: 11 listed, 2 read, 0 findings — the
package.test.mjshunk strengthens the VSIX check (no fixture in the package; kept), andnodeTestConfigSchemas.ts's stop-inspection rule moved toaddStopInspectionIssueswith the same validation (kept).Outside review: Codex adversarial completed (5 P1, fixed); Codex structured review completed (gate FAIL with 3 P1, fixed in
1ff1d2d1). Hosted CodeRabbit is off from this cycle (owner, 2026-10-27). Local reviews: open-code-review delegate 32/32 files (4 low, fixede575399a); local CodeRabbit CLI r1 (1 major, fixedee7c5866), r2 (1 trivial, fixed8d03fce3), r3 onffaf4a5f(0), r4 ond4b12d7b(3 Minor, fixedb2b07d10), r5 on the final rangeorigin/main..b2b07d10(0 findings).Exploratory QA
Functional smoke against real processes (report-only folders under the Mac's ignored
.gstack/qa-reports/):c57-pt1-ship-pass1): PASS 2/2 — a real launch of the pinned switch-time clone throughlaunchNodeServerwith Stop v2's close (port freed), and the refusal wording of a bad declaration.c57-pt1-ship-pass2): the published verdict is FAIL — captures 002/003 found a line after an oversized key block dropped with it; repaired red-first in22c84cf7, captures 004–006 PASS.c57-pt1-step11): PASS — the real launch again and an unterminated-key probe after the1ff1d2d1fixes.Design Review
No frontend files changed — design review skipped.
Eval Results
No prompt-related files changed — evals skipped. (The bundled skill stays 1.0.50.)
Scope Drift
Scope Check: CLEAN (pt1 per O1: tasks 5–8 and pt1's docs).
Plan Completion
pt1 scope of #139 (O1): 7 items — 4 DONE (tasks 5, 7, 8 and the Part A record), 1 CHANGED (task 6's fixture server is TypeScript compiled with the tests, still excluded from the VSIX and asserted by
package.test.mjs), 1 PARTIAL at audit time and done since (task 14's pt1 CHANGELOG and README), Part A confirmed by its verdict comment on #139.Issues
Refs #139
Verification Results
Step 8.1's checks: AC 2(a) the fixture launcher test — PASS in the gate's suite and in CI; AC 5 the existing browser and node-test replay tests — PASS unchanged; AC 8 the 15-check exact-HEAD gate on
b2b07d10, required CI and the local CodeRabbit CLI on the final range, and AC 10health:staticandhealth— results in Test plan below.Documentation
Status: current. No edits; read-only audit of base 5b992ea through HEAD b2b07d1 (committed content; the working tree is clean).
Scope: extension/README.md (Masked values section, recovery table), CHANGELOG.md 0.2.50.0 entry, and extension/src/utils/createOutputRedactor.ts as the source of truth for the redaction behavior after b2b07d1.
Documentation health:
Commits d4b12d7 (test only) and 22d6ba3 (refactor, same messages) need no doc change.
Coverage debt: none new. Diagram drift: none.
Test plan
The 15-check exact-HEAD gate (AGENTS.md Commands and checks, AC 8), with
LANG=en_US.UTF-8, ran onb2b07d10(treeb64fe053), every check exit 0 and the tree clean before and after:gstack-pregate --stage preflight --allow-repo-commands, secrets scan) on treeb64fe053: WARN, exit 0 — MEDIUM non-credential findings only (localhost test URLs, example internal hostnames in tests, Slack sample digits read as a phone number)pnpm format:check,pnpm typecheck,pnpm lint,pnpm health:static,pnpm dupes,pnpm dead-code: each exit 0pnpm test: 7486 tests, 7480 pass, 0 fail, 6 skippednode extension/scripts/<check>-qa.mjs verify <new folder>): study-bootstrap 288/288, wiki-reader-dom 55/55, study-reading-pose 12/12, understanding-focus 8/8, repository-return 26/26 cases passedpnpm test:package: 1081 tests, 1071 pass, 0 fail, 10 skippedpnpm health(alone): exit 0, measured suite 7486 tests (7480 passed, 6 skipped), health score 85 A, no finding above the measured baselinenode --test .codex/restore-product-context.test.mjs: 9/9b2b07d10: every check passes (Build, Format, Lint, TypeCheck, Test 1–14/14, Fallow health/dupes/dead-code, Reader DOM cases, package, Socket Security); hosted CodeRabbit skipped by policy (O6), split-files runs only onmainpushesorigin/main..b2b07d10(r5): 0 findingsEarlier gate runs, kept as evidence: at
ffaf4a5fpnpm healthwas refused (the launcher test under coverage) and 4 Reader DOM checks could not start their recording (Playwright's ffmpeg missing from this Mac's cache; installed withplaywright-cli install-browser ffmpeg, CI's Reader DOM passed); atd4b12d7bpnpm healthreported the CRAP finding fixed in22d6ba33.Honesty inventory: Gate edits: 11 listed, 2 read, 0 findings; Tests ran: tests 7486 (runner summary of the gate's
pnpm testonb2b07d10);converged:false(ship review limit; no open Critical or Major).🤖 Generated with Claude Code