

























@@ -10,22 +10,19 @@
1010 * pre-existing-byte detection (e.g., LKG fingerprint verification)
1111 * opt in via `acceptPreExistingSentinel: false`.
1212 */
13-import { describe, expect, it } from 'vitest';
14-import { setJsoncOcPath } from '../../jsonc/edit.js';
15-import { emitMd } from '../../emit.js';
16-import { emitJsonc } from '../../jsonc/emit.js';
17-import { parseJsonc } from '../../jsonc/parse.js';
18-import { emitJsonl } from '../../jsonl/emit.js';
19-import { parseJsonl } from '../../jsonl/parse.js';
20-import { parseOcPath } from '../../oc-path.js';
21-import { parseMd } from '../../parse.js';
22-import {
23-OcEmitSentinelError,
24-REDACTED_SENTINEL,
25-} from '../../sentinel.js';
13+import { describe, expect, it } from "vitest";
14+import { emitMd } from "../../emit.js";
15+import { setJsoncOcPath } from "../../jsonc/edit.js";
16+import { emitJsonc } from "../../jsonc/emit.js";
17+import { parseJsonc } from "../../jsonc/parse.js";
18+import { emitJsonl } from "../../jsonl/emit.js";
19+import { parseJsonl } from "../../jsonl/parse.js";
20+import { parseOcPath } from "../../oc-path.js";
21+import { parseMd } from "../../parse.js";
22+import { OcEmitSentinelError, REDACTED_SENTINEL } from "../../sentinel.js";
262327-describe('wave-21 sentinel guard cross-kind', () => {
28-it('S-01 jsonc round-trip echoes safely when raw contains pre-existing sentinel', () => {
24+describe("wave-21 sentinel guard cross-kind", () => {
25+it("S-01 jsonc round-trip echoes safely when raw contains pre-existing sentinel", () => {
2926// Pre-existing sentinel bytes are trusted — see emit-policy comment
3027// in jsonc/emit.ts. The strict mode below is the opt-in path for
3128// callers who want LKG-style fingerprint verification.
@@ -34,144 +31,130 @@ describe('wave-21 sentinel guard cross-kind', () => {
3431expect(emitJsonc(ast)).toBe(raw);
3532// Strict mode still rejects pre-existing sentinel for callers who
3633// explicitly opt in.
37-expect(() => emitJsonc(ast, { acceptPreExistingSentinel: false })).toThrow(
38-OcEmitSentinelError,
39-);
34+expect(() => emitJsonc(ast, { acceptPreExistingSentinel: false })).toThrow(OcEmitSentinelError);
4035});
413642-it('S-02 jsonl round-trip echoes safely; strict mode rejects', () => {
37+it("S-02 jsonl round-trip echoes safely; strict mode rejects", () => {
4338const raw = `{"x":"${REDACTED_SENTINEL}"}\n`;
4439const ast = parseJsonl(raw).ast;
4540expect(emitJsonl(ast)).toBe(raw);
46-expect(() => emitJsonl(ast, { acceptPreExistingSentinel: false })).toThrow(
47-OcEmitSentinelError,
48-);
41+expect(() => emitJsonl(ast, { acceptPreExistingSentinel: false })).toThrow(OcEmitSentinelError);
4942});
504351-it('S-03 md round-trip echoes safely; strict mode rejects', () => {
44+it("S-03 md round-trip echoes safely; strict mode rejects", () => {
5245const raw = `## Body\n\n- ${REDACTED_SENTINEL}\n`;
5346const ast = parseMd(raw).ast;
5447expect(emitMd(ast)).toBe(raw);
55-expect(() => emitMd(ast, { acceptPreExistingSentinel: false })).toThrow(
56-OcEmitSentinelError,
57-);
48+expect(() => emitMd(ast, { acceptPreExistingSentinel: false })).toThrow(OcEmitSentinelError);
5849});
595060-it('S-04 jsonc render mode walks every leaf for sentinel', () => {
51+it("S-04 jsonc render mode walks every leaf for sentinel", () => {
6152const ast = parseJsonc('{ "x": "ok" }').ast;
6253const tampered = {
6354 ...ast,
6455root: {
65-kind: 'object' as const,
56+kind: "object" as const,
6657entries: [
6758{
68-key: 'x',
59+key: "x",
6960line: 1,
70-value: { kind: 'string' as const, value: REDACTED_SENTINEL },
61+value: { kind: "string" as const, value: REDACTED_SENTINEL },
7162},
7263],
7364},
7465};
75-expect(() => emitJsonc(tampered, { mode: 'render' })).toThrow(
76-OcEmitSentinelError,
77-);
66+expect(() => emitJsonc(tampered, { mode: "render" })).toThrow(OcEmitSentinelError);
7867});
796880-it('S-05 jsonl render mode walks every value-line leaf', () => {
69+it("S-05 jsonl render mode walks every value-line leaf", () => {
8170const ast = parseJsonl('{"a":"ok"}\n').ast;
8271const tampered = {
8372 ...ast,
8473lines: [
8574{
86-kind: 'value' as const,
75+kind: "value" as const,
8776line: 1,
8877raw: '{"a":"ok"}',
8978value: {
90-kind: 'object' as const,
79+kind: "object" as const,
9180entries: [
9281{
93-key: 'a',
82+key: "a",
9483line: 1,
95-value: { kind: 'string' as const, value: REDACTED_SENTINEL },
84+value: { kind: "string" as const, value: REDACTED_SENTINEL },
9685},
9786],
9887},
9988},
10089],
10190};
102-expect(() => emitJsonl(tampered, { mode: 'render' })).toThrow(
103-OcEmitSentinelError,
104-);
91+expect(() => emitJsonl(tampered, { mode: "render" })).toThrow(OcEmitSentinelError);
10592});
10693107-it('S-06 setJsoncOcPath itself throws when the new value contains the sentinel', () => {
94+it("S-06 setJsoncOcPath itself throws when the new value contains the sentinel", () => {
10895// The substrate guard fires at write-time: setJsoncOcPath rebuilds
10996// raw via render mode emit, which scans every leaf. Defense-in-depth
11097// — even if a caller forgets to call emit afterward, the sentinel
11198// can't make it into an in-memory AST that pretends to be valid.
11299const ast = parseJsonc('{ "x": "ok" }').ast;
113100expect(() =>
114-setJsoncOcPath(ast, parseOcPath('oc://config/x'), {
115-kind: 'string',
101+setJsoncOcPath(ast, parseOcPath("oc://config/x"), {
102+kind: "string",
116103value: REDACTED_SENTINEL,
117104}),
118105).toThrow(OcEmitSentinelError);
119106});
120107121-it('S-07 sentinel embedded in deep nesting — render mode catches the leaf', () => {
108+it("S-07 sentinel embedded in deep nesting — render mode catches the leaf", () => {
122109// Round-trip echoes the pre-existing bytes (the workspace contract:
123110// a parsed file containing the sentinel as data is not "writing" it
124111// on emit). Render mode walks every leaf and rejects this caller-
125112// injected pattern — and a `setOcPath` followed by emit lands here.
126113const raw = JSON.stringify({ a: { b: { c: REDACTED_SENTINEL } } });
127114const ast = parseJsonc(raw).ast;
128115expect(emitJsonc(ast)).toBe(raw); // round-trip echo
129-expect(() => emitJsonc(ast, { mode: 'render' })).toThrow(OcEmitSentinelError);
116+expect(() => emitJsonc(ast, { mode: "render" })).toThrow(OcEmitSentinelError);
130117});
131118132-it('S-08 sentinel inside an array element triggers guard in render mode', () => {
133-const raw = JSON.stringify({ arr: ['ok', REDACTED_SENTINEL, 'ok'] });
119+it("S-08 sentinel inside an array element triggers guard in render mode", () => {
120+const raw = JSON.stringify({ arr: ["ok", REDACTED_SENTINEL, "ok"] });
134121const ast = parseJsonc(raw).ast;
135-expect(() => emitJsonc(ast, { mode: 'render' })).toThrow(OcEmitSentinelError);
122+expect(() => emitJsonc(ast, { mode: "render" })).toThrow(OcEmitSentinelError);
136123});
137124138-it('S-09 sentinel as object key in raw — strict mode catches it', () => {
125+it("S-09 sentinel as object key in raw — strict mode catches it", () => {
139126const raw = `{ "${REDACTED_SENTINEL}": 1 }`;
140127const ast = parseJsonc(raw).ast;
141128expect(emitJsonc(ast)).toBe(raw); // default-mode echo
142-expect(() => emitJsonc(ast, { acceptPreExistingSentinel: false })).toThrow(
143-OcEmitSentinelError,
144-);
129+expect(() => emitJsonc(ast, { acceptPreExistingSentinel: false })).toThrow(OcEmitSentinelError);
145130});
146131147-it('S-10 sentinel in jsonl malformed line — strict mode catches it', () => {
132+it("S-10 sentinel in jsonl malformed line — strict mode catches it", () => {
148133const raw = `${REDACTED_SENTINEL}\n`;
149134const ast = parseJsonl(raw).ast;
150135expect(emitJsonl(ast)).toBe(raw); // round-trip echoes verbatim
151-expect(() => emitJsonl(ast, { acceptPreExistingSentinel: false })).toThrow(
152-OcEmitSentinelError,
153-);
136+expect(() => emitJsonl(ast, { acceptPreExistingSentinel: false })).toThrow(OcEmitSentinelError);
154137});
155138156-it('S-11 partial sentinel substring does NOT trigger guard', () => {
139+it("S-11 partial sentinel substring does NOT trigger guard", () => {
157140const raw = '{ "x": "OPENCLAW_REDACTED" }';
158141const ast = parseJsonc(raw).ast;
159-expect(() => emitJsonc(ast)).not.toThrow();
142+expect(emitJsonc(ast)).toBe(raw);
160143});
161144162-it('S-12 sentinel guard error message includes the OcPath context (render mode)', () => {
145+it("S-12 sentinel guard error message includes the OcPath context (render mode)", () => {
163146// Render mode is the path that actually rejects caller-injected
164147// sentinel — round-trip just echoes, so the error context surfaces
165148// when render walks the offending leaf and constructs the path.
166149const raw = `{ "secret": "${REDACTED_SENTINEL}" }`;
167150const ast = parseJsonc(raw).ast;
168151try {
169-emitJsonc(ast, { mode: 'render', fileNameForGuard: 'config' });
170-expect.fail('should have thrown');
152+emitJsonc(ast, { mode: "render", fileNameForGuard: "config" });
153+expect.fail("should have thrown");
171154} catch (e) {
172155expect(e).toBeInstanceOf(OcEmitSentinelError);
173-expect(String(e)).toContain('oc://');
174-expect(String(e)).toContain('config');
156+expect(String(e)).toContain("oc://");
157+expect(String(e)).toContain("config");
175158}
176159});
177160});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。