@seanmozeik/tripwire 0.5.3 → 0.6.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.
@@ -2,10 +2,10 @@ import { type Segment, hasBypass } from '../lib/bash';
2
2
  import { type Decision, allow, deny, warn } from '../lib/decision';
3
3
 
4
4
  // Opinionated tooling enforcement. Hard-deny on the package managers and
5
- // Tools Sean has explicitly replaced (npm/pip/patch-package); soft-warn
5
+ // Tools the user has explicitly replaced (npm/pip/patch-package); soft-warn
6
6
  // Suggesting modern equivalents (find→fd, grep→rg).
7
7
  //
8
- // Hard-deny rationale (from Sean's CLAUDE.md): TypeScript is bun-only,
8
+ // Hard-deny rationale (from the user's CLAUDE.md): TypeScript is bun-only,
9
9
  // Python is uv-only. Slipping into npm or pip mid-session means the
10
10
  // Agent forgot the toolchain and is about to install into the wrong
11
11
  // Directory or make a lockfile bun can't read.
@@ -23,7 +23,7 @@ const POLICIES: readonly Policy[] = [
23
23
  rule: 'use-bun-not-npm',
24
24
  action: 'deny',
25
25
  message:
26
- 'Use `bun` instead of `npm`. Translations: `npm install` → `bun install`, `npm install <pkg>` → `bun add <pkg>`, `npm install -D <pkg>` → `bun add -d <pkg>`, `npm run X` → `bun run X` (or `bun X` for bin scripts), `npm test` → `bun test`. If you genuinely need npm (publishing to a registry that requires it, working in a non-Sean repo), append ` # tripwire-allow: <reason>` to the command.',
26
+ 'Use `bun` instead of `npm`. Translations: `npm install` → `bun install`, `npm install <pkg>` → `bun add <pkg>`, `npm install -D <pkg>` → `bun add -d <pkg>`, `npm run X` → `bun run X` (or `bun X` for bin scripts), `npm test` → `bun test`. If you genuinely need npm (publishing to a registry that requires it, working in a different repo), append ` # tripwire-allow: <reason>` to the command.',
27
27
  fires: (seg) => seg.head === 'npm',
28
28
  },
