@seanmozeik/tripwire 0.6.7 → 0.7.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 (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +154 -141
  3. package/dist/index.js +35 -0
  4. package/dist/tripwire-cli.js +2 -10
  5. package/dist/tripwire-hook.js +3 -0
  6. package/dist/tripwire-pi.js +4 -0
  7. package/dist/tripwire.js +135 -90
  8. package/dist/types/dispatch.d.ts +18 -0
  9. package/dist/types/index.d.ts +6 -0
  10. package/dist/types/lib/bash.d.ts +27 -0
  11. package/dist/types/lib/config.d.ts +110 -0
  12. package/dist/types/lib/cursor.d.ts +16 -0
  13. package/dist/types/lib/decision.d.ts +13 -0
  14. package/dist/types/lib/diff.d.ts +3 -0
  15. package/dist/types/lib/event.d.ts +45 -0
  16. package/dist/types/lib/log.d.ts +2 -0
  17. package/dist/types/lib/secrets.d.ts +41 -0
  18. package/dist/types/rules/bash-deny.d.ts +5 -0
  19. package/dist/types/rules/bash-git.d.ts +5 -0
  20. package/dist/types/rules/bash-network-install.d.ts +4 -0
  21. package/dist/types/rules/bash-redirect.d.ts +4 -0
  22. package/dist/types/rules/bash-scoped-rm.d.ts +5 -0
  23. package/dist/types/rules/bash-tar-explosion.d.ts +4 -0
  24. package/dist/types/rules/config-custom.d.ts +6 -0
  25. package/dist/types/rules/lazy-code.d.ts +4 -0
  26. package/dist/types/rules/path-protect.d.ts +12 -0
  27. package/dist/types/rules/post-secret-scrub.d.ts +12 -0
  28. package/dist/types/rules/read-protect.d.ts +4 -0
  29. package/dist/types/rules/tool-policy.d.ts +5 -0
  30. package/package.json +53 -22
  31. package/dist/tripwire-cli.js.jsc +0 -0
  32. package/dist/tripwire.js.jsc +0 -0
  33. package/src/cli.ts +0 -264
  34. package/src/dispatch.ts +0 -354
  35. package/src/index.ts +0 -6
  36. package/src/lib/bash.ts +0 -1284
  37. package/src/lib/config.ts +0 -127
  38. package/src/lib/decision.ts +0 -36
  39. package/src/lib/diff.ts +0 -26
  40. package/src/lib/event.ts +0 -106
  41. package/src/lib/install.ts +0 -238
  42. package/src/lib/log.ts +0 -24
  43. package/src/lib/secrets.ts +0 -121
  44. package/src/rules/bash-deny.ts +0 -394
  45. package/src/rules/bash-git.ts +0 -603
  46. package/src/rules/bash-network-install.ts +0 -72
  47. package/src/rules/bash-redirect.ts +0 -91
  48. package/src/rules/bash-scoped-rm.ts +0 -84
  49. package/src/rules/bash-tar-explosion.ts +0 -76
  50. package/src/rules/bash-tool-policy.ts +0 -146
  51. package/src/rules/config-custom.ts +0 -160
  52. package/src/rules/lazy-code.ts +0 -95
  53. package/src/rules/path-protect.ts +0 -68
  54. package/src/rules/post-secret-scrub.ts +0 -38
  55. package/src/rules/read-protect.ts +0 -67
@@ -1,68 +0,0 @@
1
- // oxlint-disable-next-line unicorn/import-style
2
- import { resolve } from 'node:path';
3
-
4
- import { type Decision, allow, deny } from '../lib/decision';
5
- import type { EditInput, WriteInput } from '../lib/event';
6
-
7
- interface Spec {
8
- readonly pattern: RegExp;
9
- readonly rule: string;
10
- readonly message: string;
11
- }
12
-
13
- const protections: readonly Spec[] = [
14
- {
15
- pattern: /(?<prefix>^|\/)\.env(?<ext>\.[^/]+)?$/,
16
- rule: 'env-file',
17
- message:
18
- '.env files hold secrets that should never be sent to the model. Refuse to write or edit. If an example is needed, create .env.example with redacted placeholders.',
19
- },
20
- {
21
- pattern: /(?<prefix>^|\/)\.dev\.vars(?<ext>\.[^/]+)?$/,
22
- rule: 'dev-vars',
23
- message: '.dev.vars holds Cloudflare/Wrangler secrets. Do not modify.',
24
- },
25
- {
26
- pattern: /(?<prefix>^|\/)\.ssh\//,
27
- rule: 'ssh-dir',
28
- message: 'Never write into ~/.ssh/. Refuse.',
29
- },
30
- {
31
- pattern: /(?<prefix>^|\/)(?<key>id_rsa|id_ed25519|id_ecdsa|id_dsa)(?<pub>\.pub)?$/,
32
- rule: 'ssh-key',
33
- message: 'SSH key file. Refuse.',
34
- },
35
- {
36
- pattern: /\.(?<ext>pem|key|p12|pfx)$/i,
37
- rule: 'private-key',
38
- message:
39
- 'Private key file. Refuse to overwrite. If generating a new key, use a different filename and let the user review.',
40
- },
41
- {
42
- pattern: /(?<prefix>^|\/)secrets?\.(?<ext>json|ya?ml|toml|env)$/i,
43
- rule: 'secrets-file',
44
- message: 'Secrets file. Refuse.',
45
- },
46
- {
47
- pattern: /(?<prefix>^|\/)\.aws\/credentials$/,
48
- rule: 'aws-credentials',
49
- message: 'AWS credentials file. Refuse.',
50
- },
51
- {
52
- pattern: /(?<prefix>^|\/)\.netrc$/,
53
- rule: 'netrc',
54
- message: '.netrc holds host credentials. Refuse.',
55
- },
56
- ];
57
-
58
- const pathProtect = (input: EditInput | WriteInput): Decision => {
59
- const path = resolve(input.file_path);
60
- for (const p of protections) {
61
- if (p.pattern.test(path)) {
62
- return deny(p.rule, p.message);
63
- }
64
- }
65
- return allow('path-protect');
66
- };
67
-
68
- export { pathProtect };
@@ -1,38 +0,0 @@
1
- import { type Decision, allow, deny } from '../lib/decision';
2
- import { extractResponseText } from '../lib/event';
3
- import { scanAndRedact } from '../lib/secrets';
4
-
5
- // PostToolUse: scan whatever string content a tool returned (Bash stdout,
6
- // Read content) for known secret patterns via betterleaks. If anything
7
- // Fires, block the result (so the original output never reaches the
8
- // Model) and surface a redacted version in the block reason — that lets
9
- // The agent see what was returned without leaking the secret itself.
10
-
11
- interface PostInput {
12
- readonly toolName: string;
13
- readonly response: unknown;
14
- }
15
-
16
- const postSecretScrub = (input: PostInput): Decision => {
17
- const text = extractResponseText(input.toolName, input.response);
18
- if (text.length === 0) {
19
- return allow('post-secret-scrub');
20
- }
21
- const { hits, redacted } = scanAndRedact(text);
22
- if (hits.length === 0) {
23
- return allow('post-secret-scrub');
24
- }
25
- const summary = hits.map((h) => `${h.rule}×${h.count}`).join(', ');
26
- return deny(
27
- 'secrets-in-output',
28
- [
29
- `tripwire intercepted ${hits.length} secret pattern(s) in this tool's output (${summary}). The original output was withheld so the secret never enters the model context. A redacted form is below — work from this, do not re-run the same command in a way that re-fetches the underlying secret.`,
30
- ``,
31
- `Redacted output:`,
32
- redacted.slice(0, 16_000) + (redacted.length > 16_000 ? '\n…[truncated]' : ''),
33
- ].join('\n'),
34
- );
35
- };
36
-
37
- export type { PostInput };
38
- export { postSecretScrub };
@@ -1,67 +0,0 @@
1
- // oxlint-disable-next-line unicorn/import-style
2
- import { resolve } from 'node:path';
3
-
4
- import { type Decision, allow, deny } from '../lib/decision';
5
- import type { ReadInput } from '../lib/event';
6
-
7
- interface Spec {
8
- readonly rule: string;
9
- readonly pattern: RegExp;
10
- readonly message: string;
11
- }
12
-
13
- const PROTECTIONS: readonly Spec[] = [
14
- {
15
- rule: 'read-env',
16
- pattern: /(?<prefix>^|\/)\.env(?<ext>\.[^/]+)?$/,
17
- message:
18
- '.env files hold secrets that should never enter the model context. Refuse to read. If the goal is documenting required env vars, look at .env.example or describe the schema from memory.',
19
- },
20
- {
21
- rule: 'read-dev-vars',
22
- pattern: /(?<prefix>^|\/)\.dev\.vars(?<ext>\.[^/]+)?$/,
23
- message: 'Refuse to read .dev.vars (Cloudflare/Wrangler secrets).',
24
- },
25
- {
26
- rule: 'read-ssh',
27
- pattern: /(?<prefix>^|\/)\.ssh\//,
28
- message: 'Refuse to read files inside ~/.ssh/.',
29
- },
30
- {
31
- rule: 'read-ssh-key',
32
- pattern: /(?<prefix>^|\/)(?<key>id_rsa|id_ed25519|id_ecdsa|id_dsa)$/,
33
- message: 'Refuse to read SSH private key files.',
34
- },
35
- {
36
- rule: 'read-private-key',
37
- pattern: /\.(?<ext>pem|key|p12|pfx)$/i,
38
- message: 'Refuse to read private-key-shaped files.',
39
- },
40
- {
41
- rule: 'read-aws-credentials',
42
- pattern: /(?<prefix>^|\/)\.aws\/credentials$/,
43
- message: 'Refuse to read ~/.aws/credentials.',
44
- },
45
- {
46
- rule: 'read-netrc',
47
- pattern: /(?<prefix>^|\/)\.netrc$/,
48
- message: 'Refuse to read ~/.netrc (host credentials).',
49
- },
50
- {
51
- rule: 'read-secrets-file',
52
- pattern: /(?<prefix>^|\/)secrets?\.(?<ext>json|ya?ml|toml|env)$/i,
53
- message: 'Refuse to read a file named secrets.{json,yaml,toml,env}.',
54
- },
55
- ];
56
-
57
- const readProtect = (input: ReadInput): Decision => {
58
- const path = resolve(input.file_path);
59
- for (const p of PROTECTIONS) {
60
- if (p.pattern.test(path)) {
61
- return deny(p.rule, p.message);
62
- }
63
- }
64
- return allow('read-protect');
65
- };
66
-
67
- export { readProtect };