@aictrl/hush 0.1.6 → 0.1.7

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 (47) hide show
  1. package/.gitlab-ci.yml +59 -0
  2. package/README.md +150 -3
  3. package/dist/cli.js +30 -17
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/init.d.ts +9 -0
  6. package/dist/commands/init.d.ts.map +1 -0
  7. package/dist/commands/init.js +81 -0
  8. package/dist/commands/init.js.map +1 -0
  9. package/dist/commands/redact-hook.d.ts +12 -0
  10. package/dist/commands/redact-hook.d.ts.map +1 -0
  11. package/dist/commands/redact-hook.js +89 -0
  12. package/dist/commands/redact-hook.js.map +1 -0
  13. package/dist/index.js +1 -1
  14. package/dist/middleware/redactor.d.ts +5 -0
  15. package/dist/middleware/redactor.d.ts.map +1 -1
  16. package/dist/middleware/redactor.js +69 -0
  17. package/dist/middleware/redactor.js.map +1 -1
  18. package/dist/plugins/opencode-hush.d.ts +21 -0
  19. package/dist/plugins/opencode-hush.d.ts.map +1 -0
  20. package/dist/plugins/opencode-hush.js +25 -0
  21. package/dist/plugins/opencode-hush.js.map +1 -0
  22. package/dist/plugins/sensitive-patterns.d.ts +15 -0
  23. package/dist/plugins/sensitive-patterns.d.ts.map +1 -0
  24. package/dist/plugins/sensitive-patterns.js +69 -0
  25. package/dist/plugins/sensitive-patterns.js.map +1 -0
  26. package/dist/vault/token-vault.d.ts.map +1 -1
  27. package/dist/vault/token-vault.js +16 -3
  28. package/dist/vault/token-vault.js.map +1 -1
  29. package/examples/team-config/.claude/settings.json +19 -0
  30. package/examples/team-config/.codex/config.toml +4 -0
  31. package/examples/team-config/.opencode/plugins/hush.ts +76 -0
  32. package/examples/team-config/opencode.json +10 -0
  33. package/package.json +11 -1
  34. package/scripts/e2e-plugin-block.sh +142 -0
  35. package/scripts/e2e-proxy-live.sh +185 -0
  36. package/src/cli.ts +28 -16
  37. package/src/commands/init.ts +107 -0
  38. package/src/commands/redact-hook.ts +124 -0
  39. package/src/index.ts +1 -1
  40. package/src/middleware/redactor.ts +75 -0
  41. package/src/plugins/opencode-hush.ts +30 -0
  42. package/src/plugins/sensitive-patterns.ts +71 -0
  43. package/src/vault/token-vault.ts +18 -4
  44. package/tests/init.test.ts +101 -0
  45. package/tests/opencode-plugin.test.ts +148 -0
  46. package/tests/redact-hook.test.ts +142 -0
  47. package/tests/redaction.test.ts +96 -0