29
29
  {
@@ -35,20 +35,20 @@ const POLICIES: readonly Policy[] = [
35
35
  {
36
36
  rule: 'use-bun-not-pnpm',
37
37
  action: 'deny',
38
- message: 'Use `bun` instead of `pnpm`. Sean is bun-only across his repos.',
38
+ message: 'Use `bun` instead of `pnpm`. The user is bun-only across their repos.',
39
39
  fires: (seg) => seg.head === 'pnpm',
40
40
  },
41
41
  {
42
42
  rule: 'use-bun-not-yarn',
43
43
  action: 'deny',
44
- message: 'Use `bun` instead of `yarn`. Sean is bun-only.',
44
+ message: 'Use `bun` instead of `yarn`. The user is bun-only.',
45
45
  fires: (seg) => seg.head === 'yarn',
46
46
  },
47
47
  {
48
48
  rule: 'use-uv-not-pip',
49
49
  action: 'deny',
50
50
  message:
51
- 'Use `uv` instead of `pip`. Translations: `pip install <pkg>` → `uv add <pkg>` (project dependency) or `uv pip install <pkg>` (env-only escape hatch). `pip freeze` → `uv pip freeze`. `pip list` → `uv pip list`. Sean is uv-only across Python repos.',
51
+ 'Use `uv` instead of `pip`. Translations: `pip install <pkg>` → `uv add <pkg>` (project dependency) or `uv pip install <pkg>` (env-only escape hatch). `pip freeze` → `uv pip freeze`. `pip list` → `uv pip list`. The user is uv-only across Python repos.',
52
52
  fires: (seg) => seg.head === 'pip' || seg.head === 'pip3',
53
53
  },
54
54
  {
@@ -76,12 +76,12 @@ const POLICIES: readonly Policy[] = [
76
76
  fires: (seg) => seg.head === 'patch-package',
77
77
  },
78
78
 
79
- // ── SOFT WARNS: modern equivalents Sean has installed ────────────────
79
+ // ── SOFT WARNS: modern equivalents the user has installed ────────────────
80
80
  {
81
81
  rule: 'consider-fd',
82
82
  action: 'warn',
83
83
  message:
84
- 'Consider `fd` instead of `find`. Faster, simpler syntax, respects .gitignore by default. Examples: `find . -name "*.ts"` → `fd -e ts`, `find . -type f -name "X"` → `fd -t f X`, `find PATH ...` → `fd ... PATH`. Sean has both installed; either works.',
84
+ 'Consider `fd` instead of `find`. Faster, simpler syntax, respects .gitignore by default. Examples: `find . -name "*.ts"` → `fd -e ts`, `find . -type f -name "X"` → `fd -t f X`, `find PATH ...` → `fd ... PATH`. The user has both installed; either works.',
85
85
  fires: (seg) => seg.head === 'find',
86
86
  },
87
87
  {
@@ -20,21 +20,21 @@ const STUB_RE: readonly RegExp[] = [
20
20
  /\btemp fix\b/i,
21
21
  /\bfallback\b/i,
22
22
  /\bplaceholder\b/i,
23
- /\bbackwards?[ -]?compat(ibility)?\b/i,
23
+ /\bbackwards?[ -]?compat(?<ibility>ibility)?\b/i,
24
24
  /\bfor later\b/i,
25
25
  /\blater on\b/i,
26
26
  /\bget back to\b/i,
27
27
  /\bI'?ll fix\b/i,
28
28
  /\bto be implemented\b/i,
29
- /\bnot yet (implemented|done)\b/i,
29
+ /\bnot yet (?<state>implemented|done)\b/i,
30
30
  /\bstubbed\b/i,
31
31
  ];
32
32
 
33
33
  const CODE_EXT_RE =
34
- /\.(ts|tsx|js|jsx|mjs|cjs|py|rs|go|rb|java|kt|swift|c|cc|cpp|h|hpp|cs|php|sh|zsh|bash|lua|ex|exs|clj|scala|dart)$/i;
34
+ /\.(?<ext>ts|tsx|js|jsx|mjs|cjs|py|rs|go|rb|java|kt|swift|c|cc|cpp|h|hpp|cs|php|sh|zsh|bash|lua|ex|exs|clj|scala|dart)$/i;
35
35
 
36
36
  const TEST_PATH_RE =
37
- /(^|\/)(__tests__|tests?|spec|fixtures?|mocks?|__mocks__|stories)(\/|$)|\.(test|spec|fixture|mock|stories)\.[^/]+$/i;
37
+ /(?<prefix>^|\/)(?<dir>__tests__|tests?|spec|fixtures?|mocks?|__mocks__|stories)(?<suffix>\/|$)|\.(?<ext>test|spec|fixture|mock|stories)\.[^/]+$/i;
38
38
 
39
39
  // Comment-syntax-agnostic. Works in `//`, `#`, `--`, `/* */`, `<!-- -->`,
40
40
  // `;`, `%`, etc.
@@ -1,3 +1,4 @@
1
+ // oxlint-disable-next-line unicorn/import-style
1
2
  import { resolve } from 'node:path';
2
3
 
3
4
  import { type Decision, allow, deny } from '../lib/decision';
@@ -11,39 +12,47 @@ interface Spec {
11
12
 
12
13
  const protections: readonly Spec[] = [
13
14
  {
14
- pattern: /(^|\/)\.env(\.[^/]+)?$/,
15
+ pattern: /(?<prefix>^|\/)\.env(?<ext>\.[^/]+)?$/,
15
16
  rule: 'env-file',
16
17
  message:
17
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.',
18
19
  },
19
20
  {
20
- pattern: /(^|\/)\.dev\.vars(\.[^/]+)?$/,
21
+ pattern: /(?<prefix>^|\/)\.dev\.vars(?<ext>\.[^/]+)?$/,
21
22
  rule: 'dev-vars',
22
23
  message: '.dev.vars holds Cloudflare/Wrangler secrets. Do not modify.',
23
24
  },
24
- { pattern: /(^|\/)\.ssh\//, rule: 'ssh-dir', message: 'Never write into ~/.ssh/. Refuse.' },
25
25
  {
26
- pattern: /(^|\/)(id_rsa|id_ed25519|id_ecdsa|id_dsa)(\.pub)?$/,
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)?$/,
27
32
  rule: 'ssh-key',
28
33
  message: 'SSH key file. Refuse.',
29
34
  },
30
35
  {
31
- pattern: /\.(pem|key|p12|pfx)$/i,
36
+ pattern: /\.(?<ext>pem|key|p12|pfx)$/i,
32
37
  rule: 'private-key',
33
38
  message:
34
- 'Private key file. Refuse to overwrite. If generating a new key, use a different filename and let Sean review.',
39
+ 'Private key file. Refuse to overwrite. If generating a new key, use a different filename and let the user review.',
35
40
  },
36
41
  {
37
- pattern: /(^|\/)secrets?\.(json|ya?ml|toml|env)$/i,
42
+ pattern: /(?<prefix>^|\/)secrets?\.(?<ext>json|ya?ml|toml|env)$/i,
38
43
  rule: 'secrets-file',
39
44
  message: 'Secrets file. Refuse.',
40
45
  },
41
46
  {
42
- pattern: /(^|\/)\.aws\/credentials$/,
47
+ pattern: /(?<prefix>^|\/)\.aws\/credentials$/,
43
48
  rule: 'aws-credentials',
44
49
  message: 'AWS credentials file. Refuse.',
45
50
  },
46
- { pattern: /(^|\/)\.netrc$/, rule: 'netrc', message: '.netrc holds host credentials. Refuse.' },
51
+ {
52
+ pattern: /(?<prefix>^|\/)\.netrc$/,
53
+ rule: 'netrc',
54
+ message: '.netrc holds host credentials. Refuse.',
55
+ },
47
56
  ];
48
57
 
49
58
  const pathProtect = (input: EditInput | WriteInput): Decision => {
@@ -1,3 +1,4 @@
1
+ // oxlint-disable-next-line unicorn/import-style
1
2
  import { resolve } from 'node:path';
2
3
 
3
4
  import { type Decision, allow, deny } from '../lib/decision';
@@ -12,39 +13,43 @@ interface Spec {
12
13
  const PROTECTIONS: readonly Spec[] = [
13
14
  {
14
15
  rule: 'read-env',
15
- pattern: /(^|\/)\.env(\.[^/]+)?$/,
16
+ pattern: /(?<prefix>^|\/)\.env(?<ext>\.[^/]+)?$/,
16
17
  message:
17
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.',
18
19
  },
19
20
  {
20
21
  rule: 'read-dev-vars',
21
- pattern: /(^|\/)\.dev\.vars(\.[^/]+)?$/,
22
+ pattern: /(?<prefix>^|\/)\.dev\.vars(?<ext>\.[^/]+)?$/,
22
23
  message: 'Refuse to read .dev.vars (Cloudflare/Wrangler secrets).',
23
24
  },
24
- { rule: 'read-ssh', pattern: /(^|\/)\.ssh\//, message: 'Refuse to read files inside ~/.ssh/.' },
25
+ {
26
+ rule: 'read-ssh',
27
+ pattern: /(?<prefix>^|\/)\.ssh\//,
28
+ message: 'Refuse to read files inside ~/.ssh/.',
29
+ },
25
30
  {
26
31
  rule: 'read-ssh-key',
27
- pattern: /(^|\/)(id_rsa|id_ed25519|id_ecdsa|id_dsa)$/,
32
+ pattern: /(?<prefix>^|\/)(?<key>id_rsa|id_ed25519|id_ecdsa|id_dsa)$/,
28
33
  message: 'Refuse to read SSH private key files.',
29
34
  },
30
35
  {
31
36
  rule: 'read-private-key',
32
- pattern: /\.(pem|key|p12|pfx)$/i,
37
+ pattern: /\.(?<ext>pem|key|p12|pfx)$/i,
33
38
  message: 'Refuse to read private-key-shaped files.',
34
39
  },
35
40
  {
36
41
  rule: 'read-aws-credentials',
37
- pattern: /(^|\/)\.aws\/credentials$/,
42
+ pattern: /(?<prefix>^|\/)\.aws\/credentials$/,
38
43
  message: 'Refuse to read ~/.aws/credentials.',
39
44
  },
40
45
  {
41
46
  rule: 'read-netrc',
42
- pattern: /(^|\/)\.netrc$/,
47
+ pattern: /(?<prefix>^|\/)\.netrc$/,
43
48
  message: 'Refuse to read ~/.netrc (host credentials).',
44
49
  },
45
50
  {
46
51
  rule: 'read-secrets-file',
47
- pattern: /(^|\/)secrets?\.(json|ya?ml|toml|env)$/i,
52
+ pattern: /(?<prefix>^|\/)secrets?\.(?<ext>json|ya?ml|toml|env)$/i,
48
53
  message: 'Refuse to read a file named secrets.{json,yaml,toml,env}.',
49
54
  },
50
55
  ];