@agenttrail/guardrails 0.2.0 → 0.2.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.
- package/dist/{chunk-3NDBRXP3.js → chunk-SLWHBH7H.js} +103 -26
- package/dist/chunk-SLWHBH7H.js.map +1 -0
- package/dist/guardrails.cjs +102 -25
- package/dist/guardrails.cjs.map +1 -1
- package/dist/guardrails.d.cts +8 -5
- package/dist/guardrails.d.ts +8 -5
- package/dist/guardrails.js +1 -1
- package/dist/index.cjs +102 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +44 -29
- package/dist/chunk-3NDBRXP3.js.map +0 -1
|
@@ -156,7 +156,7 @@ var acInstructionFileEdit = {
|
|
|
156
156
|
severity: "high",
|
|
157
157
|
defaultAction: "require_approval",
|
|
158
158
|
title: "The agent editing its standing instructions",
|
|
159
|
-
description: "Holds a file tool opening the instructions a coding agent loads at the start of every session: `CLAUDE.md`, `CLAUDE.local.md` and `.claude/rules/`; `AGENTS.md` and `AGENTS.override.md`, which Codex, Cursor, Windsurf, Copilot and Cline all read; `GEMINI.md`; `.cursorrules`; Windsurf's `.windsurfrules`, `.windsurf/rules/` and `.devin/rules/`; Cline's `.clinerules` file or directory and its global `Cline/Rules/` folder; Copilot's `.github/copilot-instructions.md` and `.github/instructions/**/*.instructions.md`; and `.aider.conf.yml`, which sets the files Aider reads on every launch. A line written into one of these is followed in every later session. Matched in any directory and in any letter case. File tools carry a path and no content, so it cannot see what was written
|
|
159
|
+
description: "Holds a file tool opening the instructions a coding agent loads at the start of every session: `CLAUDE.md`, `CLAUDE.local.md` and `.claude/rules/`; `AGENTS.md` and `AGENTS.override.md`, which Codex, Cursor, Windsurf, Copilot and Cline all read; `GEMINI.md`; `.cursorrules`; Windsurf's `.windsurfrules`, `.windsurf/rules/` and `.devin/rules/`; Cline's `.clinerules` file or directory and its global `Cline/Rules/` folder; Copilot's `.github/copilot-instructions.md` and `.github/instructions/**/*.instructions.md`; and `.aider.conf.yml`, which sets the files Aider reads on every launch. A line written into one of these is followed in every later session. Matched in any directory and in any letter case. Reading is excluded \u2014 the `Read` and `Grep` tools never match \u2014 so an agent opening its instructions to read them is not held; every other file tool is, including one this corpus does not know. File tools carry a path and no content, so it still cannot see what was written. Does not cover `.cursor/rules/`, which `fs.agent-self-config` holds. Misses a context file renamed through Gemini's `context.fileName` or Codex's `project_doc_fallback_filenames`, Aider's `CONVENTIONS.md`, which Aider loads only when asked and which is too common a name to match, and any of these files written by a shell command instead of a file tool.",
|
|
160
160
|
match: {
|
|
161
161
|
any_of: [
|
|
162
162
|
{
|
|
@@ -172,6 +172,11 @@ var acInstructionFileEdit = {
|
|
|
172
172
|
{ kind: "execute_tool", file_glob: "**/.github/copilot-instructions.md" },
|
|
173
173
|
{ kind: "execute_tool", file_glob: "**/.github/instructions/**/*.instructions.md" },
|
|
174
174
|
{ kind: "execute_tool", file_glob: "**/.aider.conf.yml" }
|
|
175
|
+
],
|
|
176
|
+
none_of: [
|
|
177
|
+
// A read is not an edit. Named as a deny-list rather than an `any_of` over
|
|
178
|
+
// the write tools, so an unknown file tool on a matched path still holds.
|
|
179
|
+
{ kind: "execute_tool", label: "{Read,Grep}" }
|
|
175
180
|
]
|
|
176
181
|
},
|
|
177
182
|
fixtures: {
|
|
@@ -206,7 +211,9 @@ var acInstructionFileEdit = {
|
|
|
206
211
|
file(".github/workflows/ci.yml"),
|
|
207
212
|
file(".cursor/rules/style.mdc"),
|
|
208
213
|
file(".claude/settings.json"),
|
|
209
|
-
file(".aider.chat.history.md")
|
|
214
|
+
file(".aider.chat.history.md"),
|
|
215
|
+
file("CLAUDE.md", "Read"),
|
|
216
|
+
file(".github/copilot-instructions.md", "Grep")
|
|
210
217
|
]
|
|
211
218
|
}
|
|
212
219
|
};
|
|
@@ -220,7 +227,7 @@ var acMcpServerAdd = {
|
|
|
220
227
|
severity: "high",
|
|
221
228
|
defaultAction: "require_approval",
|
|
222
229
|
title: "Adding an MCP server to an agent",
|
|
223
|
-
description: "Holds the commands that register an MCP server with a coding agent \u2014 `claude mcp add`, `claude mcp add-json`, `claude mcp add-from-claude-desktop`, `codex mcp add` and `gemini mcp add` \u2014 and `claude --mcp-config`, which attaches servers to a single session. Each gives an agent a new set of tools, often a program fetched and started on the spot, with nobody reviewing the change. Deliberately NOT matched: listing or removing servers (`claude mcp list`, `claude mcp remove`), and the MCP Inspector (`npx @modelcontextprotocol/inspector`), which is a debugging tool rather than a registration. Cursor has no command for this, so its `.cursor/mcp.json`, in a project or the home directory, is matched as a file instead; a project's `.mcp.json` is held by `fs.agent-self-config`. Misses servers written into `~/.claude.json` or Gemini's `settings.json` with a file tool, and a global flag whose value is quoted when it sits before `mcp`. A quoted MENTION is not a use: a search, a `git commit -m` message, an `echo` or a `curl --data` body that only names this command is left alone, as long as every shell metacharacter stays inside the quotes.",
|
|
230
|
+
description: "Holds the commands that register an MCP server with a coding agent \u2014 `claude mcp add`, `claude mcp add-json`, `claude mcp add-from-claude-desktop`, `codex mcp add` and `gemini mcp add` \u2014 and `claude --mcp-config`, which attaches servers to a single session. Each gives an agent a new set of tools, often a program fetched and started on the spot, with nobody reviewing the change. Deliberately NOT matched: listing or removing servers (`claude mcp list`, `claude mcp remove`), and the MCP Inspector (`npx @modelcontextprotocol/inspector`), which is a debugging tool rather than a registration. Cursor has no command for this, so its `.cursor/mcp.json`, in a project or the home directory, is matched as a file instead \u2014 written, not read: the `Read` and `Grep` tools never match it, and every other file tool does, including one this corpus does not know; a project's `.mcp.json` is held by `fs.agent-self-config`. Misses servers written into `~/.claude.json` or Gemini's `settings.json` with a file tool, and a global flag whose value is quoted when it sits before `mcp`. A quoted MENTION is not a use: a search, a `git commit -m` message, an `echo` or a `curl --data` body that only names this command is left alone, as long as every shell metacharacter stays inside the quotes.",
|
|
224
231
|
match: {
|
|
225
232
|
any_of: [
|
|
226
233
|
{
|
|
@@ -235,7 +242,14 @@ var acMcpServerAdd = {
|
|
|
235
242
|
// Cursor has no `mcp add` command; its servers are added by editing this file.
|
|
236
243
|
{ kind: "execute_tool", file_glob: "**/.cursor/mcp.json" }
|
|
237
244
|
],
|
|
238
|
-
none_of: [
|
|
245
|
+
none_of: [
|
|
246
|
+
// A read is not an addition. This covers the `.cursor/mcp.json` arm — the
|
|
247
|
+
// shell arm already pins its own tool family. Named as a deny-list rather
|
|
248
|
+
// than an `any_of` over the write tools, so an unknown file tool on that
|
|
249
|
+
// path still holds.
|
|
250
|
+
{ kind: "execute_tool", label: "{Read,Grep}" },
|
|
251
|
+
...QUOTED_MENTION
|
|
252
|
+
]
|
|
239
253
|
},
|
|
240
254
|
fixtures: {
|
|
241
255
|
block: [
|
|
@@ -260,7 +274,9 @@ var acMcpServerAdd = {
|
|
|
260
274
|
bash("npx @modelcontextprotocol/inspector"),
|
|
261
275
|
file("config/mcp.json"),
|
|
262
276
|
file(".cursor/rules/style.mdc"),
|
|
263
|
-
bash("pnpm run test")
|
|
277
|
+
bash("pnpm run test"),
|
|
278
|
+
file(".cursor/mcp.json", "Read"),
|
|
279
|
+
file("/Users/dev/.cursor/mcp.json", "Grep")
|
|
264
280
|
]
|
|
265
281
|
}
|
|
266
282
|
};
|
|
@@ -272,7 +288,7 @@ var acMemoryStoreEdit = {
|
|
|
272
288
|
severity: "high",
|
|
273
289
|
defaultAction: "require_approval",
|
|
274
290
|
title: "The agent editing its own memory",
|
|
275
|
-
description: "Holds a file tool opening the memory a coding agent carries between sessions: Claude Code's auto memory under `.claude/projects/<project>/memory/`, and its sub-agent memory in `.claude/agent-memory/` and `.claude/agent-memory-local/`; Codex's `.codex/memories/`; Gemini's private `.gemini/tmp/<project>/memory/`; Windsurf's `.codeium/windsurf/memories/`, including `global_rules.md`; and `.cursor/memory/`. A false fact saved here is recalled as true in every later session. A `MEMORY.md` outside those directories deliberately does NOT match, and neither does a project's own `docs/memory/` folder: the name alone is not an agent's memory.
|
|
291
|
+
description: "Holds a file tool opening the memory a coding agent carries between sessions: Claude Code's auto memory under `.claude/projects/<project>/memory/`, and its sub-agent memory in `.claude/agent-memory/` and `.claude/agent-memory-local/`; Codex's `.codex/memories/`; Gemini's private `.gemini/tmp/<project>/memory/`; Windsurf's `.codeium/windsurf/memories/`, including `global_rules.md`; and `.cursor/memory/`. A false fact saved here is recalled as true in every later session. A `MEMORY.md` outside those directories deliberately does NOT match, and neither does a project's own `docs/memory/` folder: the name alone is not an agent's memory. Reading is excluded \u2014 the `Read` and `Grep` tools never match \u2014 so an agent recalling a memory by reading its file is not asked; every other file tool is, including one this corpus does not know. File tools carry a path and no content, so it still cannot see what was written. Misses a memory directory moved with Claude Code's `autoMemoryDirectory` setting, and Cursor memories kept anywhere other than `.cursor/memory/`, since Cursor does not document where it stores them. Gemini memories saved into `GEMINI.md` are held by `ac.instruction-file-edit` instead.",
|
|
276
292
|
match: {
|
|
277
293
|
any_of: [
|
|
278
294
|
{ kind: "execute_tool", file_glob: "**/.claude/projects/*/memory/**" },
|
|
@@ -281,6 +297,11 @@ var acMemoryStoreEdit = {
|
|
|
281
297
|
{ kind: "execute_tool", file_glob: "**/.gemini/tmp/*/memory/**" },
|
|
282
298
|
{ kind: "execute_tool", file_glob: "**/.codeium/windsurf/memories/**" },
|
|
283
299
|
{ kind: "execute_tool", file_glob: "**/.cursor/memory/**" }
|
|
300
|
+
],
|
|
301
|
+
none_of: [
|
|
302
|
+
// A read is not an edit. Named as a deny-list rather than an `any_of` over
|
|
303
|
+
// the write tools, so an unknown file tool on a matched path still holds.
|
|
304
|
+
{ kind: "execute_tool", label: "{Read,Grep}" }
|
|
284
305
|
]
|
|
285
306
|
},
|
|
286
307
|
fixtures: {
|
|
@@ -304,7 +325,9 @@ var acMemoryStoreEdit = {
|
|
|
304
325
|
file("packages/memory-store/src/index.ts"),
|
|
305
326
|
file("/Users/dev/.claude/projects/-Users-dev-shop/transcript.jsonl"),
|
|
306
327
|
file("/home/dev/.gemini/settings.json"),
|
|
307
|
-
file(".claude/settings.json")
|
|
328
|
+
file(".claude/settings.json"),
|
|
329
|
+
file(".claude/agent-memory/reviewer/MEMORY.md", "Read"),
|
|
330
|
+
file("/home/dev/.codex/memories/project.md", "Grep")
|
|
308
331
|
]
|
|
309
332
|
}
|
|
310
333
|
};
|
|
@@ -374,7 +397,7 @@ var acSkillInstall = {
|
|
|
374
397
|
severity: "high",
|
|
375
398
|
defaultAction: "require_approval",
|
|
376
399
|
title: "The agent installing a skill, command or sub-agent",
|
|
377
|
-
description: "Holds a file tool opening a skill, slash command, sub-agent or output style that a coding agent loads by name: Claude Code's `.claude/skills/`, `.claude/commands/`, `.claude/agents/` and `.claude/output-styles/`; the shared `.agents/skills/`; Codex's `.codex/skills/`, `.codex/prompts/` and `.codex/agents/`; Gemini's `.gemini/commands/`, `.gemini/skills/` and `.gemini/agents/`; Cursor's `.cursor/skills/`, `.cursor/agents/` and `.cursor/commands/`; Windsurf's `.windsurf/workflows/` and `.windsurf/skills/` and their global copies under `.codeium/windsurf/`; Cline's `.cline/skills/`; and a `SKILL.md` anywhere, which is how a plugin ships a skill. Each becomes a reusable instruction the agent may follow later, often with a script beside it that the agent runs. Matched at project or home level and in any letter case. File tools carry a path and no content, so it cannot see what was written
|
|
400
|
+
description: "Holds a file tool opening a skill, slash command, sub-agent or output style that a coding agent loads by name: Claude Code's `.claude/skills/`, `.claude/commands/`, `.claude/agents/` and `.claude/output-styles/`; the shared `.agents/skills/`; Codex's `.codex/skills/`, `.codex/prompts/` and `.codex/agents/`; Gemini's `.gemini/commands/`, `.gemini/skills/` and `.gemini/agents/`; Cursor's `.cursor/skills/`, `.cursor/agents/` and `.cursor/commands/`; Windsurf's `.windsurf/workflows/` and `.windsurf/skills/` and their global copies under `.codeium/windsurf/`; Cline's `.cline/skills/`; and a `SKILL.md` anywhere, which is how a plugin ships a skill. Each becomes a reusable instruction the agent may follow later, often with a script beside it that the agent runs. Matched at project or home level and in any letter case. Reading is excluded \u2014 the `Read` and `Grep` tools never match \u2014 so an agent opening an installed skill to read it is not held; every other file tool is, including one this corpus does not know. File tools carry a path and no content, so it still cannot see what was written. Deliberately NOT matched: an ordinary `skills/`, `commands/` or `agents/` folder in a project's source, and `.clinerules/skills/`, which `ac.instruction-file-edit` holds. Misses a skill copied into one of these folders by a shell command such as `cp` or `git clone`, and the managed system-wide workflow folders.",
|
|
378
401
|
match: {
|
|
379
402
|
any_of: [
|
|
380
403
|
{ kind: "execute_tool", file_glob: "**/.claude/{skills,commands,agents,output-styles}/**" },
|
|
@@ -386,6 +409,11 @@ var acSkillInstall = {
|
|
|
386
409
|
{ kind: "execute_tool", file_glob: "**/.codeium/windsurf/{skills,global_workflows}/**" },
|
|
387
410
|
{ kind: "execute_tool", file_glob: "**/.cline/skills/**" },
|
|
388
411
|
{ kind: "execute_tool", file_glob: "**/SKILL.md" }
|
|
412
|
+
],
|
|
413
|
+
none_of: [
|
|
414
|
+
// A read is not an edit. Named as a deny-list rather than an `any_of` over
|
|
415
|
+
// the write tools, so an unknown file tool on a matched path still holds.
|
|
416
|
+
{ kind: "execute_tool", label: "{Read,Grep}" }
|
|
389
417
|
]
|
|
390
418
|
},
|
|
391
419
|
fixtures: {
|
|
@@ -415,7 +443,9 @@ var acSkillInstall = {
|
|
|
415
443
|
file(".claude/settings.json"),
|
|
416
444
|
file(".github/workflows/release.yml"),
|
|
417
445
|
file("scripts/release.sh"),
|
|
418
|
-
file(".gemini/settings.json")
|
|
446
|
+
file(".gemini/settings.json"),
|
|
447
|
+
file(".claude/skills/deploy/SKILL.md", "Read"),
|
|
448
|
+
file(".claude/commands/deploy.md", "Grep")
|
|
419
449
|
]
|
|
420
450
|
}
|
|
421
451
|
};
|
|
@@ -1007,7 +1037,7 @@ var fsAgentSelfConfig = {
|
|
|
1007
1037
|
severity: "high",
|
|
1008
1038
|
defaultAction: "require_approval",
|
|
1009
1039
|
title: "The agent editing its own configuration",
|
|
1010
|
-
description: "Holds a file tool opening the files that define what the agent itself is allowed to do \u2014 Claude Code settings and hooks, an MCP server list, a plugin manifest, Cursor rules, a Codex config, and the guard's own config.json and guardrails.json. An agent that can edit these can widen its own reach with nobody reviewing the change. Does NOT match ordinary project files, or `.claude/commands/*.md`, which are prompts rather than permissions. Bounded to WELL-KNOWN paths: no working directory or project root reaches the guard, so it can only match names it already knows.",
|
|
1040
|
+
description: "Holds a file tool opening the files that define what the agent itself is allowed to do \u2014 Claude Code settings and hooks, an MCP server list, a plugin manifest, Cursor rules, a Codex config, and the guard's own config.json and guardrails.json. An agent that can edit these can widen its own reach with nobody reviewing the change. Reading is excluded \u2014 the `Read` and `Grep` tools never match \u2014 so opening one of these files to read it is not held; every other file tool is, including one this corpus does not know. Does NOT match ordinary project files, or `.claude/commands/*.md`, which are prompts rather than permissions. Bounded to WELL-KNOWN paths: no working directory or project root reaches the guard, so it can only match names it already knows.",
|
|
1011
1041
|
match: {
|
|
1012
1042
|
any_of: [
|
|
1013
1043
|
{ kind: "execute_tool", file_glob: "**/.claude/settings*.json" },
|
|
@@ -1018,6 +1048,11 @@ var fsAgentSelfConfig = {
|
|
|
1018
1048
|
{ kind: "execute_tool", file_glob: "**/.codex/config.toml" },
|
|
1019
1049
|
{ kind: "execute_tool", file_glob: "**/.agenttrail/guard/config.json" },
|
|
1020
1050
|
{ kind: "execute_tool", file_glob: "**/.agenttrail/guard/guardrails.json" }
|
|
1051
|
+
],
|
|
1052
|
+
none_of: [
|
|
1053
|
+
// A read is not an edit. Named as a deny-list rather than an `any_of` over
|
|
1054
|
+
// the write tools, so an unknown file tool on a matched path still holds.
|
|
1055
|
+
{ kind: "execute_tool", label: "{Read,Grep}" }
|
|
1021
1056
|
]
|
|
1022
1057
|
},
|
|
1023
1058
|
fixtures: {
|
|
@@ -1031,7 +1066,9 @@ var fsAgentSelfConfig = {
|
|
|
1031
1066
|
file(".claude/commands/deploy.md"),
|
|
1032
1067
|
file("src/index.ts"),
|
|
1033
1068
|
file("package.json"),
|
|
1034
|
-
file("README.md")
|
|
1069
|
+
file("README.md"),
|
|
1070
|
+
file(".claude/settings.json", "Read"),
|
|
1071
|
+
file(".mcp.json", "Grep")
|
|
1035
1072
|
]
|
|
1036
1073
|
}
|
|
1037
1074
|
};
|
|
@@ -1043,7 +1080,7 @@ var fsCiDefinition = {
|
|
|
1043
1080
|
severity: "medium",
|
|
1044
1081
|
defaultAction: "require_approval",
|
|
1045
1082
|
title: "Editing the CI pipeline definition",
|
|
1046
|
-
description: "Holds a file tool opening a CI definition \u2014 GitHub Actions workflows and composite actions, .gitlab-ci.yml, a Jenkinsfile, CircleCI, Azure Pipelines, Buildkite or Bitbucket pipelines. This is where the checks that gate every merge are written down, and where a new step would run with the repository's secrets; both edits look like an ordinary diff. Does NOT match other files under .github/ (CODEOWNERS, issue templates), which gate nothing. It MISSES a CI system whose definition lives outside the repository.",
|
|
1083
|
+
description: "Holds a file tool opening a CI definition \u2014 GitHub Actions workflows and composite actions, .gitlab-ci.yml, a Jenkinsfile, CircleCI, Azure Pipelines, Buildkite or Bitbucket pipelines. This is where the checks that gate every merge are written down, and where a new step would run with the repository's secrets; both edits look like an ordinary diff. Reading is excluded \u2014 the Read and Grep tools never match \u2014 so opening a CI definition to read it is not held; every other file tool is, including one this corpus does not know. Does NOT match other files under .github/ (CODEOWNERS, issue templates), which gate nothing. It MISSES a CI system whose definition lives outside the repository.",
|
|
1047
1084
|
match: {
|
|
1048
1085
|
any_of: [
|
|
1049
1086
|
{ kind: "execute_tool", file_glob: "**/.github/workflows/**" },
|
|
@@ -1054,6 +1091,11 @@ var fsCiDefinition = {
|
|
|
1054
1091
|
{ kind: "execute_tool", file_glob: "**/azure-pipelines.yml" },
|
|
1055
1092
|
{ kind: "execute_tool", file_glob: "**/.buildkite/**" },
|
|
1056
1093
|
{ kind: "execute_tool", file_glob: "**/bitbucket-pipelines.yml" }
|
|
1094
|
+
],
|
|
1095
|
+
none_of: [
|
|
1096
|
+
// A read is not an edit. Named as a deny-list rather than an `any_of` over
|
|
1097
|
+
// the write tools, so an unknown file tool on a matched path still holds.
|
|
1098
|
+
{ kind: "execute_tool", label: "{Read,Grep}" }
|
|
1057
1099
|
]
|
|
1058
1100
|
},
|
|
1059
1101
|
fixtures: {
|
|
@@ -1067,7 +1109,9 @@ var fsCiDefinition = {
|
|
|
1067
1109
|
file(".github/CODEOWNERS"),
|
|
1068
1110
|
file(".github/PULL_REQUEST_TEMPLATE.md"),
|
|
1069
1111
|
file("package.json"),
|
|
1070
|
-
file("README.md")
|
|
1112
|
+
file("README.md"),
|
|
1113
|
+
file(".github/workflows/ci.yml", "Read"),
|
|
1114
|
+
file(".gitlab-ci.yml", "Grep")
|
|
1071
1115
|
]
|
|
1072
1116
|
}
|
|
1073
1117
|
};
|
|
@@ -1079,7 +1123,7 @@ var fsSystemPaths = {
|
|
|
1079
1123
|
severity: "high",
|
|
1080
1124
|
defaultAction: "require_approval",
|
|
1081
1125
|
title: "Writing to a system directory",
|
|
1082
|
-
description: "Holds a file tool
|
|
1126
|
+
description: "Holds a file tool writing to a path under a system directory \u2014 /etc, /bin, /sbin, /usr/bin, /usr/local/bin, /boot, /System, /Library/LaunchDaemons, or Windows/System32. Reading is excluded \u2014 the Read and Grep tools never match \u2014 so reading /etc/hosts is not held; every other file tool is, including one this corpus does not know. HONEST CEILING: this is a list of well-known ABSOLUTE paths and it cannot be anything else. No working directory and no project root reaches the guard, so the rule you would actually want \u2014 'the agent wrote outside the project' \u2014 is inexpressible, and would match everything or nothing. It therefore MISSES a write anywhere else outside your repository, including another project on the same machine.",
|
|
1083
1127
|
match: {
|
|
1084
1128
|
any_of: [
|
|
1085
1129
|
{ kind: "execute_tool", file_glob: "/etc/**" },
|
|
@@ -1091,6 +1135,11 @@ var fsSystemPaths = {
|
|
|
1091
1135
|
{ kind: "execute_tool", file_glob: "/System/**" },
|
|
1092
1136
|
{ kind: "execute_tool", file_glob: "/Library/LaunchDaemons/**" },
|
|
1093
1137
|
{ kind: "execute_tool", file_glob: "**/Windows/System32/**" }
|
|
1138
|
+
],
|
|
1139
|
+
none_of: [
|
|
1140
|
+
// A read is not an edit. Named as a deny-list rather than an `any_of` over
|
|
1141
|
+
// the write tools, so an unknown file tool on a matched path still holds.
|
|
1142
|
+
{ kind: "execute_tool", label: "{Read,Grep}" }
|
|
1094
1143
|
]
|
|
1095
1144
|
},
|
|
1096
1145
|
fixtures: {
|
|
@@ -1104,7 +1153,9 @@ var fsSystemPaths = {
|
|
|
1104
1153
|
file("src/index.ts"),
|
|
1105
1154
|
file("/home/dev/project/src/main.rs"),
|
|
1106
1155
|
file("/tmp/scratch.txt", "Write"),
|
|
1107
|
-
file("docs/etc-notes.md")
|
|
1156
|
+
file("docs/etc-notes.md"),
|
|
1157
|
+
file("/etc/hosts", "Read"),
|
|
1158
|
+
file("/usr/local/bin/app", "Grep")
|
|
1108
1159
|
]
|
|
1109
1160
|
}
|
|
1110
1161
|
};
|
|
@@ -1116,7 +1167,7 @@ var fsVcsInternals = {
|
|
|
1116
1167
|
severity: "high",
|
|
1117
1168
|
defaultAction: "require_approval",
|
|
1118
1169
|
title: "Editing git's internals directly",
|
|
1119
|
-
description: "Holds a file tool opening git's own bookkeeping \u2014 .git/config, .git/hooks/, .git/refs/, .git/HEAD, .git/info/exclude \u2014 where a change alters what future git commands do rather than what the repository contains. Deliberately NARROW: all of .git/** would include COMMIT_EDITMSG and the index, which change during every ordinary commit, so the rule would fire constantly and be switched off. It does NOT match .gitignore, .gitattributes or anything under .github/, which are tracked project files.",
|
|
1170
|
+
description: "Holds a file tool opening git's own bookkeeping \u2014 .git/config, .git/hooks/, .git/refs/, .git/HEAD, .git/info/exclude \u2014 where a change alters what future git commands do rather than what the repository contains. Deliberately NARROW: all of .git/** would include COMMIT_EDITMSG and the index, which change during every ordinary commit, so the rule would fire constantly and be switched off. Reading is excluded \u2014 the Read and Grep tools never match \u2014 so opening .git/config to read it is not held; every other file tool is, including one this corpus does not know. It does NOT match .gitignore, .gitattributes or anything under .github/, which are tracked project files.",
|
|
1120
1171
|
match: {
|
|
1121
1172
|
any_of: [
|
|
1122
1173
|
{ kind: "execute_tool", file_glob: "**/.git/config" },
|
|
@@ -1124,6 +1175,11 @@ var fsVcsInternals = {
|
|
|
1124
1175
|
{ kind: "execute_tool", file_glob: "**/.git/refs/**" },
|
|
1125
1176
|
{ kind: "execute_tool", file_glob: "**/.git/HEAD" },
|
|
1126
1177
|
{ kind: "execute_tool", file_glob: "**/.git/info/exclude" }
|
|
1178
|
+
],
|
|
1179
|
+
none_of: [
|
|
1180
|
+
// A read is not an edit. Named as a deny-list rather than an `any_of` over
|
|
1181
|
+
// the write tools, so an unknown file tool on a matched path still holds.
|
|
1182
|
+
{ kind: "execute_tool", label: "{Read,Grep}" }
|
|
1127
1183
|
]
|
|
1128
1184
|
},
|
|
1129
1185
|
fixtures: {
|
|
@@ -1137,7 +1193,9 @@ var fsVcsInternals = {
|
|
|
1137
1193
|
file(".gitignore"),
|
|
1138
1194
|
file(".gitattributes"),
|
|
1139
1195
|
file(".github/CODEOWNERS"),
|
|
1140
|
-
file("src/index.ts")
|
|
1196
|
+
file("src/index.ts"),
|
|
1197
|
+
file(".git/config", "Read"),
|
|
1198
|
+
file(".git/hooks/pre-commit", "Grep")
|
|
1141
1199
|
]
|
|
1142
1200
|
}
|
|
1143
1201
|
};
|
|
@@ -1448,7 +1506,7 @@ var blockProdConfigEdit = {
|
|
|
1448
1506
|
severity: "high",
|
|
1449
1507
|
defaultAction: "require_approval",
|
|
1450
1508
|
title: "Approve production config edits",
|
|
1451
|
-
description: "Routes edits to production configuration files to human approval. Matched by path: `*.prod.*` and `*.production.*`, the bare `prod.*` / `production.*` spellings, and any file under a `prod/` or `production/` directory. Prose is excluded \u2014 `.md`, `.mdx` and `.txt` never match \u2014 so writing a runbook under `docs/production/` does not ask for approval to change production. It matches the PATH only: it cannot tell a real production config from a file that merely spells prod in its name, and it MISSES a production config named something else entirely, such as `values-live.yaml`.",
|
|
1509
|
+
description: "Routes edits to production configuration files to human approval. Matched by path: `*.prod.*` and `*.production.*`, the bare `prod.*` / `production.*` spellings, and any file under a `prod/` or `production/` directory. Reading is excluded \u2014 the `Read` and `Grep` tools never match \u2014 so opening a production config to look at it does not ask for approval; every other file tool does, including one this corpus does not know. Prose is excluded too \u2014 `.md`, `.mdx` and `.txt` never match \u2014 so writing a runbook under `docs/production/` does not ask for approval to change production. It matches the PATH only: it cannot tell a real production config from a file that merely spells prod in its name, and it MISSES a production config named something else entirely, such as `values-live.yaml`.",
|
|
1452
1510
|
match: {
|
|
1453
1511
|
any_of: [
|
|
1454
1512
|
{ kind: "execute_tool", file_glob: "**/*.prod.*" },
|
|
@@ -1459,6 +1517,9 @@ var blockProdConfigEdit = {
|
|
|
1459
1517
|
{ kind: "execute_tool", file_glob: "**/production/**" }
|
|
1460
1518
|
],
|
|
1461
1519
|
none_of: [
|
|
1520
|
+
// A read is not an edit. Named as a deny-list rather than an `any_of` over
|
|
1521
|
+
// the write tools, so an unknown file tool on a matched path still holds.
|
|
1522
|
+
{ kind: "execute_tool", label: "{Read,Grep}" },
|
|
1462
1523
|
{ kind: "execute_tool", file_glob: "**/*.md" },
|
|
1463
1524
|
{ kind: "execute_tool", file_glob: "**/*.mdx" },
|
|
1464
1525
|
{ kind: "execute_tool", file_glob: "**/*.txt" }
|
|
@@ -1476,7 +1537,9 @@ var blockProdConfigEdit = {
|
|
|
1476
1537
|
file("docs/production/README.md"),
|
|
1477
1538
|
file("config/database.dev.yml"),
|
|
1478
1539
|
file("src/index.ts"),
|
|
1479
|
-
file("package.json")
|
|
1540
|
+
file("package.json"),
|
|
1541
|
+
file("config/database.prod.yml", "Read"),
|
|
1542
|
+
file("k8s/production/deployment.yaml", "Grep")
|
|
1480
1543
|
]
|
|
1481
1544
|
}
|
|
1482
1545
|
};
|
|
@@ -2449,7 +2512,7 @@ var requireAuthOnPiiEndpoints = {
|
|
|
2449
2512
|
severity: "medium",
|
|
2450
2513
|
defaultAction: "require_approval",
|
|
2451
2514
|
title: "Review API endpoint changes for auth",
|
|
2452
|
-
description: "Routes edits to API route/handler SOURCE files to human approval so a reviewer can confirm authentication is present on new or changed endpoints. Matched by path: a source file under routes/, handlers/ or controllers/; an api/ directory nested inside a source tree (src/api/, app/api/, pages/api/); Next's route.ts convention; and the <name>.controller.* / <name>.routes.* spellings. HEURISTIC: a path signal only \u2014 it cannot inspect the edit for a missing auth check or exposed PII, so treat a match as confirm auth on this endpoint, not as a finding. It deliberately does NOT match every file in a package merely NAMED api, nor a client-side router table such as routes.tsx, which defines no endpoint; and it MISSES endpoints declared inline in a server file or by a framework convention not listed above.",
|
|
2515
|
+
description: "Routes edits to API route/handler SOURCE files to human approval so a reviewer can confirm authentication is present on new or changed endpoints. Matched by path: a source file under routes/, handlers/ or controllers/; an api/ directory nested inside a source tree (src/api/, app/api/, pages/api/); Next's route.ts convention; and the <name>.controller.* / <name>.routes.* spellings. Reading is excluded \u2014 the Read and Grep tools never match \u2014 so opening an endpoint's source to read it does not ask for approval; every other file tool does, including one this corpus does not know. HEURISTIC: a path signal only \u2014 it cannot inspect the edit for a missing auth check or exposed PII, so treat a match as confirm auth on this endpoint, not as a finding. It deliberately does NOT match every file in a package merely NAMED api, nor a client-side router table such as routes.tsx, which defines no endpoint; and it MISSES endpoints declared inline in a server file or by a framework convention not listed above.",
|
|
2453
2516
|
match: {
|
|
2454
2517
|
any_of: [
|
|
2455
2518
|
{ kind: "execute_tool", file_glob: `**/routes/**/*.${SOURCE}` },
|
|
@@ -2461,6 +2524,11 @@ var requireAuthOnPiiEndpoints = {
|
|
|
2461
2524
|
{ kind: "execute_tool", file_glob: `**/route.${SOURCE}` },
|
|
2462
2525
|
{ kind: "execute_tool", file_glob: `**/*.controller.${SOURCE}` },
|
|
2463
2526
|
{ kind: "execute_tool", file_glob: `**/*.routes.${SOURCE}` }
|
|
2527
|
+
],
|
|
2528
|
+
none_of: [
|
|
2529
|
+
// A read is not an edit. Named as a deny-list rather than an `any_of` over
|
|
2530
|
+
// the write tools, so an unknown file tool on a matched path still holds.
|
|
2531
|
+
{ kind: "execute_tool", label: "{Read,Grep}" }
|
|
2464
2532
|
]
|
|
2465
2533
|
},
|
|
2466
2534
|
fixtures: {
|
|
@@ -2474,7 +2542,9 @@ var requireAuthOnPiiEndpoints = {
|
|
|
2474
2542
|
file("apps/api/README.md"),
|
|
2475
2543
|
file("apps/api/package.json"),
|
|
2476
2544
|
file("apps/api/src/lib/logger.ts"),
|
|
2477
|
-
file("apps/web/src/app/routes.tsx")
|
|
2545
|
+
file("apps/web/src/app/routes.tsx"),
|
|
2546
|
+
file("src/api/users.ts", "Read"),
|
|
2547
|
+
file("src/controllers/payments.ts", "Grep")
|
|
2478
2548
|
]
|
|
2479
2549
|
}
|
|
2480
2550
|
};
|
|
@@ -3031,7 +3101,7 @@ var tiTestConfigEdit = {
|
|
|
3031
3101
|
severity: "medium",
|
|
3032
3102
|
defaultAction: "require_approval",
|
|
3033
3103
|
title: "Editing a test runner or coverage configuration",
|
|
3034
|
-
description: "Holds a file tool opening a test runner's or coverage tool's own configuration: Jest's `jest.config.*`, Vitest's `vitest.config.*` and legacy `vitest.workspace.*`, `pytest.ini`, `pytest.toml` and their dotted forms, `tox.ini`, Mocha's `.mocharc.*`, PHPUnit's `phpunit.xml`, `phpunit.xml.dist` and `phpunit.dist.xml`, `codecov.yml`, nyc's `.nycrc*` and `nyc.config.*`, `.c8rc`, coverage.py's `.coveragerc`, `karma.conf.*`, and the Playwright and Cypress configs. One line in any of these can exclude a failing file, lower a coverage threshold or retry a flaky test until it passes. File tools carry a path and no content, so it cannot tell a harmless edit from a weakening one
|
|
3104
|
+
description: "Holds a file tool opening a test runner's or coverage tool's own configuration: Jest's `jest.config.*`, Vitest's `vitest.config.*` and legacy `vitest.workspace.*`, `pytest.ini`, `pytest.toml` and their dotted forms, `tox.ini`, Mocha's `.mocharc.*`, PHPUnit's `phpunit.xml`, `phpunit.xml.dist` and `phpunit.dist.xml`, `codecov.yml`, nyc's `.nycrc*` and `nyc.config.*`, `.c8rc`, coverage.py's `.coveragerc`, `karma.conf.*`, and the Playwright and Cypress configs. One line in any of these can exclude a failing file, lower a coverage threshold or retry a flaky test until it passes. Reading is excluded \u2014 the `Read` and `Grep` tools never match \u2014 so opening one of these configs to read it is not held; every other file tool is, including one this corpus does not know. File tools carry a path and no content, so it still cannot tell a harmless edit from a weakening one. Deliberately NOT matched: general files that can also hold test settings \u2014 `pyproject.toml`, `setup.cfg`, `package.json`, `vite.config.*` \u2014 and test files themselves, since editing a test is how a test gets fixed. Misses test settings kept in those general files, and a config at a path passed with `--config`.",
|
|
3035
3105
|
match: {
|
|
3036
3106
|
any_of: [
|
|
3037
3107
|
{ kind: "execute_tool", file_glob: "**/jest.config.{js,ts,mjs,mts,cjs,cts,json}" },
|
|
@@ -3056,6 +3126,11 @@ var tiTestConfigEdit = {
|
|
|
3056
3126
|
kind: "execute_tool",
|
|
3057
3127
|
file_glob: "**/{playwright,cypress}.config.{js,ts,mjs,mts,cjs,cts}"
|
|
3058
3128
|
}
|
|
3129
|
+
],
|
|
3130
|
+
none_of: [
|
|
3131
|
+
// A read is not an edit. Named as a deny-list rather than an `any_of` over
|
|
3132
|
+
// the write tools, so an unknown file tool on a matched path still holds.
|
|
3133
|
+
{ kind: "execute_tool", label: "{Read,Grep}" }
|
|
3059
3134
|
]
|
|
3060
3135
|
},
|
|
3061
3136
|
fixtures: {
|
|
@@ -3088,7 +3163,9 @@ var tiTestConfigEdit = {
|
|
|
3088
3163
|
file("jest.setup.js"),
|
|
3089
3164
|
file(".env.test"),
|
|
3090
3165
|
file("docs/testing.md"),
|
|
3091
|
-
file("biome.json")
|
|
3166
|
+
file("biome.json"),
|
|
3167
|
+
file("vitest.config.ts", "Read"),
|
|
3168
|
+
file("jest.config.js", "Grep")
|
|
3092
3169
|
]
|
|
3093
3170
|
}
|
|
3094
3171
|
};
|
|
@@ -3574,8 +3651,8 @@ function isPack(value) {
|
|
|
3574
3651
|
}
|
|
3575
3652
|
|
|
3576
3653
|
// src/stamp.ts
|
|
3577
|
-
var CATALOG_VERSION = "0.2.
|
|
3578
|
-
var CATALOG_PUBLISHED_AT = "2026-09-
|
|
3654
|
+
var CATALOG_VERSION = "0.2.1";
|
|
3655
|
+
var CATALOG_PUBLISHED_AT = "2026-09-29T03:49:22Z";
|
|
3579
3656
|
|
|
3580
3657
|
// src/rules.ts
|
|
3581
3658
|
var RULES_BY_PACK = {
|
|
@@ -3625,4 +3702,4 @@ export {
|
|
|
3625
3702
|
getRule,
|
|
3626
3703
|
rulesForPack
|
|
3627
3704
|
};
|
|
3628
|
-
//# sourceMappingURL=chunk-
|
|
3705
|
+
//# sourceMappingURL=chunk-SLWHBH7H.js.map
|