@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.
- package/README.md +37 -19
- package/dist/cli.js +21 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/doctor.js +20 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/guardian.js +22 -0
- package/dist/commands/guardian.js.map +1 -1
- package/dist/commands/install.js +20 -0
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/status.js +20 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/sync.js +20 -0
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/version.js +18 -0
- package/dist/commands/version.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/opencode.js +53 -0
- package/dist/lib/opencode.js.map +1 -1
- package/dist/lib/package.js +22 -0
- package/dist/lib/package.js.map +1 -1
- package/dist/lib/vvoc-paths.js +26 -0
- package/dist/lib/vvoc-paths.js.map +1 -1
- package/dist/plugins/guardian.js +42 -0
- package/dist/plugins/guardian.js.map +1 -1
- package/dist/plugins/memory-store.d.ts +2 -1
- package/dist/plugins/memory-store.js +78 -7
- package/dist/plugins/memory-store.js.map +1 -1
- package/dist/plugins/memory.js +43 -5
- package/dist/plugins/memory.js.map +1 -1
- package/dist/plugins/secrets-redaction/config.d.ts +26 -0
- package/dist/plugins/secrets-redaction/config.js +158 -0
- package/dist/plugins/secrets-redaction/config.js.map +1 -0
- package/dist/plugins/secrets-redaction/deep.d.ts +4 -0
- package/dist/plugins/secrets-redaction/deep.js +78 -0
- package/dist/plugins/secrets-redaction/deep.js.map +1 -0
- package/dist/plugins/secrets-redaction/engine.d.ts +14 -0
- package/dist/plugins/secrets-redaction/engine.js +113 -0
- package/dist/plugins/secrets-redaction/engine.js.map +1 -0
- package/dist/plugins/secrets-redaction/index.d.ts +2 -0
- package/dist/plugins/secrets-redaction/index.js +124 -0
- package/dist/plugins/secrets-redaction/index.js.map +1 -0
- package/dist/plugins/secrets-redaction/patterns.d.ts +26 -0
- package/dist/plugins/secrets-redaction/patterns.js +85 -0
- package/dist/plugins/secrets-redaction/patterns.js.map +1 -0
- package/dist/plugins/secrets-redaction/restore.d.ts +2 -0
- package/dist/plugins/secrets-redaction/restore.js +25 -0
- package/dist/plugins/secrets-redaction/restore.js.map +1 -0
- package/dist/plugins/secrets-redaction/session.d.ts +30 -0
- package/dist/plugins/secrets-redaction/session.js +113 -0
- package/dist/plugins/secrets-redaction/session.js.map +1 -0
- package/dist/plugins/secrets-redaction.d.ts +1 -0
- package/dist/plugins/secrets-redaction.js +16 -0
- package/dist/plugins/secrets-redaction.js.map +1 -0
- 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":"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"}
|
|
@@ -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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"}
|