@@ -0,0 +1,21 @@
1
+ /**
2
+ * OpenCode Plugin: Hush PII Guard
3
+ *
4
+ * Blocks reads of sensitive files (`.env`, `*.pem`, `credentials.*`, etc.)
5
+ * before the tool executes — the AI model never sees the content.
6
+ *
7
+ * Defense-in-depth: works alongside the Hush proxy which redacts PII from
8
+ * API requests. The plugin prevents file reads; the proxy catches anything
9
+ * that slips through in normal files.
10
+ *
11
+ * Install: copy to `.opencode/plugins/hush.ts` and add to `opencode.json`:
12
+ * { "plugin": [".opencode/plugins/hush.ts"] }
13
+ */
14
+ export declare const HushPlugin: () => Promise<{
15
+ 'tool.execute.before': (input: {
16
+ tool: string;
17
+ }, output: {
18
+ args: Record<string, string>;
19
+ }) => Promise<void>;
20
+ }>;
21
+ //# sourceMappingURL=opencode-hush.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode-hush.d.ts","sourceRoot":"","sources":["../../src/plugins/opencode-hush.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,eAAO,MAAM,UAAU;mCAEZ;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,UACf;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE;EAU1C,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * OpenCode Plugin: Hush PII Guard
3
+ *
4
+ * Blocks reads of sensitive files (`.env`, `*.pem`, `credentials.*`, etc.)
5
+ * before the tool executes — the AI model never sees the content.
6
+ *
7
+ * Defense-in-depth: works alongside the Hush proxy which redacts PII from
8
+ * API requests. The plugin prevents file reads; the proxy catches anything
9
+ * that slips through in normal files.
10
+ *
11
+ * Install: copy to `.opencode/plugins/hush.ts` and add to `opencode.json`:
12
+ * { "plugin": [".opencode/plugins/hush.ts"] }
13
+ */
14
+ import { isSensitivePath, commandReadsSensitiveFile } from './sensitive-patterns.js';
15
+ export const HushPlugin = async () => ({
16
+ 'tool.execute.before': async (input, output) => {
17
+ if (input.tool === 'read' && isSensitivePath(output.args['filePath'] ?? '')) {
18
+ throw new Error('[hush] Blocked: sensitive file');
19
+ }
20
+ if (input.tool === 'bash' && commandReadsSensitiveFile(output.args['command'] ?? '')) {
21
+ throw new Error('[hush] Blocked: command reads sensitive file');
22
+ }
23
+ },
24
+ });
25
+ //# sourceMappingURL=opencode-hush.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode-hush.js","sourceRoot":"","sources":["../../src/plugins/opencode-hush.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAErF,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,IAAI,EAAE,CAAC,CAAC;IACrC,qBAAqB,EAAE,KAAK,EAC1B,KAAuB,EACvB,MAAwC,EACxC,EAAE;QACF,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YAC5E,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACpD,CAAC;QAED,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,yBAAyB,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YACrF,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Shared helpers for detecting sensitive file paths and commands.
3
+ * Used by the OpenCode hush plugin to block reads of secret files.
4
+ */
5
+ /**
6
+ * Check whether a file path points to a sensitive file.
7
+ * Matches against the basename only so absolute/relative paths both work.
8
+ */
9
+ export declare function isSensitivePath(filePath: string): boolean;
10
+ /**
11
+ * Check whether a bash command reads a sensitive file.
12
+ * Looks for common read commands followed by a sensitive filename.
13
+ */
14
+ export declare function commandReadsSensitiveFile(cmd: string): boolean;
15
+ //# sourceMappingURL=sensitive-patterns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sensitive-patterns.d.ts","sourceRoot":"","sources":["../../src/plugins/sensitive-patterns.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAmBH;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGzD;AAUD;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CA2B9D"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Shared helpers for detecting sensitive file paths and commands.
3
+ * Used by the OpenCode hush plugin to block reads of secret files.
4
+ */
5
+ /** Glob-style patterns for files that should never be read by AI tools. */
6
+ const SENSITIVE_GLOBS = [
7
+ /^\.env($|\..*)/, // .env, .env.local, .env.production, etc.
8
+ /credentials/i,
9
+ /secret/i,
10
+ /\.pem$/,
11
+ /\.key$/,
12
+ /\.p12$/,
13
+ /\.pfx$/,
14
+ /\.jks$/,
15
+ /\.keystore$/,
16
+ /\.asc$/,
17
+ /^id_rsa/,
18
+ /^\.netrc$/,
19
+ /^\.pgpass$/,
20
+ ];
21
+ /**
22
+ * Check whether a file path points to a sensitive file.
23
+ * Matches against the basename only so absolute/relative paths both work.
24
+ */
25
+ export function isSensitivePath(filePath) {
26
+ const basename = (filePath.split('/').pop() ?? '').trim();
27
+ return SENSITIVE_GLOBS.some((re) => re.test(basename));
28
+ }
29
+ /** Commands that read file contents (includes batcat — Ubuntu symlink for bat). */
30
+ const READ_COMMANDS = /\b(cat|head|tail|less|more|bat|batcat)\b/;
31
+ /** Strip shell metacharacters that could wrap a filename to bypass detection. */
32
+ function stripShellMeta(token) {
33
+ return token.replace(/[`"'$(){}]/g, '');
34
+ }
35
+ /**
36
+ * Check whether a bash command reads a sensitive file.
37
+ * Looks for common read commands followed by a sensitive filename.
38
+ */
39
+ export function commandReadsSensitiveFile(cmd) {
40
+ if (!READ_COMMANDS.test(cmd))
41
+ return false;
42
+ // Check input redirections: `cat <.env` or `cat < .env`
43
+ // The file after `<` is read by the preceding command.
44
+ const redirectPattern = /<\s*([^\s|;&<>]+)/g;
45
+ let rMatch;
46
+ while ((rMatch = redirectPattern.exec(cmd)) !== null) {
47
+ if (isSensitivePath(stripShellMeta(rMatch[1])))
48
+ return true;
49
+ }
50
+ // Split on pipes, semicolons, &&, and redirections to get individual commands
51
+ const parts = cmd.split(/[|;&<>]+/);
52
+ for (const part of parts) {
53
+ const tokens = part.trim().split(/\s+/);
54
+ const cmdIndex = tokens.findIndex((t) => READ_COMMANDS.test(t));
55
+ if (cmdIndex === -1)
56
+ continue;
57
+ // Check all tokens after the command for sensitive paths (skip flags).
58
+ for (let i = cmdIndex + 1; i < tokens.length; i++) {
59
+ const token = tokens[i];
60
+ if (token.startsWith('-'))
61
+ continue; // skip flags like -n, -5
62
+ const cleaned = stripShellMeta(token);
63
+ if (isSensitivePath(cleaned))
64
+ return true;
65
+ }
66
+ }
67
+ return false;
68
+ }
69
+ //# sourceMappingURL=sensitive-patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sensitive-patterns.js","sourceRoot":"","sources":["../../src/plugins/sensitive-patterns.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,2EAA2E;AAC3E,MAAM,eAAe,GAAG;IACtB,gBAAgB,EAAE,0CAA0C;IAC5D,cAAc;IACd,SAAS;IACT,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,aAAa;IACb,QAAQ;IACR,SAAS;IACT,WAAW;IACX,YAAY;CACb,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,MAAM,QAAQ,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1D,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,mFAAmF;AACnF,MAAM,aAAa,GAAG,0CAA0C,CAAC;AAEjE,iFAAiF;AACjF,SAAS,cAAc,CAAC,KAAa;IACnC,OAAO,KAAK,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,GAAW;IACnD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAE3C,wDAAwD;IACxD,uDAAuD;IACvD,MAAM,eAAe,GAAG,oBAAoB,CAAC;IAC7C,IAAI,MAAM,CAAC;IACX,OAAO,CAAC,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACrD,IAAI,eAAe,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;IAC/D,CAAC;IAED,8EAA8E;IAC9E,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACpC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAChE,IAAI,QAAQ,KAAK,CAAC,CAAC;YAAE,SAAS;QAE9B,uEAAuE;QACvE,KAAK,IAAI,CAAC,GAAG,QAAQ,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAClD,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC;YACzB,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,SAAS,CAAC,yBAAyB;YAC9D,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;YACtC,IAAI,eAAe,CAAC,OAAO,CAAC;gBAAE,OAAO,IAAI,CAAC;QAC5C,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"token-vault.d.ts","sourceRoot":"","sources":["../../src/vault/token-vault.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAAgE;IAC7E,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAE7B;;OAEG;gBACS,KAAK,GAAE,MAAuB;IAI1C;;;;OAIG;IACI,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAQpD;;;;;OAKG;IACI,SAAS,CAAC,KAAK,EAAE,GAAG,GAAG,GAAG;IA0CjC;;;OAGG;IACI,yBAAyB,KAsBtB,OAAO,MAAM,KAAG,MAAM;IAwGhC;;OAEG;IACH,OAAO,CAAC,KAAK;IASb;;;;;OAKG;IACI,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAK7C;;OAEG;IACI,KAAK,IAAI,IAAI;IAIpB;;OAEG;IACH,IAAW,IAAI,IAAI,MAAM,CAExB;CACF"}
1
+ {"version":3,"file":"token-vault.d.ts","sourceRoot":"","sources":["../../src/vault/token-vault.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAAgE;IAC7E,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAE7B;;OAEG;gBACS,KAAK,GAAE,MAAuB;IAI1C;;;;OAIG;IACI,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAQpD;;;;;OAKG;IACI,SAAS,CAAC,KAAK,EAAE,GAAG,GAAG,GAAG;IA0CjC;;;OAGG;IACI,yBAAyB,KAwBtB,OAAO,MAAM,KAAG,MAAM;IAoHhC;;OAEG;IACH,OAAO,CAAC,KAAK;IASb;;;;;OAKG;IACI,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAK7C;;OAEG;IACI,KAAK,IAAI,IAAI;IAIpB;;OAEG;IACH,IAAW,IAAI,IAAI,MAAM,CAExB;CACF"}
@@ -78,7 +78,9 @@ export class TokenVault {
78
78
  createStreamingRehydrator() {
79
79
  let buffer = '';
80
80
  const maxTokenLen = Math.max(...[...this.vault.keys()].map(t => t.length), 0);
81
- // Accumulate content fields across SSE events to reassemble split tokens
81
+ // Accumulate content fields across SSE events to reassemble split tokens.
82
+ // Cap buffer size to prevent unbounded memory growth on very long streams.
83
+ const MAX_BUFFER_SIZE = 1024 * 1024; // 1 MB per field
82
84
  const contentBuffers = {};
83
85
  const CONTENT_FIELDS = ['content', 'reasoning_content', 'partial_json'];
84
86
  const rehydrateText = (text) => {
@@ -167,11 +169,22 @@ export class TokenVault {
167
169
  continue;
168
170
  const bufKey = actualField;
169
171
  contentBuffers[bufKey] = (contentBuffers[bufKey] || '') + target[actualField];
172
+ // Cap buffer size: flush everything if it grows too large
173
+ if (contentBuffers[bufKey].length > MAX_BUFFER_SIZE) {
174
+ target[actualField] = flushField(bufKey);
175
+ modified = true;
176
+ continue;
177
+ }
170
178
  const buf = contentBuffers[bufKey];
171
179
  const lastBracket = buf.lastIndexOf('[');
180
+ // Only treat as partial token if the text after '[' looks like a
181
+ // token prefix (uppercase letter or underscore), not JSON array content.
182
+ // Also hold back a bare '[' at the end — not enough chars yet to decide.
183
+ const tail = lastBracket >= 0 ? buf.substring(lastBracket) : '';
172
184
  const hasPartialToken = maxTokenLen > 0 && lastBracket >= 0 &&
173
- !buf.substring(lastBracket).includes(']') &&
174
- buf.length - lastBracket < maxTokenLen;
185
+ !tail.includes(']') &&
186
+ buf.length - lastBracket < maxTokenLen &&
187
+ (tail === '[' || /^\[[A-Z_]/.test(tail));
175
188
  if (hasPartialToken) {
176
189
  const safe = buf.substring(0, lastBracket);
177
190
  contentBuffers[bufKey] = buf.substring(lastBracket);
@@ -1 +1 @@
1
- {"version":3,"file":"token-vault.js","sourceRoot":"","sources":["../../src/vault/token-vault.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"token-vault.js","sourceRoot":"","sources":["../../src/vault/token-vault.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ {
2
+ "env": {
3
+ "ANTHROPIC_BASE_URL": "http://127.0.0.1:4000"
4
+ },
5
+ "hooks": {
6
+ "PostToolUse": [
7
+ {
8
+ "matcher": "Bash|Read|Grep|WebFetch",
9
+ "hooks": [
10
+ {
11
+ "type": "command",
12
+ "command": "hush redact-hook",
13
+ "timeout": 10
14
+ }
15
+ ]
16
+ }
17
+ ]
18
+ }
19
+ }
@@ -0,0 +1,4 @@
1
+ model_provider = "hush"
2
+
3
+ [model_providers.hush]
4
+ base_url = "http://127.0.0.1:4000/v1"
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Hush PII Guard — OpenCode Plugin (drop-in copy)
3
+ *
4
+ * Blocks reads of sensitive files (.env, *.pem, credentials.*, etc.)
5
+ * before the tool executes — the AI model never sees the content.
6
+ *
7
+ * Usage: copy this file to `.opencode/plugins/hush.ts` in your project
8
+ * and add to `opencode.json`:
9
+ * { "plugin": [".opencode/plugins/hush.ts"] }
10
+ *
11
+ * Or install from npm:
12
+ * import { HushPlugin } from '@aictrl/hush/opencode-plugin'
13
+ */
14
+
15
+ const SENSITIVE_GLOBS = [
16
+ /^\.env($|\..*)/, // .env, .env.local, .env.production, etc.
17
+ /credentials/i,
18
+ /secret/i,
19
+ /\.pem$/,
20
+ /\.key$/,
21
+ /\.p12$/,
22
+ /\.pfx$/,
23
+ /\.jks$/,
24
+ /\.keystore$/,
25
+ /\.asc$/,
26
+ /^id_rsa/,
27
+ /^\.netrc$/,
28
+ /^\.pgpass$/,
29
+ ];
30
+
31
+ function isSensitivePath(filePath: string): boolean {
32
+ const basename = (filePath.split('/').pop() ?? '').trim();
33
+ return SENSITIVE_GLOBS.some((re) => re.test(basename));
34
+ }
35
+
36
+ const READ_COMMANDS = /\b(cat|head|tail|less|more|bat|batcat)\b/;
37
+
38
+ function stripShellMeta(token: string): string {
39
+ return token.replace(/[`"'$(){}]/g, '');
40
+ }
41
+
42
+ function commandReadsSensitiveFile(cmd: string): boolean {
43
+ if (!READ_COMMANDS.test(cmd)) return false;
44
+ const redirectPattern = /<\s*([^\s|;&<>]+)/g;
45
+ let rMatch;
46
+ while ((rMatch = redirectPattern.exec(cmd)) !== null) {
47
+ if (isSensitivePath(stripShellMeta(rMatch[1]!))) return true;
48
+ }
49
+ const parts = cmd.split(/[|;&<>]+/);
50
+ for (const part of parts) {
51
+ const tokens = part.trim().split(/\s+/);
52
+ const cmdIndex = tokens.findIndex((t) => READ_COMMANDS.test(t));
53
+ if (cmdIndex === -1) continue;
54
+ for (let i = cmdIndex + 1; i < tokens.length; i++) {
55
+ const token = tokens[i]!;
56
+ if (token.startsWith('-')) continue;
57
+ const cleaned = stripShellMeta(token);
58
+ if (isSensitivePath(cleaned)) return true;
59
+ }
60
+ }
61
+ return false;
62
+ }
63
+
64
+ export const HushPlugin = async () => ({
65
+ 'tool.execute.before': async (
66
+ input: { tool: string },
67
+ output: { args: Record<string, string> },
68
+ ) => {
69
+ if (input.tool === 'read' && isSensitivePath(output.args['filePath'] ?? '')) {
70
+ throw new Error('[hush] Blocked: sensitive file');
71
+ }
72
+ if (input.tool === 'bash' && commandReadsSensitiveFile(output.args['command'] ?? '')) {
73
+ throw new Error('[hush] Blocked: command reads sensitive file');
74
+ }
75
+ },
76
+ });
@@ -0,0 +1,10 @@
1
+ {
2
+ "provider": {
3
+ "zai-coding-plan": {
4
+ "options": {
5
+ "baseURL": "http://127.0.0.1:4000/api/coding/paas/v4"
6
+ }
7
+ }
8
+ },
9
+ "plugin": [".opencode/plugins/hush.ts"]
10
+ }
package/package.json CHANGED
@@ -1,10 +1,20 @@
1
1
  {
2
2
  "name": "@aictrl/hush",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Hush: A Semantic Security Gateway for AI Agents. Redacts PII from prompts and tool outputs locally before they hit the cloud.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ },
13
+ "./opencode-plugin": {
14
+ "import": "./dist/plugins/opencode-hush.js",
15
+ "types": "./dist/plugins/opencode-hush.d.ts"
16
+ }
17
+ },
8
18
  "bin": {
9
19
  "hush": "dist/cli.js"
10
20
  },
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # E2E Scenario A: OpenCode hush plugin blocks .env read
4
+ #
5
+ # Verifies that the hush plugin's tool.execute.before hook prevents
6
+ # the AI model from ever reading sensitive files. The model should
7
+ # receive a "blocked" error instead of the file contents.
8
+ #
9
+ # Usage: ./scripts/e2e-plugin-block.sh
10
+ # Requirements: opencode CLI, node
11
+
12
+ set -euo pipefail
13
+
14
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15
+ PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
16
+
17
+ # Colors
18
+ RED='\033[0;31m'
19
+ GREEN='\033[0;32m'
20
+ YELLOW='\033[1;33m'
21
+ CYAN='\033[0;36m'
22
+ NC='\033[0m'
23
+
24
+ PASS_COUNT=0
25
+ FAIL_COUNT=0
26
+ WORK_DIR=""
27
+
28
+ cleanup() {
29
+ echo ""
30
+ echo -e "${CYAN}Cleaning up...${NC}"
31
+ [ -n "$WORK_DIR" ] && rm -rf "$WORK_DIR"
32
+ }
33
+ trap cleanup EXIT
34
+
35
+ pass() {
36
+ PASS_COUNT=$((PASS_COUNT + 1))
37
+ echo -e " ${GREEN}PASS${NC} $1"
38
+ }
39
+
40
+ fail() {
41
+ FAIL_COUNT=$((FAIL_COUNT + 1))
42
+ echo -e " ${RED}FAIL${NC} $1"
43
+ }
44
+
45
+ assert_contains() {
46
+ local haystack="$1" needle="$2" msg="$3"
47
+ if echo "$haystack" | grep -qiF "$needle"; then
48
+ pass "$msg"
49
+ else
50
+ fail "$msg (expected to find '$needle')"
51
+ fi
52
+ }
53
+
54
+ assert_not_contains() {
55
+ local haystack="$1" needle="$2" msg="$3"
56
+ if echo "$haystack" | grep -qiF "$needle"; then
57
+ fail "$msg (found '$needle' which should have been blocked)"
58
+ else
59
+ pass "$msg"
60
+ fi
61
+ }
62
+
63
+ echo -e "${CYAN}================================================${NC}"
64
+ echo -e "${CYAN} E2E Scenario A: Plugin Blocks .env Read ${NC}"
65
+ echo -e "${CYAN}================================================${NC}"
66
+ echo ""
67
+
68
+ # --- Step 1: Create temp project with .env and hush plugin ---
69
+ echo -e "${YELLOW}[1/4] Creating temp project with .env and hush plugin...${NC}"
70
+
71
+ WORK_DIR=$(mktemp -d)
72
+ mkdir -p "$WORK_DIR/.opencode/plugins"
73
+
74
+ # Sensitive .env file with PII
75
+ cat > "$WORK_DIR/.env" <<'ENVEOF'
76
+ DATABASE_URL=postgres://admin:supersecret@10.42.99.7:5432/prod
77
+ API_KEY=sk-live-a1b2c3d4e5f6g7h8i9j0k1l2m3n4
78
+ ADMIN_EMAIL=alice@confidential-corp.com
79
+ AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
80
+ ENVEOF
81
+
82
+ # Copy the drop-in plugin
83
+ cp "$PROJECT_DIR/examples/team-config/.opencode/plugins/hush.ts" \
84
+ "$WORK_DIR/.opencode/plugins/hush.ts"
85
+
86
+ # opencode.json — point at real provider + enable plugin
87
+ cat > "$WORK_DIR/opencode.json" <<OCEOF
88
+ {
89
+ "provider": {
90
+ "zai-coding-plan": {
91
+ "options": {
92
+ "baseURL": "https://open.bigmodel.cn/api/coding/paas/v4"
93
+ }
94
+ }
95
+ },
96
+ "plugin": [".opencode/plugins/hush.ts"]
97
+ }
98
+ OCEOF
99
+
100
+ echo -e " Temp project: ${WORK_DIR}"
101
+ echo -e " .env contains: email, API key, DB URL, AWS secret"
102
+
103
+ # --- Step 2: Run OpenCode with prompt to read .env ---
104
+ echo ""
105
+ echo -e "${YELLOW}[2/4] Running OpenCode: 'read the file .env and tell me what's in it'...${NC}"
106
+
107
+ cd "$WORK_DIR"
108
+ OUTPUT=$(timeout 120 opencode -p "read the file .env and tell me what's in it" -q -f json 2>&1) || true
109
+ echo -e " Output length: $(echo "$OUTPUT" | wc -c) bytes"
110
+
111
+ # --- Step 3: Verify plugin blocked the read ---
112
+ echo ""
113
+ echo -e "${YELLOW}[3/4] Verifying plugin blocked .env read...${NC}"
114
+ echo ""
115
+
116
+ # The output should mention blocking/error, not contain the actual PII
117
+ assert_contains "$OUTPUT" "block" "Output mentions blocking"
118
+
119
+ # --- Step 4: Verify PII never appears in output ---
120
+ echo ""
121
+ echo -e "${YELLOW}[4/4] Verifying PII never appears in output...${NC}"
122
+ echo ""
123
+
124
+ assert_not_contains "$OUTPUT" "alice@confidential-corp.com" "Email not in output"
125
+ assert_not_contains "$OUTPUT" "sk-live-a1b2c3d4e5f6g7h8i9j0k1l2m3n4" "API key not in output"
126
+ assert_not_contains "$OUTPUT" "supersecret" "DB password not in output"
127
+ assert_not_contains "$OUTPUT" "wJalrXUtnFEMI" "AWS secret not in output"
128
+
129
+ # --- Summary ---
130
+ echo ""
131
+ echo -e "${CYAN}================================================${NC}"
132
+ TOTAL=$((PASS_COUNT + FAIL_COUNT))
133
+ if [ "$FAIL_COUNT" -eq 0 ]; then
134
+ echo -e "${GREEN} ALL ${TOTAL} CHECKS PASSED${NC}"
135
+ echo ""
136
+ echo -e " ${GREEN}Plugin blocked .env read — PII never reached the model.${NC}"
137
+ else
138
+ echo -e "${RED} ${FAIL_COUNT}/${TOTAL} CHECKS FAILED${NC}"
139
+ fi
140
+ echo -e "${CYAN}================================================${NC}"
141
+
142
+ exit "$FAIL_COUNT"