opencode-secrets-obfuscation 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1 -31
  3. package/package.json +29 -23
  4. package/plugin.mjs +3841 -0
  5. package/.editorconfig +0 -12
  6. package/.github/workflows/ci.yml +0 -75
  7. package/.github/workflows/release.yml +0 -50
  8. package/.node-version +0 -1
  9. package/AGENTS.md +0 -23
  10. package/INSTALL.md +0 -104
  11. package/docs/checkpoint.md +0 -68
  12. package/docs/history/1-spec-review.md +0 -233
  13. package/docs/history/10-p0-launch-prerequisites-review.md +0 -186
  14. package/docs/history/11-p0-job-containment-review.md +0 -188
  15. package/docs/history/12-p0-api-client.md +0 -15
  16. package/docs/history/13-p0-status-review.md +0 -122
  17. package/docs/history/14-p0-containment-final-review.md +0 -84
  18. package/docs/history/15-config-source-implementation.md +0 -27
  19. package/docs/history/16-sanitizer-implementation.md +0 -65
  20. package/docs/history/17-store-policy-implementation.md +0 -36
  21. package/docs/history/18-pure-mvp-review.md +0 -182
  22. package/docs/history/19-pure-mvp-re-review.md +0 -142
  23. package/docs/history/2-p0-runtime-prerequisites.md +0 -163
  24. package/docs/history/20-pure-mvp-final-review.md +0 -116
  25. package/docs/history/21-pure-mvp-review-final.md +0 -109
  26. package/docs/history/22-pure-mvp-signoff-review.md +0 -113
  27. package/docs/history/23-pure-mvp-signoff-review.md +0 -75
  28. package/docs/history/24-owned-tools-implementation.md +0 -27
  29. package/docs/history/25-v2-plugin-integration.md +0 -53
  30. package/docs/history/26-owned-tools-review.md +0 -138
  31. package/docs/history/27-owned-tools-final-review.md +0 -93
  32. package/docs/history/28-owned-tools-signoff.md +0 -98
  33. package/docs/history/3-p0-harness-foundation.md +0 -105
  34. package/docs/history/4-p0-source-opening.md +0 -78
  35. package/docs/history/5-qualification-gate-review.md +0 -133
  36. package/docs/history/6-p0-infrastructure-review.md +0 -275
  37. package/docs/history/7-p0-job-containment.md +0 -29
  38. package/docs/history/8-p0-evidence-support.md +0 -52
  39. package/docs/history/9-p0-launch-plan.md +0 -88
  40. package/docs/spec/design.md +0 -111
  41. package/docs/spec/intent.md +0 -81
  42. package/docs/spec/plan.md +0 -78
  43. package/docs/testing.md +0 -157
  44. package/scripts/build-plugin.mjs +0 -84
  45. package/scripts/install-opencode-ci.ps1 +0 -39
  46. package/scripts/install-opencode-ci.sh +0 -27
  47. package/scripts/smoke.mjs +0 -105
  48. package/scripts/verify-package.mjs +0 -18
  49. package/src/README.md +0 -22
  50. package/src/budgets/index.ts +0 -49
  51. package/src/config/README.md +0 -4
  52. package/src/config/options.ts +0 -76
  53. package/src/diagnostics/README.md +0 -4
  54. package/src/opencode/v2/filter.ts +0 -350
  55. package/src/opencode/v2/index.ts +0 -86
  56. package/src/opencode/v2/runtime.ts +0 -207
  57. package/src/opencode/v2/transports/README.md +0 -5
  58. package/src/runtime/http-transport.ts +0 -20
  59. package/src/sanitize/README.md +0 -4
  60. package/src/sanitize/index.ts +0 -454
  61. package/src/sources/README.md +0 -5
  62. package/src/sources/dotenv.ts +0 -133
  63. package/src/sources/native/README.md +0 -5
  64. package/src/store/index.ts +0 -64
  65. package/tests/README.md +0 -26
  66. package/tests/contract/plugin-v2.test.ts +0 -29
  67. package/tests/fixtures/README.md +0 -9
  68. package/tests/fixtures/job-child.mjs +0 -18
  69. package/tests/fixtures/plugins/README.md +0 -8
  70. package/tests/fixtures/process-child.mjs +0 -20
  71. package/tests/fixtures/services/README.md +0 -10
  72. package/tests/integration/components.test.ts +0 -5
  73. package/tests/integration/transparent-runtime.test.ts +0 -97
  74. package/tests/integration/windows-job.test.ts +0 -71
  75. package/tests/p0-host/README.md +0 -24
  76. package/tests/p0-host/linux-job.sh +0 -61
  77. package/tests/p0-host/windows-job.ps1 +0 -51
  78. package/tests/p0-native/README.md +0 -33
  79. package/tests/p0-native/windows-handle-loader.tests.ps1 +0 -191
  80. package/tests/scaffold/repository.test.ts +0 -105
  81. package/tests/smoke/README.md +0 -37
  82. package/tests/smoke/cases.json +0 -17
  83. package/tests/smoke/qualification.json +0 -20
  84. package/tests/smoke/runtime-candidate.json +0 -111
  85. package/tests/support/README.md +0 -32
  86. package/tests/support/child-process.ts +0 -235
  87. package/tests/support/host-api.ts +0 -123
  88. package/tests/support/opencode-environment.ts +0 -239
  89. package/tests/support/qualification.ts +0 -154
  90. package/tests/support/recording-endpoint.ts +0 -242
  91. package/tests/support/run-directory.ts +0 -179
  92. package/tests/support/smoke-cases.ts +0 -289
  93. package/tests/unit/budgets.test.ts +0 -35
  94. package/tests/unit/config.test.ts +0 -40
  95. package/tests/unit/dotenv.test.ts +0 -72
  96. package/tests/unit/filter-size.test.ts +0 -132
  97. package/tests/unit/harness.test.ts +0 -228
  98. package/tests/unit/host-api.test.ts +0 -122
  99. package/tests/unit/opencode-environment.test.ts +0 -161
  100. package/tests/unit/qualification.test.ts +0 -128
  101. package/tests/unit/recording-endpoint.test.ts +0 -188
  102. package/tests/unit/sanitize.test.ts +0 -159
  103. package/tests/unit/smoke-cases.test.ts +0 -20
  104. package/tsconfig.json +0 -20
