@osovv/vv-opencode 0.2.4 → 0.3.0

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 (56) hide show
  1. package/README.md +37 -19
  2. package/dist/cli.js +21 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/doctor.js +20 -0
  5. package/dist/commands/doctor.js.map +1 -1
  6. package/dist/commands/guardian.js +22 -0
  7. package/dist/commands/guardian.js.map +1 -1
  8. package/dist/commands/install.js +20 -0
  9. package/dist/commands/install.js.map +1 -1
  10. package/dist/commands/status.js +20 -0
  11. package/dist/commands/status.js.map +1 -1
  12. package/dist/commands/sync.js +20 -0
  13. package/dist/commands/sync.js.map +1 -1
  14. package/dist/commands/version.js +18 -0
  15. package/dist/commands/version.js.map +1 -1
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.js +19 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/lib/opencode.js +53 -0
  20. package/dist/lib/opencode.js.map +1 -1
  21. package/dist/lib/package.js +22 -0
  22. package/dist/lib/package.js.map +1 -1
  23. package/dist/lib/vvoc-paths.js +26 -0
  24. package/dist/lib/vvoc-paths.js.map +1 -1
  25. package/dist/plugins/guardian.js +42 -0
  26. package/dist/plugins/guardian.js.map +1 -1
  27. package/dist/plugins/memory-store.d.ts +2 -1
  28. package/dist/plugins/memory-store.js +78 -7
  29. package/dist/plugins/memory-store.js.map +1 -1
  30. package/dist/plugins/memory.js +43 -5
  31. package/dist/plugins/memory.js.map +1 -1
  32. package/dist/plugins/secrets-redaction/config.d.ts +26 -0
  33. package/dist/plugins/secrets-redaction/config.js +158 -0
  34. package/dist/plugins/secrets-redaction/config.js.map +1 -0
  35. package/dist/plugins/secrets-redaction/deep.d.ts +4 -0
  36. package/dist/plugins/secrets-redaction/deep.js +78 -0
  37. package/dist/plugins/secrets-redaction/deep.js.map +1 -0
  38. package/dist/plugins/secrets-redaction/engine.d.ts +14 -0
  39. package/dist/plugins/secrets-redaction/engine.js +113 -0
  40. package/dist/plugins/secrets-redaction/engine.js.map +1 -0
  41. package/dist/plugins/secrets-redaction/index.d.ts +2 -0
  42. package/dist/plugins/secrets-redaction/index.js +124 -0
  43. package/dist/plugins/secrets-redaction/index.js.map +1 -0
  44. package/dist/plugins/secrets-redaction/patterns.d.ts +26 -0
  45. package/dist/plugins/secrets-redaction/patterns.js +85 -0
  46. package/dist/plugins/secrets-redaction/patterns.js.map +1 -0
  47. package/dist/plugins/secrets-redaction/restore.d.ts +2 -0
  48. package/dist/plugins/secrets-redaction/restore.js +25 -0
  49. package/dist/plugins/secrets-redaction/restore.js.map +1 -0
  50. package/dist/plugins/secrets-redaction/session.d.ts +30 -0
  51. package/dist/plugins/secrets-redaction/session.js +113 -0
  52. package/dist/plugins/secrets-redaction/session.js.map +1 -0
  53. package/dist/plugins/secrets-redaction.d.ts +1 -0
  54. package/dist/plugins/secrets-redaction.js +16 -0
  55. package/dist/plugins/secrets-redaction.js.map +1 -0
  56. package/package.json +5 -2