@@ -1,188 +0,0 @@
1
- import assert from "node:assert/strict"
2
- import { test } from "node:test"
3
- import { request } from "node:http"
4
- import { once } from "node:events"
5
- import { startRecordingEndpoint } from "../support/recording-endpoint.ts"
6
-
7
- test("recording fixture: actual loopback HTTP captures request bytes and returns scripted response", async () => {
8
- const endpoint = await startRecordingEndpoint({ responses: [{ status: 200, body: "fixture-response" }] })
9
- try {
10
- const response = await fetch(`${endpoint.url}/v1/messages`, {
11
- method: "POST",
12
- headers: { "x-synthetic": "capture-me", authorization: "Bearer fixture" },
13
- body: "synthetic-input",
14
- })
15
- assert.equal(response.status, 200)
16
- assert.equal(await response.text(), "fixture-response")
17
- const captures = endpoint.captures()
18
- assert.equal(captures.length, 1)
19
- assert.equal(captures[0]!.method, "POST")
20
- assert.equal(captures[0]!.headers["x-synthetic"], "capture-me")
21
- assert.equal(captures[0]!.headers.authorization, "Bearer fixture")
22
- assert.equal(captures[0]!.body.equals(Buffer.from("synthetic-input")), true)
23
- captures[0]!.body.fill(0)
24
- assert.equal(captures[0]!.headers["x-synthetic"], "capture-me", "header capture is independent of body zeroing")
25
- assert.equal(endpoint.captures()[0]!.body.equals(Buffer.from("synthetic-input")), true)
26
- } finally { await endpoint.close() }
27
- })
28
-
29
- test("recording fixture: an oversized body is rejected without retaining partial bytes", async () => {
30
- const endpoint = await startRecordingEndpoint({ responses: [{ status: 200, body: "ok" }], maxBodyBytes: 8 })
31
- try {
32
- const response = await fetch(endpoint.url, { method: "POST", body: "x".repeat(9) })
33
- assert.equal(response.status, 413)
34
- assert.equal(endpoint.captures().length, 0)
35
- assert.equal(endpoint.counts().rejected, 1)
36
- } finally { await endpoint.close() }
37
- })
38
-
39
- test("recording fixture: unscripted requests fail instead of silently succeeding", async () => {
40
- const endpoint = await startRecordingEndpoint({ responses: [] })
41
- try {
42
- assert.equal((await fetch(endpoint.url)).status, 503)
43
- assert.equal(endpoint.counts().attempted, 1)
44
- assert.equal(endpoint.counts().rejected, 1)
45
- } finally { await endpoint.close() }
46
- })
47
-
48
- test("recording fixture: request capacity is reserved before reading a body", async () => {
49
- const endpoint = await startRecordingEndpoint({ responses: [{ status: 200, body: "ok" }], maxRequests: 1 })
50
- try {
51
- assert.equal((await fetch(endpoint.url, { method: "POST", body: "first" })).status, 200)
52
- assert.equal((await fetch(endpoint.url, { method: "POST", body: "second" })).status, 503)
53
- assert.equal(endpoint.counts().attempted, 2)
54
- assert.equal(endpoint.captures().length, 1)
55
- } finally { await endpoint.close() }
56
- })
57
-
58
- test("recording fixture: closing clears private captures and is idempotent", async () => {
59
- const endpoint = await startRecordingEndpoint({ responses: [{ status: 200, body: "ok" }] })
60
- await fetch(endpoint.url, { method: "POST", body: "synthetic-input" })
61
- await endpoint.close()
62
- await endpoint.close()
63
- assert.equal(endpoint.captures().length, 0)
64
- await assert.rejects(fetch(endpoint.url), () => true)
65
- })
66
-
67
- test("recording fixture: invalid budgets and response plans fail with fixed diagnostics", async () => {
68
- for (const options of [
69
- { responses: [], maxBodyBytes: 0 },
70
- { responses: [], maxRequests: Infinity },
71
- { responses: [], timeoutMs: -1 },
72
- { responses: [{ status: 999, body: "unsafe-value-not-to-echo" }] },
73
- { responses: [{ status: 200, body: "x".repeat(1_048_577) }] },
74
- ]) {
75
- await assert.rejects(startRecordingEndpoint(options), (error: unknown) =>
76
- error instanceof Error && error.message === "FIXTURE_INVALID_OPTIONS")
77
- }
78
- })
79
-
80
- test("recording fixture: incomplete request bodies terminate at a deadline without capture", async () => {
81
- const endpoint = await startRecordingEndpoint({ responses: [{ status: 200, body: "ok" }], timeoutMs: 150 })
82
- const child = request(endpoint.url, { method: "POST", headers: { "content-length": "100" } })
83
- const outcome = new Promise<number>((resolve) => {
84
- child.on("response", (response) => { response.resume(); resolve(response.statusCode ?? 0) })
85
- child.on("error", () => resolve(0))
86
- })
87
- try {
88
- child.write("partial")
89
- const status = await outcome
90
- assert.ok(status === 0 || status === 408)
91
- assert.equal(endpoint.captures().length, 0)
92
- } finally { child.destroy(); await endpoint.close() }
93
- })
94
-
95
- test("recording fixture: closing an active socket discards pending data", async () => {
96
- const endpoint = await startRecordingEndpoint({ responses: [{ status: 200, body: "ok" }] })
97
- const child = request(endpoint.url, { method: "POST", headers: { "content-length": "100" } })
98
- child.on("error", () => {})
99
- try {
100
- const connected = once(child, "socket")
101
- child.write("partial")
102
- await connected
103
- const closed = new Promise<void>((resolve) => child.once("close", resolve))
104
- await endpoint.close()
105
- await closed
106
- assert.equal(endpoint.captures().length, 0)
107
- assert.equal(endpoint.counts().openConnections, 0)
108
- assert.equal(endpoint.counts().pendingRequests, 0)
109
- } finally { child.destroy(); await endpoint.close() }
110
- })
111
-
112
- test("recording fixture: a resolver selects scripted responses from request bodies", async () => {
113
- const endpoint = await startRecordingEndpoint({
114
- responses: [
115
- { status: 200, body: "title" },
116
- { status: 200, body: "toolcall" },
117
- { status: 200, body: "final" },
118
- ],
119
- resolve: ({ body }: { body: Buffer }) => {
120
- const text = body.toString("utf8")
121
- if (text.includes("tool-result")) return 2
122
- if (text.includes("title-generator")) return 0
123
- return 1
124
- },
125
- })
126
- try {
127
- const post = async (text: string) => {
128
- const response = await fetch(endpoint.url, { method: "POST", body: text })
129
- return { status: response.status, body: await response.text() }
130
- }
131
- assert.deepEqual(await post("title-generator prompt"), { status: 200, body: "title" })
132
- assert.deepEqual(await post("main prompt"), { status: 200, body: "toolcall" })
133
- assert.deepEqual(await post("main prompt with tool-result"), { status: 200, body: "final" })
134
- assert.equal(endpoint.captures().length, 3)
135
- assert.equal(endpoint.counts().rejected, 0)
136
- } finally { await endpoint.close() }
137
- })
138
-
139
- test("recording fixture: resolver failures, wrong types and out-of-range indices fail closed", async () => {
140
- for (const resolve of [
141
- () => 99,
142
- () => -1,
143
- () => "0",
144
- () => Number.NaN,
145
- () => { throw new Error("private-resolver-value") },
146
- ]) {
147
- const endpoint = await startRecordingEndpoint({ responses: [{ status: 200, body: "ok" }], resolve: resolve as never })
148
- try {
149
- const response = await fetch(endpoint.url, { method: "POST", body: "x" })
150
- assert.equal(response.status, 503)
151
- assert.equal(endpoint.counts().rejected, 1)
152
- } finally { await endpoint.close() }
153
- }
154
- await assert.rejects(startRecordingEndpoint({ responses: [], resolve: 5 as never }), (error: unknown) =>
155
- error instanceof Error && error.message === "FIXTURE_INVALID_OPTIONS")
156
- let invoked = false
157
- await assert.rejects(startRecordingEndpoint({
158
- responses: [],
159
- get resolve() { invoked = true; throw new Error("private-value") },
160
- }), (error: unknown) => error instanceof Error && error.message === "FIXTURE_INVALID_OPTIONS")
161
- assert.equal(invoked, false)
162
- })
163
-
164
- test("recording fixture: malformed runtime options fail without leaking input or invoking accessors", async () => {
165
- let invoked = false
166
- for (const options of [
167
- null, { responses: null }, { responses: [null] }, { responses: [{ status: 200, body: {} }] },
168
- { get responses() { invoked = true; throw new Error("private-value") } },
169
- ]) {
170
- await assert.rejects(startRecordingEndpoint(options), (error: unknown) =>
171
- error instanceof Error && error.message === "FIXTURE_INVALID_OPTIONS")
172
- }
173
- assert.equal(invoked, false)
174
- })
175
-
176
- test("recording fixture: resolvers receive captured headers for selection", async () => {
177
- const endpoint = await startRecordingEndpoint({
178
- responses: [{ status: 200, body: "scripted" }, { status: 200, body: "authorized" }],
179
- resolve: ({ headers }: { headers: Record<string, string> }) => headers.authorization === "Bearer fixture" ? 1 : 0,
180
- })
181
- try {
182
- const plain = await fetch(endpoint.url, { method: "POST", body: "x" })
183
- assert.equal(await plain.text(), "scripted")
184
- const authorized = await fetch(endpoint.url, { method: "POST", headers: { authorization: "Bearer fixture" }, body: "y" })
185
- assert.equal(await authorized.text(), "authorized")
186
- assert.equal(endpoint.counts().rejected, 0)
187
- } finally { await endpoint.close() }
188
- })
@@ -1,159 +0,0 @@
1
- import assert from "node:assert/strict"
2
- import { test } from "node:test"
3
- import {
4
- admitPatterns,
5
- canonicalTextSink,
6
- collectIntervals,
7
- projectPlain,
8
- sanitizeText,
9
- scanForSecrets,
10
- verifyCeilingBytes,
11
- type Pattern,
12
- representationsFor,
13
- } from "../../src/sanitize/index.ts"
14
-
15
- test("interval collection merges transitive overlaps independently of replacement", () => {
16
- const intervals = collectIntervals("abcdef", ["abc", "bcdef"])
17
- assert.deepEqual(intervals, [{ start: 0, end: 6, patterns: ["abc", "bcdef"] }])
18
- })
19
-
20
- test("sanitization replaces an overlap once and is idempotent", () => {
21
- const patterns: Pattern[] = [
22
- { text: "abc", replacement: "secret-11111111-1111-4111-8111-111111111111", entry: "a" },
23
- { text: "bcdef", replacement: "secret-22222222-2222-4222-8222-222222222222", entry: "b" },
24
- ]
25
- assert.equal(sanitizeText("abcdef", patterns), "[REDACTED]")
26
- assert.equal(sanitizeText("safe [REDACTED]", patterns), "safe [REDACTED]")
27
- })
28
-
29
- test("admission rejects UUID-language and reserved inventory conflicts as a whole", () => {
30
- assert.equal(admitPatterns([{ text: "e" }, { text: "safe-value" }]).ok, false)
31
- assert.equal(admitPatterns([{ text: "true" }]).ok, false)
32
- assert.equal(admitPatterns([{ text: "!" }]).ok, true)
33
- })
34
-
35
- test("canonical sink joins parts before matching and emits one text part", () => {
36
- const result = canonicalTextSink(["alpha", "beta"], [{ text: "alpha\nbeta", replacement: "!" }])
37
- assert.deepEqual(result, { content: [{ type: "text", text: "!" }] })
38
- })
39
-
40
- test("plain projection handles scalars and keys with bounds, without invoking user serialization", () => {
41
- const result = projectPlain({ token: "alpha", count: 123456, enabled: true }, [{ text: "alpha", replacement: "!" }])
42
- assert.equal(result, '{"count":123456,"enabled":true,"token":"!"}')
43
- assert.equal(projectPlain({ alpha: "value" }, [{ text: "alpha", replacement: "!" }]), null)
44
- assert.equal(projectPlain({ deep: { x: 1 } }, [], { maxDepth: 0 }), null)
45
- })
46
-
47
- test("construction budgets reject without returning a partial output", () => {
48
- assert.equal(sanitizeText("abcdef", [{ text: "abc", replacement: "!" }], { maxOutputBytes: 1 }), null)
49
- assert.equal(projectPlain({ x: "long" }, [], { maxOutputBytes: 3 }), null)
50
- })
51
-
52
- test("caller metadata cannot add representations outside the derived inventory", () => {
53
- const pattern: Pattern = { text: "token", representations: ["attacker-spelling"] }
54
- assert.equal(sanitizeText("attacker-spelling", [pattern]), "attacker-spelling")
55
- assert.equal(sanitizeText("token", [pattern]), "[REDACTED]")
56
- })
57
-
58
- test("dotenv inventory matches quoted, escaped, and multiline parser forms", () => {
59
- const value = 'a\\b"c\n\r\tline'
60
- const result = representationsFor(value)
61
- assert.ok(result)
62
- if (!result) throw new Error("expected representations")
63
- const inventory = result.dotenv
64
- assert.deepEqual(inventory, [
65
- `"a\\\\b\\"c\\n\\r\\tline"`,
66
- `'a\\b"c\n\r\tline'`,
67
- ])
68
- })
69
-
70
- test("active object identity is rejected instead of recursing forever", () => {
71
- const cyclic: { self?: unknown } = {}
72
- cyclic.self = cyclic
73
- assert.equal(projectPlain(cyclic, []), null)
74
- })
75
-
76
- test("default bounds reject excessive matches and output without partial results", () => {
77
- assert.equal(sanitizeText("x".repeat(200_000), [{ text: "x" }]), null)
78
- assert.equal(sanitizeText("safe".repeat(600_000), []), null)
79
- })
80
-
81
- test("sanitizer boundaries fail closed for throwing proxies and accessors", () => {
82
- const throwingObject = new Proxy({}, { getPrototypeOf: () => { throw new Error("x") } })
83
- const throwingKeys = new Proxy({}, { ownKeys: () => { throw new Error("x") } })
84
- const throwingPattern = Object.defineProperty({}, "text", { get: () => { throw new Error("x") } })
85
- const throwingBudget = Object.defineProperty({}, "maxNodes", { get: () => { throw new Error("x") } })
86
- assert.deepEqual(admitPatterns([throwingPattern as Pattern]), { ok: false, code: "SANITIZATION_UNAVAILABLE" })
87
- assert.equal(sanitizeText("x", [throwingPattern as Pattern]), null)
88
- assert.equal(projectPlain(throwingObject, []), null)
89
- assert.equal(projectPlain(throwingKeys, []), null)
90
- assert.equal(sanitizeText("x", [], throwingBudget), null)
91
- })
92
-
93
- test("sanitizer rejects oversized pattern inventories before expansion", () => {
94
- assert.deepEqual(admitPatterns(Array.from({ length: 10_000 }, () => ({ text: "safe" }))), {
95
- ok: false,
96
- code: "SANITIZATION_UNAVAILABLE",
97
- })
98
- assert.equal(sanitizeText("safe", [{ text: "x".repeat(100_000) }]), null)
99
- assert.equal(projectPlain({ value: "safe" }, [{ text: "x".repeat(100_000) }]), null)
100
- })
101
-
102
- test("sanitizer applies aggregate limits to every transform and releases reservations", () => {
103
- const many = Array.from({ length: 4_097 }, (_, index) => ({ text: `pattern-${index}` }))
104
- assert.deepEqual(collectIntervals("safe", many), [])
105
- assert.equal(sanitizeText("safe", many), null)
106
- assert.equal(canonicalTextSink(["safe"], many), null)
107
- assert.equal(projectPlain({ value: "safe" }, many), null)
108
- assert.equal(admitPatterns(many).ok, false)
109
- assert.equal(sanitizeText("safe", [{ text: "safe", replacement: "!" }]), "!")
110
- })
111
-
112
- test("sanitizer rejects explicit budgets above every hard ceiling", () => {
113
- assert.deepEqual(collectIntervals("x", ["x"], { maxMatches: 50_001 }), [])
114
- assert.equal(projectPlain({ value: "safe" }, [], { maxNodes: 50_001 }), null)
115
- assert.equal(projectPlain({ value: "safe" }, [], { maxDepth: 33 }), null)
116
- assert.equal(sanitizeText("safe", [], { maxOutputBytes: 2 * 1024 * 1024 + 1 }), null)
117
- })
118
-
119
- test("repeated matches are denied before materialization and reservations are released", () => {
120
- assert.deepEqual(collectIntervals("x".repeat(50_001), ["x"], { maxMatches: Number.MAX_SAFE_INTEGER }), [])
121
- assert.deepEqual(collectIntervals("x", ["x"]), [{ start: 0, end: 1, patterns: ["x"] }])
122
- })
123
-
124
- test("canonical sink contains throwing array proxies and releases reservations", () => {
125
- const throwingParts = new Proxy(["safe"], { get: () => { throw new Error("foreign") } })
126
- assert.equal(canonicalTextSink(throwingParts, []), null)
127
- assert.deepEqual(canonicalTextSink(["safe"], []), { content: [{ type: "text", text: "safe" }] })
128
- })
129
-
130
- test("plain projection bounds key enumeration before sorting under low node budgets", () => {
131
- const large = Object.fromEntries(Array.from({ length: 100_000 }, (_, index) => [`key-${index}`, "safe"]))
132
- assert.equal(projectPlain(large, [], { maxNodes: 1 }), null)
133
- })
134
-
135
- test("containment scan detects every representation class and verifies clean input", () => {
136
- const value = "Zebra_9x_canary"
137
- const patterns: Pattern[] = [{ text: value }]
138
- assert.equal(admitPatterns(patterns).ok, true)
139
- const derived = representationsFor(value)
140
- assert.ok(derived !== null)
141
- for (const spelling of [value, derived.dotenv[0] as string, derived.json, derived.percent[1] as string, derived.base64[0] as string]) {
142
- assert.equal(scanForSecrets(`prefix ${spelling} suffix`, patterns), "match")
143
- }
144
- assert.equal(scanForSecrets("verified clean payload", patterns), "clean")
145
- })
146
-
147
- test("containment scan fails closed as unverifiable instead of guessing", () => {
148
- const patterns: Pattern[] = [{ text: "Zebra_9x_canary" }]
149
- assert.equal(scanForSecrets("a".repeat(9 * 1024 * 1024), patterns), "unverifiable")
150
- assert.equal(scanForSecrets("safe", patterns, { maxMatches: -1 }), "unverifiable")
151
- assert.equal(scanForSecrets("safe", ["not-a-pattern" as unknown as Pattern]), "unverifiable")
152
- })
153
-
154
- test("verify ceiling is the operation ceiling minus admitted pattern bytes", () => {
155
- assert.equal(verifyCeilingBytes([]), 8 * 1024 * 1024)
156
- assert.equal(verifyCeilingBytes([{ text: "abcd" }]), 8 * 1024 * 1024 - 4)
157
- assert.equal(verifyCeilingBytes([null as unknown as Pattern]), 0)
158
- assert.equal(verifyCeilingBytes([{ text: "a".repeat(100_000) }, null as unknown as Pattern]), 0)
159
- })
@@ -1,20 +0,0 @@
1
- import assert from "node:assert/strict"
2
- import { test } from "node:test"
3
- import { parseOptions } from "../../src/config/options.ts"
4
- import { buildPluginOptions, smokePrompt } from "../support/smoke-cases.ts"
5
-
6
- test("smoke options describe only transparent source substitution", () => {
7
- const parsed = parseOptions(buildPluginOptions())
8
- assert.equal(parsed.version, 1)
9
- assert.deepEqual(parsed.sources.map((source) => source.id), ["smoke-env"])
10
- assert.deepEqual(parsed.sources[0]?.keys, ["SMOKE_ROUNDTRIP_TOKEN"])
11
- })
12
-
13
- test("smoke prompt carries only a base64 canary representation", () => {
14
- const canary = "smk_0123456789abcdef"
15
- const prompt = smokePrompt(canary)
16
- assert.ok(!prompt.includes(canary))
17
- assert.equal(prompt.split(Buffer.from(canary).toString("base64")).length, 2)
18
- assert.ok(!prompt.includes("credentials_read"))
19
- assert.ok(!prompt.includes("credential_http"))
20
- })
package/tsconfig.json DELETED
@@ -1,20 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2023",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "strict": true,
7
- "noEmit": true,
8
- "allowImportingTsExtensions": true,
9
- "verbatimModuleSyntax": true,
10
- "erasableSyntaxOnly": true,
11
- "isolatedModules": true,
12
- "noUncheckedIndexedAccess": true,
13
- "exactOptionalPropertyTypes": true,
14
- "forceConsistentCasingInFileNames": true,
15
- "skipLibCheck": true,
16
- "types": ["node"]
17
- },
18
- "include": ["src/**/*.ts", "tests/**/*.ts"],
19
- "exclude": ["node_modules", "dist", ".artifacts"]
20
- }