@@ -0,0 +1,158 @@
1
+ // FILE: src/plugins/secrets-redaction/config.ts
2
+ // VERSION: 1.0.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Loads and validates secrets-redaction config from file system with environment variable substitution.
5
+ // SCOPE: config file lookup, env substitution, default values
6
+ // DEPENDS: node:fs/promises, node:path
7
+ // LINKS: knowledge-graph://plugins/secrets-redaction
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // loadConfig - loads and returns normalized config
14
+ // getConfigCandidates - returns ordered candidate paths
15
+ // END_MODULE_MAP
16
+ import { readFile } from "node:fs/promises";
17
+ import { join } from "node:path";
18
+ import { generateFallbackSecret } from "./session.js";
19
+ export const DEFAULT_CONFIG = {
20
+ enabled: true,
21
+ secret: "",
22
+ ttlMs: 3_600_000,
23
+ maxMappings: 10_000,
24
+ patterns: {
25
+ keywords: [],
26
+ regex: [],
27
+ builtin: ["email", "china_phone", "china_id", "uuid", "ipv4", "mac"],
28
+ exclude: [],
29
+ },
30
+ debug: false,
31
+ };
32
+ const CONFIG_FILE_NAMES = ["secrets-redaction.config.json", "secrets-redaction.config.jsonc"];
33
+ function substituteEnvVars(value) {
34
+ return value.replace(/\$\{([^}]+)\}/g, (_, varName) => {
35
+ return process.env[varName] ?? "";
36
+ });
37
+ }
38
+ function deepClone(obj) {
39
+ if (obj === null || typeof obj !== "object")
40
+ return obj;
41
+ if (Array.isArray(obj))
42
+ return obj.map(deepClone);
43
+ const result = {};
44
+ for (const [k, v] of Object.entries(obj)) {
45
+ result[k] = deepClone(v);
46
+ }
47
+ return result;
48
+ }
49
+ function mergeConfig(base, override) {
50
+ const result = deepClone(base);
51
+ if (override.enabled !== undefined)
52
+ result.enabled = override.enabled;
53
+ if (override.secret !== undefined)
54
+ result.secret = override.secret;
55
+ if (override.ttlMs !== undefined)
56
+ result.ttlMs = override.ttlMs;
57
+ if (override.maxMappings !== undefined)
58
+ result.maxMappings = override.maxMappings;
59
+ if (override.debug !== undefined)
60
+ result.debug = override.debug;
61
+ if (override.patterns) {
62
+ if (override.patterns.keywords)
63
+ result.patterns.keywords = override.patterns.keywords;
64
+ if (override.patterns.regex)
65
+ result.patterns.regex = override.patterns.regex;
66
+ if (override.patterns.builtin)
67
+ result.patterns.builtin = override.patterns.builtin;
68
+ if (override.patterns.exclude)
69
+ result.patterns.exclude = override.patterns.exclude;
70
+ }
71
+ return result;
72
+ }
73
+ function parseJsonc(content) {
74
+ content = content.replace(/\/\/.*$/gm, "");
75
+ content = content.replace(/\/\*[\s\S]*?\*\//g, "");
76
+ return JSON.parse(content);
77
+ }
78
+ function configFromJson(json) {
79
+ const result = {};
80
+ if (json.enabled !== undefined)
81
+ result.enabled = Boolean(json.enabled);
82
+ if (json.secret !== undefined && typeof json.secret === "string")
83
+ result.secret = json.secret;
84
+ if (json.ttlMs !== undefined)
85
+ result.ttlMs = Number(json.ttlMs);
86
+ if (json.maxMappings !== undefined)
87
+ result.maxMappings = Number(json.maxMappings);
88
+ if (json.debug !== undefined)
89
+ result.debug = Boolean(json.debug);
90
+ if (json.patterns && typeof json.patterns === "object") {
91
+ const p = json.patterns;
92
+ result.patterns = {
93
+ keywords: [],
94
+ regex: [],
95
+ builtin: [],
96
+ exclude: [],
97
+ };
98
+ if (Array.isArray(p.keywords))
99
+ result.patterns.keywords = p.keywords;
100
+ if (Array.isArray(p.regex))
101
+ result.patterns.regex = p.regex;
102
+ if (Array.isArray(p.builtin))
103
+ result.patterns.builtin = p.builtin;
104
+ if (Array.isArray(p.exclude))
105
+ result.patterns.exclude = p.exclude;
106
+ }
107
+ return result;
108
+ }
109
+ export function getConfigCandidates(directory) {
110
+ const candidates = [];
111
+ const envPath = process.env.OPENCODE_SECRETS_REDACTION_CONFIG;
112
+ if (envPath)
113
+ candidates.push(envPath);
114
+ for (const name of CONFIG_FILE_NAMES) {
115
+ candidates.push(join(directory, name));
116
+ candidates.push(join(directory, ".opencode", name));
117
+ candidates.push(join(directory, ".vvoc", name));
118
+ }
119
+ const xdgConfig = process.env.XDG_CONFIG_HOME ?? join(process.env.HOME ?? "", ".config");
120
+ for (const name of CONFIG_FILE_NAMES) {
121
+ candidates.push(join(xdgConfig, "opencode", name));
122
+ candidates.push(join(xdgConfig, "vvoc", name));
123
+ }
124
+ return candidates;
125
+ }
126
+ export async function loadConfig(directory) {
127
+ const candidates = getConfigCandidates(directory);
128
+ const warnings = [];
129
+ for (const candidate of candidates) {
130
+ try {
131
+ const content = await readFile(candidate, "utf-8");
132
+ const json = parseJsonc(content);
133
+ const partial = configFromJson(json);
134
+ let finalSecret = partial.secret ?? DEFAULT_CONFIG.secret;
135
+ if (finalSecret) {
136
+ finalSecret = substituteEnvVars(finalSecret);
137
+ }
138
+ if (!finalSecret) {
139
+ finalSecret = generateFallbackSecret();
140
+ warnings.push(`No VVOC_SECRET env var set — using random fallback secret. Secrets won't be reversible across restarts.`);
141
+ }
142
+ const merged = mergeConfig(DEFAULT_CONFIG, { ...partial, secret: finalSecret });
143
+ return { config: merged, path: candidate, warnings };
144
+ }
145
+ catch {
146
+ // file not found or parse error — continue
147
+ }
148
+ }
149
+ const fallbackSecret = generateFallbackSecret();
150
+ warnings.push(`No secrets-redaction config found — using defaults with random secret.`);
151
+ warnings.push(`Set VVOC_SECRET env var and create $XDG_CONFIG_HOME/vvoc/secrets-redaction.config.json for persistent redaction.`);
152
+ return {
153
+ config: { ...DEFAULT_CONFIG, secret: fallbackSecret },
154
+ path: null,
155
+ warnings,
156
+ };
157
+ }
158
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/plugins/secrets-redaction/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type PlaceholderSession } from "./session.js";
2
+ import { type PatternSet } from "./patterns.js";
3
+ export declare function restoreDeep(value: unknown, session: PlaceholderSession): unknown;
4
+ export declare function redactDeep(value: unknown, patternSet: PatternSet, session: PlaceholderSession): unknown;
@@ -0,0 +1,78 @@
1
+ // FILE: src/plugins/secrets-redaction/deep.ts
2
+ // VERSION: 1.0.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Deep traversal helpers for restoring/redacting placeholders in nested objects and arrays.
5
+ // SCOPE: in-place object/array traversal, cycle-safe with WeakSet
6
+ // DEPENDS: session, restore, engine
7
+ // LINKS: knowledge-graph://plugins/secrets-redaction
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // restoreDeep - restores placeholders in objects/arrays in-place
14
+ // redactDeep - redacts secrets in objects/arrays in-place
15
+ // END_MODULE_MAP
16
+ import { redactText } from "./engine.js";
17
+ import { restoreText } from "./restore.js";
18
+ export function restoreDeep(value, session) {
19
+ if (value === null || value === undefined)
20
+ return value;
21
+ if (typeof value === "string")
22
+ return restoreText(value, session);
23
+ if (typeof value === "number" || typeof value === "boolean")
24
+ return value;
25
+ if (typeof value === "bigint")
26
+ return value;
27
+ if (Array.isArray(value)) {
28
+ for (let i = 0; i < value.length; i++) {
29
+ value[i] = restoreDeep(value[i], session);
30
+ }
31
+ return value;
32
+ }
33
+ if (typeof value === "object") {
34
+ const seen = new WeakSet();
35
+ return restoreDeepObject(value, session, seen);
36
+ }
37
+ return value;
38
+ }
39
+ function restoreDeepObject(obj, session, seen) {
40
+ if (seen.has(obj))
41
+ return obj;
42
+ seen.add(obj);
43
+ for (const key of Object.keys(obj)) {
44
+ obj[key] = restoreDeep(obj[key], session);
45
+ }
46
+ return obj;
47
+ }
48
+ export function redactDeep(value, patternSet, session) {
49
+ if (value === null || value === undefined)
50
+ return value;
51
+ if (typeof value === "string")
52
+ return redactText(value, patternSet, session).text;
53
+ if (typeof value === "number" || typeof value === "boolean")
54
+ return value;
55
+ if (typeof value === "bigint")
56
+ return value;
57
+ if (Array.isArray(value)) {
58
+ for (let i = 0; i < value.length; i++) {
59
+ value[i] = redactDeep(value[i], patternSet, session);
60
+ }
61
+ return value;
62
+ }
63
+ if (typeof value === "object") {
64
+ const seen = new WeakSet();
65
+ return redactDeepObject(value, patternSet, session, seen);
66
+ }
67
+ return value;
68
+ }
69
+ function redactDeepObject(obj, patternSet, session, seen) {
70
+ if (seen.has(obj))
71
+ return obj;
72
+ seen.add(obj);
73
+ for (const key of Object.keys(obj)) {
74
+ obj[key] = redactDeep(obj[key], patternSet, session);
75
+ }
76
+ return obj;
77
+ }
78
+ //# sourceMappingURL=deep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deep.js","sourceRoot":"","sources":["../../../src/plugins/secrets-redaction/deep.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { type PatternSet } from "./patterns.js";
2
+ import { type PlaceholderSession } from "./session.js";
3
+ export interface Match {
4
+ start: number;
5
+ end: number;
6
+ original: string;
7
+ placeholder: string;
8
+ category: string;
9
+ }
10
+ export interface RedactResult {
11
+ text: string;
12
+ matches: Match[];
13
+ }
14
+ export declare function redactText(input: string, patternSet: PatternSet, session: PlaceholderSession): RedactResult;
@@ -0,0 +1,113 @@
1
+ // FILE: src/plugins/secrets-redaction/engine.ts
2
+ // VERSION: 1.0.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Core redaction engine — performs find/replace of secrets with placeholders in text.
5
+ // SCOPE: text scanning, match sorting, interval arithmetic, replacement
6
+ // DEPENDS: session, patterns
7
+ // LINKS: knowledge-graph://plugins/secrets-redaction
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // redactText - replaces secrets in text with placeholders, returns changed text + match list
14
+ // END_MODULE_MAP
15
+ function subtractCovered(intervals) {
16
+ if (intervals.length === 0)
17
+ return [];
18
+ intervals.sort((a, b) => a[0] - b[0]);
19
+ const result = [];
20
+ let currentEnd = intervals[0][0];
21
+ for (const [start, end] of intervals) {
22
+ if (start > currentEnd) {
23
+ result.push([currentEnd, start]);
24
+ }
25
+ if (end > currentEnd) {
26
+ currentEnd = end;
27
+ }
28
+ }
29
+ return result;
30
+ }
31
+ function insertCovered(intervals, newInterval) {
32
+ const merged = [...intervals, newInterval];
33
+ merged.sort((a, b) => a[0] - b[0]);
34
+ const result = [];
35
+ for (const interval of merged) {
36
+ if (result.length > 0 && interval[0] <= result[result.length - 1][1]) {
37
+ result[result.length - 1][1] = Math.max(result[result.length - 1][1], interval[1]);
38
+ }
39
+ else {
40
+ result.push([...interval]);
41
+ }
42
+ }
43
+ return result;
44
+ }
45
+ function sortByPositionDesc(rules, text) {
46
+ const allMatches = [];
47
+ for (const rule of rules) {
48
+ const re = new RegExp(rule.pattern.source, rule.pattern.flags.includes("g") ? rule.pattern.flags : `${rule.pattern.flags}g`);
49
+ let match;
50
+ while ((match = re.exec(text)) !== null) {
51
+ allMatches.push({ rule, match: match });
52
+ }
53
+ }
54
+ allMatches.sort((a, b) => {
55
+ const aStart = a.match.index;
56
+ const bStart = b.match.index;
57
+ if (aStart !== bStart)
58
+ return bStart - aStart;
59
+ return (b.match[0].length - a.match[0].length);
60
+ });
61
+ return allMatches.map((x) => ({ rule: x.rule, matches: x.match }));
62
+ }
63
+ export function redactText(input, patternSet, session) {
64
+ if (!input || patternSet.rules.length === 0) {
65
+ return { text: input, matches: [] };
66
+ }
67
+ const sorted = sortByPositionDesc(patternSet.rules, input);
68
+ const covered = [];
69
+ const matches = [];
70
+ for (const { rule, matches: match } of sorted) {
71
+ const start = match.index;
72
+ const end = start + match[0].length;
73
+ const value = match[0];
74
+ if (patternSet.exclude.has(value.toLowerCase())) {
75
+ continue;
76
+ }
77
+ const gaps = subtractCovered(covered);
78
+ const isInside = gaps.every(([gStart, gEnd]) => start >= gStart && end <= gEnd);
79
+ if (isInside)
80
+ continue;
81
+ const placeholder = session.getOrCreatePlaceholder(value, rule.category);
82
+ matches.push({ start, end, original: value, placeholder, category: rule.category });
83
+ const remainingGaps = [];
84
+ for (const [gStart, gEnd] of gaps) {
85
+ if (start >= gEnd || end <= gStart) {
86
+ remainingGaps.push([gStart, gEnd]);
87
+ }
88
+ else {
89
+ if (start > gStart) {
90
+ remainingGaps.push([gStart, start]);
91
+ }
92
+ if (end < gEnd) {
93
+ remainingGaps.push([end, gEnd]);
94
+ }
95
+ }
96
+ }
97
+ covered.length = 0;
98
+ for (const g of remainingGaps) {
99
+ insertCovered(covered, g);
100
+ }
101
+ }
102
+ const sortedMatches = [...matches].sort((a, b) => a.start - b.start);
103
+ let result = "";
104
+ let lastIndex = 0;
105
+ for (const m of sortedMatches) {
106
+ result += input.slice(lastIndex, m.start);
107
+ result += m.placeholder;
108
+ lastIndex = m.end;
109
+ }
110
+ result += input.slice(lastIndex);
111
+ return { text: result, matches: sortedMatches };
112
+ }
113
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/plugins/secrets-redaction/engine.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,iBAAiB;AACjB,wBAAwB;AACxB,iGAAiG;AACjG,0EAA0E;AAC1E,+BAA+B;AAC/B,uDAAuD;AACvD,kBAAkB;AAClB,sBAAsB;AACtB,sBAAsB;AACtB,EAAE;AACF,mBAAmB;AACnB,+FAA+F;AAC/F,iBAAiB;AAkBjB,SAAS,eAAe,CAAC,SAA6B;IACpD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEtC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEtC,MAAM,MAAM,GAAuB,EAAE,CAAC;IACtC,IAAI,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEjC,KAAK,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,SAAS,EAAE,CAAC;QACrC,IAAI,KAAK,GAAG,UAAU,EAAE,CAAC;YACvB,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC;QACnC,CAAC;QACD,IAAI,GAAG,GAAG,UAAU,EAAE,CAAC;YACrB,UAAU,GAAG,GAAG,CAAC;QACnB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,aAAa,CACpB,SAA6B,EAC7B,WAA6B;IAE7B,MAAM,MAAM,GAAG,CAAC,GAAG,SAAS,EAAE,WAAW,CAAC,CAAC;IAC3C,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEnC,MAAM,MAAM,GAAuB,EAAE,CAAC;IACtC,KAAK,MAAM,QAAQ,IAAI,MAAM,EAAE,CAAC;QAC9B,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACrE,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QACrF,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAoB,EAAE,IAAY;IAC5D,MAAM,UAAU,GAA0D,EAAE,CAAC;IAE7E,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC;QAC7H,IAAI,KAA6B,CAAC;QAClC,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACxC,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAyB,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACvB,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,KAAM,CAAC;QAC9B,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,KAAM,CAAC;QAC9B,IAAI,MAAM,KAAK,MAAM;YAAE,OAAO,MAAM,GAAG,MAAM,CAAC;QAC9C,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,KAAa,EACb,UAAsB,EACtB,OAA2B;IAE3B,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5C,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACtC,CAAC;IAED,MAAM,MAAM,GAAG,kBAAkB,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAE3D,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,MAAM,OAAO,GAAY,EAAE,CAAC;IAE5B,KAAK,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,MAAM,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAM,CAAC;QAC3B,MAAM,GAAG,GAAG,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QACpC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAEvB,IAAI,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YAChD,SAAS;QACX,CAAC;QAED,MAAM,IAAI,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC;QAChF,IAAI,QAAQ;YAAE,SAAS;QAEvB,MAAM,WAAW,GAAG,OAAO,CAAC,sBAAsB,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzE,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QAEpF,MAAM,aAAa,GAAuB,EAAE,CAAC;QAC7C,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;YAClC,IAAI,KAAK,IAAI,IAAI,IAAI,GAAG,IAAI,MAAM,EAAE,CAAC;gBACnC,aAAa,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;YACrC,CAAC;iBAAM,CAAC;gBACN,IAAI,KAAK,GAAG,MAAM,EAAE,CAAC;oBACnB,aAAa,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;gBACtC,CAAC;gBACD,IAAI,GAAG,GAAG,IAAI,EAAE,CAAC;oBACf,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;gBAClC,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QACnB,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;YAC9B,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,MAAM,aAAa,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAErE,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,IAAI,CAAC,CAAC,WAAW,CAAC;QACxB,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC;IACpB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAEjC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC;AAClD,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Plugin } from "@opencode-ai/plugin";
2
+ export declare const SecretsRedactionPlugin: Plugin;
@@ -0,0 +1,124 @@
1
+ // FILE: src/plugins/secrets-redaction/index.ts
2
+ // VERSION: 1.0.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: OpenCode plugin that redacts secrets from messages before LLM requests and restores them after.
5
+ // SCOPE: 3 hook handlers — chat.messages.transform, text.complete, tool.execute.before
6
+ // DEPENDS: session, engine, patterns, restore, deep, config
7
+ // LINKS: knowledge-graph://plugins/secrets-redaction
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // SecretsRedactionPlugin - main plugin factory function
14
+ // END_MODULE_MAP
15
+ import { loadConfig } from "./config.js";
16
+ import { buildPatternSet } from "./patterns.js";
17
+ import { redactText } from "./engine.js";
18
+ import { restoreText } from "./restore.js";
19
+ import { redactDeep, restoreDeep } from "./deep.js";
20
+ import { PlaceholderSession } from "./session.js";
21
+ const PLACEHOLDER_PREFIX = "__VVOC_SECRET_";
22
+ function isTextPart(part) {
23
+ return part.type === "text";
24
+ }
25
+ function isReasoningPart(part) {
26
+ return part.type === "reasoning";
27
+ }
28
+ function redactMessageParts(parts, patternSet, session) {
29
+ for (const part of parts) {
30
+ if (isTextPart(part)) {
31
+ const result = redactText(part.text, patternSet, session);
32
+ part.text = result.text;
33
+ }
34
+ if (isReasoningPart(part)) {
35
+ const result = redactText(part.text, patternSet, session);
36
+ part.text = result.text;
37
+ }
38
+ }
39
+ }
40
+ function redactAssistantState(msg, patternSet, session) {
41
+ const state = msg.state;
42
+ if (state) {
43
+ if (state.input) {
44
+ redactDeep(state.input, patternSet, session);
45
+ }
46
+ if (state.output) {
47
+ redactDeep(state.output, patternSet, session);
48
+ }
49
+ if (state.error) {
50
+ redactDeep(state.error, patternSet, session);
51
+ }
52
+ if (state.raw) {
53
+ redactDeep(state.raw, patternSet, session);
54
+ }
55
+ }
56
+ }
57
+ export const SecretsRedactionPlugin = async (ctx) => {
58
+ const { config, path, warnings } = await loadConfig(ctx.directory);
59
+ if (config.debug) {
60
+ await ctx.client.app.log({
61
+ body: {
62
+ service: "secrets-redaction",
63
+ level: "debug",
64
+ message: `config loaded from: ${path ?? "none"}`,
65
+ },
66
+ });
67
+ }
68
+ for (const warning of warnings) {
69
+ await ctx.client.app.log({
70
+ body: {
71
+ service: "secrets-redaction",
72
+ level: "warn",
73
+ message: warning,
74
+ },
75
+ });
76
+ }
77
+ if (!config.enabled) {
78
+ return {};
79
+ }
80
+ const patternSet = buildPatternSet(config.patterns);
81
+ const session = new PlaceholderSession({
82
+ prefix: PLACEHOLDER_PREFIX,
83
+ ttlMs: config.ttlMs,
84
+ maxMappings: config.maxMappings,
85
+ secret: config.secret,
86
+ });
87
+ if (config.ttlMs > 0) {
88
+ setInterval(() => {
89
+ const evicted = session.cleanup(Date.now());
90
+ if (config.debug && evicted > 0) {
91
+ ctx.client.app.log({
92
+ body: {
93
+ service: "secrets-redaction",
94
+ level: "debug",
95
+ message: `evicted ${evicted} expired placeholders`,
96
+ },
97
+ });
98
+ }
99
+ }, Math.min(config.ttlMs, 60_000));
100
+ }
101
+ return {
102
+ config: async () => { },
103
+ event: async () => { },
104
+ "tool.execute.before": async (_input, output) => {
105
+ if (output.args) {
106
+ restoreDeep(output.args, session);
107
+ }
108
+ },
109
+ "experimental.chat.messages.transform": async (_input, output) => {
110
+ for (const msg of output.messages) {
111
+ if (msg.info.role === "assistant") {
112
+ redactAssistantState(msg.info, patternSet, session);
113
+ }
114
+ redactMessageParts(msg.parts, patternSet, session);
115
+ }
116
+ },
117
+ "experimental.text.complete": async (_input, output) => {
118
+ if (output.text) {
119
+ output.text = restoreText(output.text, session);
120
+ }
121
+ },
122
+ };
123
+ };
124
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/secrets-redaction/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export interface PatternRule {
2
+ pattern: RegExp;
3
+ category: string;
4
+ }
5
+ export interface PatternSet {
6
+ rules: PatternRule[];
7
+ exclude: Set<string>;
8
+ }
9
+ export interface PatternsConfig {
10
+ keywords?: Array<{
11
+ value: string;
12
+ category?: string;
13
+ }>;
14
+ regex?: Array<{
15
+ pattern: string;
16
+ category: string;
17
+ }>;
18
+ builtin?: string[];
19
+ exclude?: string[];
20
+ }
21
+ declare const BUILTIN_PATTERNS: Map<string, {
22
+ pattern: string;
23
+ category: string;
24
+ }>;
25
+ export declare function buildPatternSet(config: PatternsConfig): PatternSet;
26
+ export { BUILTIN_PATTERNS };
@@ -0,0 +1,85 @@
1
+ // FILE: src/plugins/secrets-redaction/patterns.ts
2
+ // VERSION: 1.0.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Builds the internal pattern set from config — keywords, regex rules, and builtin patterns.
5
+ // SCOPE: pattern parsing, normalization, deduplication
6
+ // DEPENDS: node:crypto (for hashing)
7
+ // LINKS: knowledge-graph://plugins/secrets-redaction
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // buildPatternSet - builds pattern set from config object
14
+ // BUILTIN_PATTERNS - Map of 6 builtin pattern definitions
15
+ // END_MODULE_MAP
16
+ const BUILTIN_PATTERNS = new Map([
17
+ ["email", { pattern: "[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,}", category: "EMAIL" }],
18
+ [
19
+ "china_phone",
20
+ { pattern: "(?<!\\d)1[3-9]\\d{9}(?!\\d)", category: "CHINA_PHONE" },
21
+ ],
22
+ [
23
+ "china_id",
24
+ { pattern: "(?<!\\d)\\d{17}[\\dXx](?!\\d)", category: "CHINA_ID" },
25
+ ],
26
+ [
27
+ "uuid",
28
+ {
29
+ pattern: "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}",
30
+ category: "UUID",
31
+ },
32
+ ],
33
+ [
34
+ "ipv4",
35
+ { pattern: "(?:\\d{1,3}\\.){3}\\d{1,3}", category: "IPV4" },
36
+ ],
37
+ ["mac", { pattern: "(?:[0-9a-f]{2}:){5}[0-9a-f]{2}", category: "MAC" }],
38
+ ]);
39
+ function peelFlags(pattern) {
40
+ const inlineFlags = [];
41
+ let p = pattern;
42
+ const iMatch = p.match(/^\(\?([a-z]+)\)/);
43
+ if (iMatch) {
44
+ const captured = iMatch[1];
45
+ if (captured.includes("i"))
46
+ inlineFlags.push("i");
47
+ if (captured.includes("m"))
48
+ inlineFlags.push("m");
49
+ if (captured.includes("s"))
50
+ inlineFlags.push("s");
51
+ p = p.slice(iMatch[0].length);
52
+ }
53
+ return { pattern: p, flags: inlineFlags.join("") };
54
+ }
55
+ function buildRegex(pattern, defaultFlags = "gi") {
56
+ const { pattern: raw, flags: peeled } = peelFlags(pattern);
57
+ const flags = peeled ? `${defaultFlags}${peeled}` : defaultFlags;
58
+ return new RegExp(raw, flags);
59
+ }
60
+ export function buildPatternSet(config) {
61
+ const rules = [];
62
+ if (config.builtin) {
63
+ for (const name of config.builtin) {
64
+ const builtin = BUILTIN_PATTERNS.get(name);
65
+ if (builtin) {
66
+ rules.push({ pattern: buildRegex(builtin.pattern), category: builtin.category });
67
+ }
68
+ }
69
+ }
70
+ if (config.regex) {
71
+ for (const { pattern, category } of config.regex) {
72
+ rules.push({ pattern: buildRegex(pattern), category });
73
+ }
74
+ }
75
+ if (config.keywords) {
76
+ for (const { value, category = "KEYWORD" } of config.keywords) {
77
+ const escaped = value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
78
+ rules.push({ pattern: new RegExp(escaped, "gi"), category });
79
+ }
80
+ }
81
+ const exclude = new Set(config.exclude ?? []);
82
+ return { rules, exclude };
83
+ }
84
+ export { BUILTIN_PATTERNS };
85
+ //# sourceMappingURL=patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../../src/plugins/secrets-redaction/patterns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { type PlaceholderSession } from "./session.js";
2
+ export declare function restoreText(input: string, session: PlaceholderSession): string;