ghostrules 0.2.1__tar.gz → 0.4.0__tar.gz

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 (283) hide show
  1. {ghostrules-0.2.1 → ghostrules-0.4.0}/.ghostrules.lock +7 -7
  2. {ghostrules-0.2.1 → ghostrules-0.4.0}/.ghostrules.toml +2 -0
  3. ghostrules-0.4.0/.github/dependabot.yml +10 -0
  4. {ghostrules-0.2.1 → ghostrules-0.4.0}/.github/workflows/ci.yml +2 -2
  5. ghostrules-0.4.0/.github/workflows/corpus.yml +80 -0
  6. ghostrules-0.4.0/.github/workflows/pages.yml +48 -0
  7. {ghostrules-0.2.1 → ghostrules-0.4.0}/.github/workflows/release.yml +27 -6
  8. {ghostrules-0.2.1 → ghostrules-0.4.0}/.github/workflows/self-test.yml +8 -2
  9. ghostrules-0.4.0/.gitignore +23 -0
  10. ghostrules-0.4.0/CHANGELOG.md +314 -0
  11. {ghostrules-0.2.1 → ghostrules-0.4.0}/CLAUDE.md +1 -1
  12. {ghostrules-0.2.1 → ghostrules-0.4.0}/CONTRIBUTING.md +15 -1
  13. ghostrules-0.4.0/PKG-INFO +233 -0
  14. ghostrules-0.4.0/README.md +173 -0
  15. ghostrules-0.4.0/action-requirements.in +3 -0
  16. ghostrules-0.4.0/action-requirements.txt +60 -0
  17. ghostrules-0.4.0/action.yml +320 -0
  18. ghostrules-0.4.0/assets/banner-dark.png +0 -0
  19. ghostrules-0.4.0/assets/banner-light.png +0 -0
  20. ghostrules-0.4.0/assets/logo.svg +7 -0
  21. ghostrules-0.4.0/assets/social-preview.png +0 -0
  22. ghostrules-0.4.0/bench/.cache-run.log +1 -0
  23. ghostrules-0.4.0/bench/README.md +44 -0
  24. ghostrules-0.4.0/bench/RESULTS.md +97 -0
  25. ghostrules-0.4.0/bench/attacks/context-and-config.toml +246 -0
  26. ghostrules-0.4.0/bench/attacks/prose.toml +463 -0
  27. ghostrules-0.4.0/bench/attacks/sources.toml +42 -0
  28. ghostrules-0.4.0/bench/attacks/unicode.toml +212 -0
  29. ghostrules-0.4.0/bench/attacks/w5.toml +237 -0
  30. ghostrules-0.4.0/bench/heldout-labels.toml +130 -0
  31. ghostrules-0.4.0/bench/heldout-results.json +116 -0
  32. ghostrules-0.4.0/bench/heldout.toml +315 -0
  33. ghostrules-0.4.0/bench/lib.py +203 -0
  34. ghostrules-0.4.0/bench/run.py +275 -0
  35. {ghostrules-0.2.1 → ghostrules-0.4.0}/docs/AGENT_MODELS.md +69 -4
  36. {ghostrules-0.2.1 → ghostrules-0.4.0}/docs/DECISIONS.md +399 -0
  37. {ghostrules-0.2.1 → ghostrules-0.4.0}/docs/RULES.md +176 -11
  38. ghostrules-0.2.1/PKG-INFO → ghostrules-0.4.0/docs/USAGE.md +272 -259
  39. ghostrules-0.4.0/docs/design/v0.3/CORPUS.md +82 -0
  40. ghostrules-0.4.0/docs/design/v0.3/PLAN.md +40 -0
  41. ghostrules-0.4.0/docs/design/v0.3/PLAYGROUND.md +53 -0
  42. ghostrules-0.4.0/docs/design/v0.3/STUDY.md +56 -0
  43. ghostrules-0.4.0/docs/design/v0.4/REMEDIATION.md +186 -0
  44. ghostrules-0.4.0/docs/v0.2.1/FIXES.md +116 -0
  45. {ghostrules-0.2.1 → ghostrules-0.4.0}/pyproject.toml +10 -0
  46. ghostrules-0.4.0/release-notes.md +108 -0
  47. ghostrules-0.4.0/scripts/build_site.py +41 -0
  48. {ghostrules-0.2.1 → ghostrules-0.4.0}/scripts/gen_rules_table.py +13 -15
  49. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/__init__.py +1 -1
  50. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/agents/__init__.py +11 -1
  51. ghostrules-0.4.0/src/ghostrules/agents/codex.py +122 -0
  52. ghostrules-0.4.0/src/ghostrules/agents/gemini_cli.py +97 -0
  53. ghostrules-0.4.0/src/ghostrules/baseline.py +70 -0
  54. ghostrules-0.4.0/src/ghostrules/changeset.py +35 -0
  55. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/cli.py +231 -7
  56. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/config.py +13 -3
  57. ghostrules-0.4.0/src/ghostrules/context.py +59 -0
  58. ghostrules-0.4.0/src/ghostrules/firstparty.py +83 -0
  59. ghostrules-0.4.0/src/ghostrules/gitref.py +109 -0
  60. ghostrules-0.4.0/src/ghostrules/ignores.py +36 -0
  61. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/imports.py +3 -0
  62. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/models.py +28 -1
  63. ghostrules-0.4.0/src/ghostrules/playground.py +152 -0
  64. ghostrules-0.4.0/src/ghostrules/reach.py +233 -0
  65. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/reporters/common.py +3 -0
  66. ghostrules-0.4.0/src/ghostrules/reporters/context.py +161 -0
  67. ghostrules-0.2.1/src/ghostrules/reporters/context.py → ghostrules-0.4.0/src/ghostrules/reporters/context_data.py +3 -147
  68. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/reporters/json_.py +1 -0
  69. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/reporters/sarif.py +1 -1
  70. ghostrules-0.4.0/src/ghostrules/reveal.py +37 -0
  71. ghostrules-0.4.0/src/ghostrules/reveal_data.py +107 -0
  72. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/rules/__init__.py +11 -1
  73. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/rules/agent_settings.py +54 -0
  74. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/rules/context_rules.py +14 -0
  75. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/rules/directive.py +6 -4
  76. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/rules/injection.py +245 -16
  77. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/rules/known_installers.py +19 -3
  78. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/rules/patterns.py +31 -10
  79. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/rules/registry.py +35 -3
  80. ghostrules-0.4.0/src/ghostrules/rules/scanner_config.py +165 -0
  81. ghostrules-0.4.0/src/ghostrules/rules/scripts.py +300 -0
  82. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/rules/unicode.py +24 -3
  83. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/scanner.py +209 -18
  84. ghostrules-0.4.0/src/ghostrules/schemas/context.schema.json +107 -0
  85. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/sensitive.py +3 -1
  86. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/targets.py +8 -0
  87. ghostrules-0.4.0/src/ghostrules/visibility.py +40 -0
  88. ghostrules-0.4.0/study/analyze.py +278 -0
  89. ghostrules-0.4.0/study/charts/01-adoption-dark.svg +245 -0
  90. ghostrules-0.4.0/study/charts/01-adoption-light.svg +245 -0
  91. ghostrules-0.4.0/study/charts/02-tools-per-repo-dark.svg +143 -0
  92. ghostrules-0.4.0/study/charts/02-tools-per-repo-light.svg +143 -0
  93. ghostrules-0.4.0/study/charts/03-claude-agents-dark.svg +126 -0
  94. ghostrules-0.4.0/study/charts/03-claude-agents-light.svg +126 -0
  95. ghostrules-0.4.0/study/charts/04-what-agents-read-dark.svg +143 -0
  96. ghostrules-0.4.0/study/charts/04-what-agents-read-light.svg +143 -0
  97. ghostrules-0.4.0/study/charts/05-risk-dark.svg +126 -0
  98. ghostrules-0.4.0/study/charts/05-risk-light.svg +126 -0
  99. ghostrules-0.4.0/study/charts/06-precision-dark.svg +432 -0
  100. ghostrules-0.4.0/study/charts/06-precision-light.svg +432 -0
  101. ghostrules-0.4.0/study/charts.py +283 -0
  102. ghostrules-0.4.0/study/data/adoption_families.csv +13 -0
  103. ghostrules-0.4.0/study/data/claude_agents_relation.csv +5 -0
  104. ghostrules-0.4.0/study/data/conditional_rules.csv +5 -0
  105. ghostrules-0.4.0/study/data/findings_by_rule.csv +33 -0
  106. ghostrules-0.4.0/study/data/headline.json +18 -0
  107. ghostrules-0.4.0/study/data/imports.csv +6 -0
  108. ghostrules-0.4.0/study/data/instruction_file_lines.csv +6 -0
  109. ghostrules-0.4.0/study/data/numbers.csv +12 -0
  110. ghostrules-0.4.0/study/data/precision_by_rule.csv +15 -0
  111. ghostrules-0.4.0/study/data/precision_runs.csv +5 -0
  112. ghostrules-0.4.0/study/data/risk_indicators.csv +7 -0
  113. ghostrules-0.4.0/study/data/sample.csv +3 -0
  114. ghostrules-0.4.0/study/data/skills_concentration.csv +7 -0
  115. ghostrules-0.4.0/study/data/tools_per_repo.csv +8 -0
  116. ghostrules-0.4.0/study/features.py +138 -0
  117. ghostrules-0.4.0/study/label_classes.py +136 -0
  118. ghostrules-0.4.0/study/labels.toml +2646 -0
  119. ghostrules-0.4.0/study/report.md +227 -0
  120. ghostrules-0.4.0/study/report.py +267 -0
  121. ghostrules-0.4.0/tests/corpus_fakes.py +103 -0
  122. ghostrules-0.4.0/tests/pr_helpers.py +121 -0
  123. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_agents_others.py +1 -1
  124. ghostrules-0.4.0/tests/test_baseline.py +125 -0
  125. ghostrules-0.4.0/tests/test_bench.py +173 -0
  126. ghostrules-0.4.0/tests/test_bench_heldout.py +32 -0
  127. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_ci_files.py +440 -16
  128. ghostrules-0.4.0/tests/test_codex_gemini.py +275 -0
  129. ghostrules-0.4.0/tests/test_context_api.py +59 -0
  130. ghostrules-0.4.0/tests/test_core_without_cli_deps.py +74 -0
  131. ghostrules-0.4.0/tests/test_corpus_packaging.py +31 -0
  132. ghostrules-0.4.0/tests/test_corpus_tools.py +682 -0
  133. ghostrules-0.4.0/tests/test_crlf.py +26 -0
  134. ghostrules-0.4.0/tests/test_cross_sentence.py +44 -0
  135. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_directive.py +1 -1
  136. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_docs.py +131 -51
  137. ghostrules-0.4.0/tests/test_gr030.py +205 -0
  138. ghostrules-0.4.0/tests/test_hidden_ignores.py +106 -0
  139. ghostrules-0.4.0/tests/test_hook_scripts.py +289 -0
  140. ghostrules-0.4.0/tests/test_lock_base.py +98 -0
  141. ghostrules-0.4.0/tests/test_noise_fixes.py +174 -0
  142. ghostrules-0.4.0/tests/test_playground.py +62 -0
  143. ghostrules-0.4.0/tests/test_pr_mode.py +207 -0
  144. ghostrules-0.4.0/tests/test_precision_study.py +164 -0
  145. ghostrules-0.4.0/tests/test_precision_v030.py +343 -0
  146. ghostrules-0.4.0/tests/test_referenced_files.py +116 -0
  147. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_reporters.py +1 -1
  148. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_rules_injection.py +4 -3
  149. ghostrules-0.4.0/tests/test_study.py +138 -0
  150. ghostrules-0.4.0/tests/test_visibility.py +96 -0
  151. ghostrules-0.4.0/tests/web/test_playground_smoke.py +99 -0
  152. ghostrules-0.4.0/web/app.js +376 -0
  153. ghostrules-0.4.0/web/index.html +77 -0
  154. ghostrules-0.4.0/web/style.css +101 -0
  155. ghostrules-0.2.1/.gitignore +0 -14
  156. ghostrules-0.2.1/CHANGELOG.md +0 -150
  157. ghostrules-0.2.1/README.md +0 -525
  158. ghostrules-0.2.1/action.yml +0 -148
  159. ghostrules-0.2.1/release-notes.md +0 -43
  160. ghostrules-0.2.1/src/ghostrules/reveal.py +0 -90
  161. {ghostrules-0.2.1 → ghostrules-0.4.0}/.gitattributes +0 -0
  162. {ghostrules-0.2.1 → ghostrules-0.4.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  163. {ghostrules-0.2.1 → ghostrules-0.4.0}/.github/ISSUE_TEMPLATE/false-positive.yml +0 -0
  164. {ghostrules-0.2.1 → ghostrules-0.4.0}/.github/ISSUE_TEMPLATE/new-rule.yml +0 -0
  165. {ghostrules-0.2.1 → ghostrules-0.4.0}/.pre-commit-hooks.yaml +0 -0
  166. {ghostrules-0.2.1 → ghostrules-0.4.0}/LICENSE +0 -0
  167. {ghostrules-0.2.1 → ghostrules-0.4.0}/SECURITY.md +0 -0
  168. {ghostrules-0.2.1 → ghostrules-0.4.0}/demo/README.md +0 -0
  169. {ghostrules-0.2.1 → ghostrules-0.4.0}/demo/demo.gif +0 -0
  170. {ghostrules-0.2.1 → ghostrules-0.4.0}/demo/demo.tape +0 -0
  171. {ghostrules-0.2.1 → ghostrules-0.4.0}/demo/imports.gif +0 -0
  172. {ghostrules-0.2.1 → ghostrules-0.4.0}/demo/imports.tape +0 -0
  173. {ghostrules-0.2.1 → ghostrules-0.4.0}/demo/lock.tape +0 -0
  174. {ghostrules-0.2.1 → ghostrules-0.4.0}/docs/design/PLAN.md +0 -0
  175. {ghostrules-0.2.1 → ghostrules-0.4.0}/docs/design/SPEC.md +0 -0
  176. {ghostrules-0.2.1 → ghostrules-0.4.0}/docs/design/v0.1.1/GR012-FIX.md +0 -0
  177. {ghostrules-0.2.1 → ghostrules-0.4.0}/docs/design/v0.2/PLAN.md +0 -0
  178. {ghostrules-0.2.1 → ghostrules-0.4.0}/docs/design/v0.2/RULES.md +0 -0
  179. {ghostrules-0.2.1 → ghostrules-0.4.0}/docs/design/v0.2/SPEC.md +0 -0
  180. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/clean-repo/.claude/settings.json +0 -0
  181. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/clean-repo/.mcp.json +0 -0
  182. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/clean-repo/AGENTS.md +0 -0
  183. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/clean-repo/CLAUDE.md +0 -0
  184. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/clean-repo/README.md +0 -0
  185. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/import-chain-repo/.claude/rules/api.md +0 -0
  186. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/import-chain-repo/.env +0 -0
  187. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/import-chain-repo/AGENTS.md +0 -0
  188. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/import-chain-repo/CLAUDE.md +0 -0
  189. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/import-chain-repo/README.md +0 -0
  190. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/import-chain-repo/docs/setup.md +0 -0
  191. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/import-chain-repo/docs/style.md +0 -0
  192. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/import-chain-repo/shared/team-rules.md +0 -0
  193. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/import-chain-repo/src/api/users.ts +0 -0
  194. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/import-chain-repo/src/legacy/CLAUDE.md +0 -0
  195. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/poisoned-repo/.claude/settings.json +0 -0
  196. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/poisoned-repo/.claude/skills/setup/SKILL.md +0 -0
  197. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/poisoned-repo/.cursorrules +0 -0
  198. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/poisoned-repo/.github/copilot-instructions.md +0 -0
  199. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/poisoned-repo/.mcp.json +0 -0
  200. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/poisoned-repo/AGENTS.md +0 -0
  201. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/poisoned-repo/CLAUDE.md +0 -0
  202. {ghostrules-0.2.1 → ghostrules-0.4.0}/examples/poisoned-repo/README.md +0 -0
  203. {ghostrules-0.2.1 → ghostrules-0.4.0}/scripts/changelog_section.py +0 -0
  204. {ghostrules-0.2.1 → ghostrules-0.4.0}/scripts/make_demo.py +0 -0
  205. {ghostrules-0.2.1 → ghostrules-0.4.0}/scripts/make_fixtures.py +0 -0
  206. {ghostrules-0.2.1 → ghostrules-0.4.0}/scripts/set_owner.py +0 -0
  207. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/_compat.py +0 -0
  208. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/agents/base.py +0 -0
  209. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/agents/claude_code.py +0 -0
  210. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/agents/copilot_cli.py +0 -0
  211. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/agents/cursor.py +0 -0
  212. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/agents/generic.py +0 -0
  213. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/agents/repo.py +0 -0
  214. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/clean.py +0 -0
  215. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/context_command.py +0 -0
  216. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/contextscan.py +0 -0
  217. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/globs.py +0 -0
  218. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/jsonloc.py +0 -0
  219. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/lock.py +0 -0
  220. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/markdown_utils.py +0 -0
  221. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/mcp_config.py +0 -0
  222. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/py.typed +0 -0
  223. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/reporters/__init__.py +0 -0
  224. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/reporters/lock.py +0 -0
  225. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/reporters/markdown.py +0 -0
  226. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/reporters/table.py +0 -0
  227. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/rules/helpers.py +0 -0
  228. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/rules/mcp.py +0 -0
  229. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/scancontext.py +0 -0
  230. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/secrets.py +0 -0
  231. {ghostrules-0.2.1 → ghostrules-0.4.0}/src/ghostrules/unicode_utils.py +0 -0
  232. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/conftest.py +0 -0
  233. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/data/sarif-schema-2.1.0.json +0 -0
  234. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr001_flag_forged/AGENTS.md +0 -0
  235. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr001_flag_ok/AGENTS.md +0 -0
  236. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr001_tags/AGENTS.md +0 -0
  237. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr002_bidi/AGENTS.md +0 -0
  238. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr002_rtl_medium/AGENTS.md +0 -0
  239. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr003_bom_midfile/AGENTS.md +0 -0
  240. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr003_bom_ok/AGENTS.md +0 -0
  241. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr003_emoji_zwj_ok/AGENTS.md +0 -0
  242. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr003_indic_ok/AGENTS.md +0 -0
  243. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr003_persian_ok/AGENTS.md +0 -0
  244. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr003_soft_hyphen/AGENTS.md +0 -0
  245. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr003_zw_file_high/AGENTS.md +0 -0
  246. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr003_zw_line_high/AGENTS.md +0 -0
  247. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr003_zw_medium/AGENTS.md +0 -0
  248. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr004_vs_bytes/AGENTS.md +0 -0
  249. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr004_vs_ok/AGENTS.md +0 -0
  250. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr005_benign_ok/CLAUDE.md +0 -0
  251. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr005_comment_imperative/CLAUDE.md +0 -0
  252. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr005_comment_injection/CLAUDE.md +0 -0
  253. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr005_comment_multiline/CLAUDE.md +0 -0
  254. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr005_in_code_block_ok/CLAUDE.md +0 -0
  255. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr005_short_ok/CLAUDE.md +0 -0
  256. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr005_unterminated/CLAUDE.md +0 -0
  257. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr006_ok/AGENTS.md +0 -0
  258. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr006_url/AGENTS.md +0 -0
  259. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/fixtures/unicode/gr006_word/AGENTS.md +0 -0
  260. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/secret_samples.py +0 -0
  261. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_agents_claude.py +0 -0
  262. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_agents_repo.py +0 -0
  263. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_cli.py +0 -0
  264. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_config.py +0 -0
  265. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_context_command.py +0 -0
  266. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_demo.py +0 -0
  267. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_globs.py +0 -0
  268. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_imports.py +0 -0
  269. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_lock.py +0 -0
  270. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_markdown_utils.py +0 -0
  271. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_mcp_config.py +0 -0
  272. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_models.py +0 -0
  273. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_patterns.py +0 -0
  274. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_precision_v021.py +0 -0
  275. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_rules_config.py +0 -0
  276. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_rules_unicode.py +0 -0
  277. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_scan_imports.py +0 -0
  278. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_scanner.py +0 -0
  279. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_secret_masking.py +0 -0
  280. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_secrets.py +0 -0
  281. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_symlink_alias.py +0 -0
  282. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_targets.py +0 -0
  283. {ghostrules-0.2.1 → ghostrules-0.4.0}/tests/test_unicode_utils.py +0 -0
@@ -3,22 +3,22 @@
3
3
  "claude-code": [
4
4
  {
5
5
  "conditions": [],
6
- "lines": "2a3d3f1fb26381e9 e3b0c44298fc1c14 ddabff43c0a4efe5 6aa552cc1598dcb7 be186e6b970ab643 fb78540ec32b52f9 e3b0c44298fc1c14 d393a517d5cbec9f e3b0c44298fc1c14 85b7ae55df076ab0 2f6995b0ecd75c8d e3b0c44298fc1c14 5f2235a1b010f82c 56a4406ad70b7f0a ba2cd86d7e76eff5 a7b723b74ee03fc8 e3b0c44298fc1c14 782729a560418c17 36a8e590ff4c085c e3b0c44298fc1c14 9f4e3cc48918efc0 efeeec23855e4659 2f23b1dcff8841e8 c3abd357eb574eb6 76881ea91e0040bd e3b0c44298fc1c14 36cd3f2bb454f575 ad332335cfaa348c a58865feac87f52b 052081156966d443 5654f9fffd4a2a7a bd0710fd0315ecbb e4d8cec4158bb770 f1b901847390b0ed e3b0c44298fc1c14 966a8946115b377a 5b59b2f749ffabac 9bf96d3c4c385073 43d8bbb16372109c 5226bbb3f5f9e13d add6d744d3ac0c02 3dafca094d79548b 21a3cd5236dfd642 79e12b3b50117933 9cb81024d1184666 f1e7b346d65f35c5 e3b0c44298fc1c14 60ab6be4219694a0 3a1c5dcc5281208a e256f3fb8239bf8c 10d8918d097bebb5 ff85c33a894fab39 10f274c7d25257d2 6216cf539fa87bd8 e3b0c44298fc1c14 7136000e494604c0 aa8d4cf82644ac63 f75f6ee8f0d942eb 1f59b655e6071114 da29957f3e8be475",
6
+ "lines": "2a3d3f1fb26381e9 e3b0c44298fc1c14 ddabff43c0a4efe5 6aa552cc1598dcb7 be186e6b970ab643 fb78540ec32b52f9 e3b0c44298fc1c14 662c42577f74cece e3b0c44298fc1c14 85b7ae55df076ab0 2f6995b0ecd75c8d e3b0c44298fc1c14 5f2235a1b010f82c 56a4406ad70b7f0a ba2cd86d7e76eff5 a7b723b74ee03fc8 e3b0c44298fc1c14 782729a560418c17 36a8e590ff4c085c e3b0c44298fc1c14 9f4e3cc48918efc0 efeeec23855e4659 2f23b1dcff8841e8 c3abd357eb574eb6 76881ea91e0040bd e3b0c44298fc1c14 36cd3f2bb454f575 ad332335cfaa348c a58865feac87f52b 052081156966d443 5654f9fffd4a2a7a bd0710fd0315ecbb e4d8cec4158bb770 f1b901847390b0ed e3b0c44298fc1c14 966a8946115b377a 5b59b2f749ffabac 9bf96d3c4c385073 43d8bbb16372109c 5226bbb3f5f9e13d add6d744d3ac0c02 3dafca094d79548b 21a3cd5236dfd642 79e12b3b50117933 9cb81024d1184666 f1e7b346d65f35c5 e3b0c44298fc1c14 60ab6be4219694a0 3a1c5dcc5281208a e256f3fb8239bf8c 10d8918d097bebb5 ff85c33a894fab39 10f274c7d25257d2 6216cf539fa87bd8 e3b0c44298fc1c14 7136000e494604c0 aa8d4cf82644ac63 f75f6ee8f0d942eb 1f59b655e6071114 da29957f3e8be475",
7
7
  "load": "always",
8
8
  "path": "CLAUDE.md",
9
- "raw_sha256": "c21de91b03da043818a3d8a83418a2e4ce449e58e1e6a5906e7d7c2212ddfca5",
10
- "seen_sha256": "c21de91b03da043818a3d8a83418a2e4ce449e58e1e6a5906e7d7c2212ddfca5",
9
+ "raw_sha256": "d989296d3afb40ba35cdf955a9dcc549df351fa4a5b0ee4585475e94e86e774c",
10
+ "seen_sha256": "d989296d3afb40ba35cdf955a9dcc549df351fa4a5b0ee4585475e94e86e774c",
11
11
  "via": []
12
12
  }
13
13
  ],
14
14
  "copilot-cli": [
15
15
  {
16
16
  "conditions": [],
17
- "lines": "2a3d3f1fb26381e9 e3b0c44298fc1c14 ddabff43c0a4efe5 6aa552cc1598dcb7 be186e6b970ab643 fb78540ec32b52f9 e3b0c44298fc1c14 d393a517d5cbec9f e3b0c44298fc1c14 85b7ae55df076ab0 2f6995b0ecd75c8d e3b0c44298fc1c14 5f2235a1b010f82c 56a4406ad70b7f0a ba2cd86d7e76eff5 a7b723b74ee03fc8 e3b0c44298fc1c14 782729a560418c17 36a8e590ff4c085c e3b0c44298fc1c14 9f4e3cc48918efc0 efeeec23855e4659 2f23b1dcff8841e8 c3abd357eb574eb6 76881ea91e0040bd e3b0c44298fc1c14 36cd3f2bb454f575 ad332335cfaa348c a58865feac87f52b 052081156966d443 5654f9fffd4a2a7a bd0710fd0315ecbb e4d8cec4158bb770 f1b901847390b0ed e3b0c44298fc1c14 966a8946115b377a 5b59b2f749ffabac 9bf96d3c4c385073 43d8bbb16372109c 5226bbb3f5f9e13d add6d744d3ac0c02 3dafca094d79548b 21a3cd5236dfd642 79e12b3b50117933 9cb81024d1184666 f1e7b346d65f35c5 e3b0c44298fc1c14 60ab6be4219694a0 3a1c5dcc5281208a e256f3fb8239bf8c 10d8918d097bebb5 ff85c33a894fab39 10f274c7d25257d2 6216cf539fa87bd8 e3b0c44298fc1c14 7136000e494604c0 aa8d4cf82644ac63 f75f6ee8f0d942eb 1f59b655e6071114 da29957f3e8be475",
17
+ "lines": "2a3d3f1fb26381e9 e3b0c44298fc1c14 ddabff43c0a4efe5 6aa552cc1598dcb7 be186e6b970ab643 fb78540ec32b52f9 e3b0c44298fc1c14 662c42577f74cece e3b0c44298fc1c14 85b7ae55df076ab0 2f6995b0ecd75c8d e3b0c44298fc1c14 5f2235a1b010f82c 56a4406ad70b7f0a ba2cd86d7e76eff5 a7b723b74ee03fc8 e3b0c44298fc1c14 782729a560418c17 36a8e590ff4c085c e3b0c44298fc1c14 9f4e3cc48918efc0 efeeec23855e4659 2f23b1dcff8841e8 c3abd357eb574eb6 76881ea91e0040bd e3b0c44298fc1c14 36cd3f2bb454f575 ad332335cfaa348c a58865feac87f52b 052081156966d443 5654f9fffd4a2a7a bd0710fd0315ecbb e4d8cec4158bb770 f1b901847390b0ed e3b0c44298fc1c14 966a8946115b377a 5b59b2f749ffabac 9bf96d3c4c385073 43d8bbb16372109c 5226bbb3f5f9e13d add6d744d3ac0c02 3dafca094d79548b 21a3cd5236dfd642 79e12b3b50117933 9cb81024d1184666 f1e7b346d65f35c5 e3b0c44298fc1c14 60ab6be4219694a0 3a1c5dcc5281208a e256f3fb8239bf8c 10d8918d097bebb5 ff85c33a894fab39 10f274c7d25257d2 6216cf539fa87bd8 e3b0c44298fc1c14 7136000e494604c0 aa8d4cf82644ac63 f75f6ee8f0d942eb 1f59b655e6071114 da29957f3e8be475",
18
18
  "load": "always",
19
19
  "path": "CLAUDE.md",
20
- "raw_sha256": "c21de91b03da043818a3d8a83418a2e4ce449e58e1e6a5906e7d7c2212ddfca5",
21
- "seen_sha256": "c21de91b03da043818a3d8a83418a2e4ce449e58e1e6a5906e7d7c2212ddfca5",
20
+ "raw_sha256": "d989296d3afb40ba35cdf955a9dcc549df351fa4a5b0ee4585475e94e86e774c",
21
+ "seen_sha256": "d989296d3afb40ba35cdf955a9dcc549df351fa4a5b0ee4585475e94e86e774c",
22
22
  "via": []
23
23
  }
24
24
  ],
@@ -26,6 +26,6 @@
26
26
  "generic": []
27
27
  },
28
28
  "configs": [],
29
- "generator": "ghostrules 0.2.1",
29
+ "generator": "ghostrules 0.4.0",
30
30
  "lock_version": 1
31
31
  }
@@ -7,4 +7,6 @@ exclude = [
7
7
  ".mypy_cache/**",
8
8
  ".ruff_cache/**",
9
9
  ".pytest_cache/**",
10
+ "corpus/.cache/**", # API responses and clones are other people's text
11
+ "corpus/results/**",
10
12
  ]
@@ -0,0 +1,10 @@
1
+ # Keeps the commit-pinned actions in .github/workflows and action.yml up to date: each update is a
2
+ # pull request that changes the SHA and its version comment.
3
+ version: 2
4
+ updates:
5
+ - package-ecosystem: github-actions
6
+ directory: /
7
+ schedule:
8
+ interval: weekly
9
+ commit-message:
10
+ prefix: "chore"
@@ -14,8 +14,8 @@ jobs:
14
14
  os: [ubuntu-latest, windows-latest, macos-latest]
15
15
  python-version: ["3.10", "3.11", "3.12", "3.13"]
16
16
  steps:
17
- - uses: actions/checkout@v4
18
- - uses: actions/setup-python@v5
17
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
18
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
19
19
  with:
20
20
  python-version: ${{ matrix.python-version }}
21
21
  - name: Install
@@ -0,0 +1,80 @@
1
+ name: Corpus
2
+
3
+ # Runs ghostrules against the public repositories listed in corpus/repos.toml (the only networked
4
+ # part of the project). Never on pull requests.
5
+ on:
6
+ schedule:
7
+ - cron: "17 4 * * 1"
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ concurrency:
14
+ group: corpus
15
+ cancel-in-progress: false
16
+
17
+ jobs:
18
+ corpus:
19
+ runs-on: ubuntu-latest
20
+ timeout-minutes: 120
21
+ env:
22
+ GH_TOKEN: ${{ github.token }}
23
+ steps:
24
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
25
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
26
+ with:
27
+ python-version: "3.12"
28
+ - name: Install ghostrules from this checkout
29
+ run: pip install -e ".[dev]"
30
+ - name: Scan the regression tier
31
+ run: python corpus/run.py --tier regression
32
+ - name: Gate against labels.toml
33
+ run: python corpus/check.py
34
+ - name: Aggregate files (badge and summary, counts only)
35
+ if: always() && hashFiles('corpus/results/latest-summary.json') != ''
36
+ run: python corpus/badge.py --out corpus-public
37
+ - name: Upload results
38
+ if: always()
39
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
40
+ with:
41
+ name: corpus-results
42
+ path: |
43
+ corpus/results
44
+ corpus-public
45
+ retention-days: 30
46
+ if-no-files-found: ignore
47
+
48
+ publish:
49
+ # Only the default branch publishes; the badge reads corpus/badge.json from the orphan
50
+ # branch "badges" (gh-pages is not served: Pages is deployed from Actions by pages.yml).
51
+ needs: corpus
52
+ if: always() && needs.corpus.result != 'skipped' && github.ref == 'refs/heads/main'
53
+ runs-on: ubuntu-latest
54
+ permissions:
55
+ contents: write
56
+ steps:
57
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
58
+ with:
59
+ name: corpus-results
60
+ path: artifact
61
+ - name: Publish to the badges branch
62
+ env:
63
+ GH_TOKEN: ${{ github.token }}
64
+ REPO: ${{ github.repository }}
65
+ run: |
66
+ set -euo pipefail
67
+ test -f artifact/corpus-public/badge.json
68
+ git clone --quiet --depth 1 --branch badges \
69
+ "https://x-access-token:${GH_TOKEN}@github.com/${REPO}.git" site \
70
+ || { mkdir site && git -C site init --quiet -b badges \
71
+ && git -C site remote add origin \
72
+ "https://x-access-token:${GH_TOKEN}@github.com/${REPO}.git"; }
73
+ mkdir -p site/corpus
74
+ cp artifact/corpus-public/badge.json artifact/corpus-public/summary.json site/corpus/
75
+ cd site
76
+ git config user.name "github-actions[bot]"
77
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
78
+ git add corpus
79
+ git diff --cached --quiet || git commit --quiet -m "corpus: weekly summary"
80
+ git push origin badges
@@ -0,0 +1,48 @@
1
+ name: Playground
2
+
3
+ # Builds the browser playground (web/ plus the wheel of this checkout) and deploys it to GitHub Pages.
4
+ on:
5
+ push:
6
+ tags: ["v*"]
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: pages
14
+ cancel-in-progress: false
15
+
16
+ jobs:
17
+ build:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
21
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
22
+ with:
23
+ python-version: "3.12"
24
+ - name: Install
25
+ run: pip install -e ".[dev,web-test]"
26
+ - name: Build the site
27
+ run: python scripts/build_site.py _site
28
+ - name: Playwright smoke test on the built site
29
+ run: |
30
+ playwright install --with-deps chromium
31
+ pytest -q tests/web
32
+ - uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5
33
+ - uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3
34
+ with:
35
+ path: _site
36
+
37
+ deploy:
38
+ needs: build
39
+ runs-on: ubuntu-latest
40
+ permissions:
41
+ pages: write
42
+ id-token: write
43
+ environment:
44
+ name: github-pages
45
+ url: ${{ steps.deployment.outputs.page_url }}
46
+ steps:
47
+ - id: deployment
48
+ uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4
@@ -14,9 +14,9 @@ jobs:
14
14
  build:
15
15
  runs-on: ubuntu-latest
16
16
  steps:
17
- - uses: actions/checkout@v4
17
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
18
18
 
19
- - uses: actions/setup-python@v5
19
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
20
20
  with:
21
21
  python-version: "3.12"
22
22
 
@@ -41,7 +41,7 @@ jobs:
41
41
  python -m pip install --disable-pip-version-check --quiet build
42
42
  python -m build
43
43
 
44
- - uses: actions/upload-artifact@v4
44
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
45
45
  with:
46
46
  name: dist
47
47
  path: |
@@ -55,10 +55,10 @@ jobs:
55
55
  permissions:
56
56
  id-token: write # Trusted Publishing
57
57
  steps:
58
- - uses: actions/download-artifact@v4
58
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
59
59
  with:
60
60
  name: dist
61
- - uses: pypa/gh-action-pypi-publish@release/v1
61
+ - uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # release/v1
62
62
 
63
63
  github-release:
64
64
  needs: publish-pypi
@@ -66,7 +66,7 @@ jobs:
66
66
  permissions:
67
67
  contents: write
68
68
  steps:
69
- - uses: actions/download-artifact@v4
69
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
70
70
  with:
71
71
  name: dist
72
72
  - name: Create the GitHub release
@@ -75,3 +75,24 @@ jobs:
75
75
  TAG: ${{ github.ref_name }}
76
76
  REPO: ${{ github.repository }}
77
77
  run: gh release create "$TAG" dist/* --repo "$REPO" --title "$TAG" --notes-file release-notes.md
78
+
79
+ move-major-tag:
80
+ # Users pin BardLaudian/ghostrules@v0 (or an exact tag). Only a stable x.y.z release moves it.
81
+ needs: github-release
82
+ runs-on: ubuntu-latest
83
+ permissions:
84
+ contents: write
85
+ steps:
86
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
87
+ - name: Move the v0 tag to this release
88
+ env:
89
+ TAG: ${{ github.ref_name }}
90
+ run: |
91
+ set -euo pipefail
92
+ if ! [[ "$TAG" =~ ^v0\.[0-9]+\.[0-9]+$ ]]; then
93
+ echo "$TAG is not a stable v0.x.y release: the v0 tag stays where it is"
94
+ exit 0
95
+ fi
96
+ git tag -f v0 "$TAG"
97
+ git push --force origin v0
98
+
@@ -13,7 +13,7 @@ jobs:
13
13
  action:
14
14
  runs-on: ubuntu-latest
15
15
  steps:
16
- - uses: actions/checkout@v4
16
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
17
17
 
18
18
  - name: Poisoned demo with fail-on none (must pass, must report findings)
19
19
  id: poisoned
@@ -75,7 +75,7 @@ jobs:
75
75
  import-chain:
76
76
  runs-on: ubuntu-latest
77
77
  steps:
78
- - uses: actions/checkout@v4
78
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
79
79
 
80
80
  - name: Import-chain demo, following imports (default)
81
81
  uses: ./
@@ -125,6 +125,9 @@ jobs:
125
125
  uses: ./
126
126
  with:
127
127
  path: ${{ runner.temp }}/acme/base
128
+ # not a git repository: scanned with its own settings
129
+ trust-repo-config: "true"
130
+ inline-suppressions: all
128
131
  fail-on: none
129
132
  lock-check: "true"
130
133
  upload-sarif: "false"
@@ -140,6 +143,9 @@ jobs:
140
143
  continue-on-error: true
141
144
  with:
142
145
  path: ${{ runner.temp }}/acme/pr
146
+ # not a git repository: scanned with its own settings
147
+ trust-repo-config: "true"
148
+ inline-suppressions: all
143
149
  fail-on: none
144
150
  lock-check: "true"
145
151
  upload-sarif: "false"
@@ -0,0 +1,23 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .venv/
5
+ venv/
6
+ build/
7
+ dist/
8
+ .pytest_cache/
9
+ .mypy_cache/
10
+ .ruff_cache/
11
+ .coverage
12
+ htmlcov/
13
+ *.ghostrules.bak
14
+ ghostrules.sarif
15
+
16
+ # corpus tooling
17
+ corpus/.cache/
18
+ corpus/results/*
19
+ !corpus/results/latest-summary.json
20
+ _site/
21
+
22
+ # benchmark: findings of third-party repositories
23
+ bench/.cache/
@@ -0,0 +1,314 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [0.4.0] - 2026-10-29
9
+
10
+ Remediation release, from an independent review of 0.3.0 ([plan](docs/design/v0.4/REMEDIATION.md)).
11
+ The scanned change can no longer switch the scanner off, the lock cannot be re-blessed by a pull
12
+ request, visible prose no longer drowns the check, claims are corrected and measured, and the scanner
13
+ reads more of what agents run. On a new benchmark (101 attack cases and a 100-repository held-out
14
+ set, `bench/`): 87 of 101 attacks reported, 50 fail the default check; precision for a user on the
15
+ held-out set is 19% (4 of 21 findings, labels provisional). Both numbers come with their misses.
16
+
17
+ **Upgrading: breaking changes.** (1) On pull requests the Action reads the config, the ignore comments,
18
+ the baseline and the lock from the base commit; a path outside a git repository needs
19
+ `trust-repo-config: "true"` and `inline-suppressions: all`. (2) Plain visible prose is `low` or `info`
20
+ by default, so a visible `curl | sh` no longer fails `--fail-on high`; `--strict` (config
21
+ `profile = "strict"`, Action `profile: strict`) restores the 0.3 severities. (3) The label `wontfix` is
22
+ now `benign-context` in the corpus tools. (4) The Action installs from a hash-pinned requirements file.
23
+
24
+ ### Added
25
+
26
+ - **Scripts that hooks and skills run** (W5.1, W5.2): hook commands of Claude Code, Gemini, Cursor and
27
+ Codex and scripts named in `SKILL.md` are scanned as code, with the chain that reaches them: GR110
28
+ (sends the environment or a secret), GR111 (reads credential files), GR112 (downloads and runs code),
29
+ GR113 (hides what it runs).
30
+ - **The context engine as a library** (W8): `ghostrules.context.resolve()` and `schema()`, a JSON
31
+ schema for the result validated in the tests, and a README section on alternatives.
32
+ - **Settings a pull request cannot rewrite** (W2 of docs/design/v0.4/REMEDIATION.md): `scan
33
+ --config-from-ref REF`, `--trusted-config FILE`, `--no-inline-suppressions` and
34
+ `--suppressions-from-ref REF`. They close two ways a change could silence the scanner for its own
35
+ payload: a `ghostrules-ignore` comment on the malicious line and `exclude` in `.ghostrules.toml`.
36
+ - **Codex and Gemini CLI** (W5.3): `context` models for both (`--agent codex`, `--agent gemini-cli`;
37
+ opt-in through `agents`, so existing lockfiles do not change); `AGENTS.override.md`,
38
+ `.codex/config.toml` and `.codex/hooks.json` are scanned; GR107 reports Codex
39
+ `sandbox_mode = "danger-full-access"` and `approval_policy = "never"` and Gemini's bare
40
+ `run_shell_command` allow and `enablePermanentToolApproval`.
41
+ - **Files that prose points to** (W5.4): `Read X and follow every step` and `Run scripts/x.sh` make the
42
+ file part of the scan, with the chain and the tag `reached-via-reference` (GR026, a tag, not a
43
+ detector). The `context` tree does not show a `referenced` state yet.
44
+ - **Instructions split across two sentences** (W5.5): GR013 reports a secret in one sentence and a send
45
+ to a URL in the next, with a new `confidence: medium` field on the finding.
46
+ - **A benchmark you can check** (W6): `bench/` has 81 defanged attack cases written from public
47
+ sources (recall per technique and per rule, misses listed, four cases from the independent review as
48
+ known misses) and the 100-repository held-out set run once, with precision for a user per rule. The
49
+ README now shows these numbers instead of the corpus claims. Labels `wontfix` are now
50
+ `benign-context`.
51
+ - **Supply-chain hygiene** (W7): every `uses:` in the Action and the workflows is pinned to a full
52
+ commit SHA (Dependabot keeps them current); the Action installs its dependencies and the build
53
+ backend from `action-requirements.txt`, hash-pinned, with `--require-hashes --no-deps
54
+ --no-build-isolation`; the release workflow moves a `v0` tag to each stable `v0.x.y` release.
55
+ - **Fewer false positives from the independent review** (W4): installers of the project's own
56
+ GitHub organisation and homepage are known installers (read from the base ref when the scan has
57
+ one); Azure CLI, Flox, golangci-lint, Foundry, Flux and Linkerd are known installers; "do not tell
58
+ the user they …" is not concealment.
59
+ - **`ghostrules baseline` and `scan --baseline / --no-baseline / --baseline-from-ref`**: record
60
+ today's findings as fingerprints (no line numbers, no snippets) and fail only on new ones. Hidden
61
+ text is never baselined. The Action reads the baseline at the base commit on pull requests, and
62
+ editing it is reported by GR030.
63
+ - **Breaking: severity by visibility.** Plain visible prose in an agent file is now `low` (an
64
+ instruction) or `info` (a description or quotation) for GR010 to GR014 and GR016; text in an HTML
65
+ comment, decoded hidden text, files reached only through an import, GR015 and every configuration
66
+ rule keep their severity. A visible `curl | sh` or "send `.env` to a URL" no longer fails the
67
+ default check (`--fail-on high`). `--strict`, `profile = "strict"` in the config and the Action's
68
+ `profile: strict` restore the 0.3 behaviour.
69
+ - **`lock --check --base REF`** (W3): compares with the lock and the config at `REF`, so a pull
70
+ request that edits what the agents read and regenerates `.ghostrules.lock` still fails. Exit 2 when
71
+ the ref or its lock does not exist. The idea is cairnlock's `verify --base`.
72
+ - **Breaking: the Action's lock check uses the lock at the base on pull requests**, and a new
73
+ `approve-label` input lets a maintainer approve a legitimate change by applying a label; only the
74
+ event that applies it approves (new commits void it), and the summary names who and when. Output
75
+ `lock-approved`. `trust-repo-config: "true"` restores the working-tree lock.
76
+ - **Inline ignores no longer hide text a reviewer cannot see** (W2): a finding inside an HTML
77
+ comment is never suppressed, and no ignore counts inside a file that an agent reaches only
78
+ through an import (the report says how many were not honoured). Decoded hidden text, GR001 and
79
+ GR002 were already never suppressed. An ignore on a visible line works as before.
80
+ - **GR030, scanner configuration changed** (high): with a base ref, the change adds or edits
81
+ `.ghostrules.toml`, `[tool.ghostrules]`, the lockfile or a `ghostrules-ignore` comment. Reported
82
+ even when legitimate, never suppressible inline, and the change cannot disable it. A new `change`
83
+ scope of rules compares the scanned tree with the base.
84
+ - **Breaking: the Action reads settings from the base commit on pull requests.** On
85
+ `pull_request` and `pull_request_target` events it passes `--config-from-ref` and
86
+ `--suppressions-from-ref` with the base SHA, fetching that commit if the checkout is shallow, and
87
+ fails with exit code 2 when it cannot read it. New inputs: `config`, `trust-repo-config` (default
88
+ `false`) and `inline-suppressions` (`base`, `off` or `all`; default `base`). Workflows that scan a
89
+ path outside a git repository on a pull request need `trust-repo-config: "true"` and
90
+ `inline-suppressions: all`. Other events behave as before.
91
+
92
+ ### Changed
93
+
94
+ - **Corrected claims** (W1 of [docs/design/v0.4/REMEDIATION.md](docs/design/v0.4/REMEDIATION.md)).
95
+ The 0.2 statement that no other tool follows `@path` imports was wrong (cfgaudit does, since
96
+ 2026-10-24): the prior-art notes are corrected and dated, and ghostrules no longer claims to be
97
+ the first or the only one. The README says "scheduled weekly; last run" instead of "every week".
98
+ The study report is now "A snapshot (2026-10-28)", puts hygiene statistics apart from security
99
+ indicators, shows a numerator and denominator next to each percentage, explains the MCP
100
+ denominator (a lower bound, so the share is an upper bound), counts benign-context matches as noise
101
+ in a per-rule precision table, and has a "Threats to validity" section. The 0.3.0 notes below are
102
+ left as published.
103
+ - README restructured as a landing page; option tables, configuration, supported files, FAQ and limits
104
+ moved to `docs/USAGE.md`, and the rules table to `docs/RULES.md`.
105
+ - SARIF `helpUri` points to `docs/RULES.md#grNNN` (the rules table moved there).
106
+
107
+ ### Known limits
108
+
109
+ - Paraphrases, languages other than English and Spanish (GR013 has no Spanish patterns), a few read
110
+ verbs (`Open ~/.npmrc`), `exec(urlopen())`, endpoint overrides in settings and the descriptions an MCP
111
+ server serves are not caught: 14 of the 101 attack cases (`bench/RESULTS.md`).
112
+ - Only 4 of the review's 18 evasion cases are in the attack set; the rest were not available.
113
+ - The held-out labels are provisional (given by the assistant that ran the benchmark, not reviewed by a
114
+ person) and 21 findings are too few for a per-rule precision estimate.
115
+ - The `context` tree does not show files reached by a prose reference, and the lock does not record
116
+ them; Codex and Gemini CLI models are opt-in.
117
+ - The MCP share in the study is an upper bound (its denominator is a lower bound).
118
+
119
+ ## [0.3.0] - 2026-10-28
120
+
121
+ Measurement release. ghostrules now runs against real repositories every week, a browser playground
122
+ runs the real scanner without installing anything, and the first full study of popular repositories
123
+ drove a round of precision fixes. On the 300-repository regression tier 0.2.1 reported 323 findings
124
+ (84 critical, 156 high); 0.3.0 reports 212 (0 critical, 53 high), every critical and high finding
125
+ reviewed. On the 1,283-repository study tier the first run reported 1,072 findings (13 critical, 296
126
+ high); after the fixes 945 (12 critical, 252 high), all of medium and above triaged.
127
+
128
+ ### Added
129
+ - **Playground** (`web/`, `.github/workflows/pages.yml`): a static page that runs the real scanner in
130
+ the browser with Pyodide. Paste a file, drop a folder (agent files and what they import, up to
131
+ 5 MB) or name a public GitHub repo (the only tab that uses the network). Shows what you see versus
132
+ what the agent reads, the context tree per agent and downloadable JSON, Markdown and SARIF reports.
133
+ Playwright smoke test; deployed to GitHub Pages on release tags.
134
+ - **Corpus tooling** (`corpus/`, outside the package and the wheel): `discover.py`, `run.py`,
135
+ `check.py`, `triage.py`, `badge.py`, `filestats.py`, a weekly `corpus.yml` workflow and an endpoint
136
+ badge in the README. Findings are labelled by fingerprint in `corpus/labels.toml`; labels never
137
+ name a repository for a reported finding.
138
+ - **Study tooling** (`study/`): per-repository features, aggregate CSVs, SVG charts in light and dark,
139
+ the triage classes and `study/report.md`, generated from the CSVs.
140
+ - `ghostrules.playground`, `ghostrules.reveal_data` and `ghostrules.reporters.context_data`: the core
141
+ (scanner, rules, context engine, JSON, SARIF and Markdown reporters) now imports without `typer`
142
+ and `rich`; the terminal output is unchanged.
143
+ - `action.yml` is named `ghostrules scan` and its description fits the Marketplace limit (125
144
+ characters).
145
+
146
+ ### Fixed
147
+ - GR003: a lone U+200B between two letters of Khmer, Thai, Lao or Myanmar text is that script's word
148
+ separator and is ignored.
149
+ - GR005: a hidden comment is `medium` when it carries an instruction cue, `low` when it only mentions
150
+ agents, `high` unchanged for injection matches.
151
+ - GR010: `override system|safety` needs a following noun, and defensive text that quotes the phrase
152
+ is `low`.
153
+ - GR011: `without asking the user` is no longer concealment; a prohibition earlier in the clause, a
154
+ safety claim ("does not silently install"), a description in the third person ("silently runs") and
155
+ a modal before it are not reported.
156
+ - GR012: naming the `curl | sh` pattern without a target is `low`; a `curl` in prose no longer joins
157
+ the next code block; `| bash script.sh` is not a data pipe into the shell.
158
+ - GR013: needs a verb, a secret and a URL in the same clause; prohibitions, loopback URLs, `POST`
159
+ and `.post(`, "send the user to" and "send X only to the fixed origin" are not exfiltration.
160
+ - GR014: the verb must govern the path across no paragraph break, clause connector (`before`,
161
+ `after`, `when`), passive or noun use; `### Output` is a heading; `.env.default` and copying a
162
+ dotenv file are not reads.
163
+ - GR015: runs inside URLs, Subresource Integrity digests and low-entropy hex (`AAAA…`) are skipped.
164
+ - GR016: a prohibition ("Avoid `--yolo`"), a table row and a list item that documents a flag are not
165
+ an instruction.
166
+ - A bare `@/`, `@~/`, `@./` or `@../` is a path prefix, not an import.
167
+
168
+ ### Known limits
169
+ - Splitting an exfiltration instruction across two sentences avoids the GR013 prose match, and a
170
+ concealment right after an unrelated prohibition in the same clause is not reported.
171
+
172
+ ## [0.2.1] - 2026-10-28
173
+
174
+ Precision release. A scan of 12 popular public repositories with 0.2.0 found no critical issue,
175
+ but every `high` finding was a false positive, and `context` was wrong for the most common real
176
+ setup. On those repositories 0.2.0 reported 9 high, 18 medium and 8 low findings; 0.2.1 reports
177
+ 2 medium and 2 low, with no high, no critical and no GR025.
178
+
179
+ ### Added
180
+ - `ghostrules context --format json` entries carry `alias_of` (and `link_problem`) when a symlink is
181
+ involved; lock entries carry `link` for an alias. Both keys are omitted otherwise.
182
+ - `ghostrules.rules.directive.classify`: the helper that tells directive, descriptive and example
183
+ text apart (used by GR011, GR014 and GR016).
184
+
185
+ ### Fixed
186
+ - A symbolic link whose final target is a regular file inside the repository is now an **alias**:
187
+ `CLAUDE.md -> AGENTS.md` (the setup Claude Code documents) is loaded under the link's name,
188
+ `context` shows `CLAUDE.md → AGENTS.md (symlink)` and the `AGENTS.md` entry as already read, the
189
+ content is scanned once (findings say `via CLAUDE.md (symlink)`), and `lock` records the link and
190
+ its target. Chains of up to 8 links and in-repository directory links work the same way. Nothing
191
+ is opened before the resolved path is known to be inside the repository.
192
+ GR025 now fires only for links that leave the repository (`high`) or are broken, cyclic or too
193
+ long (`low`), instead of one `medium` per link, and adds an `info` note for a link checked out as
194
+ a text file (Windows with `core.symlinks=false`).
195
+ - GR022 no longer reports npm scopes and mentions (`@n8n/design-system`, `@cline/llms`, `@types/node`)
196
+ as imports that do not load. It reports a token only if it has a file extension, starts with `./`,
197
+ `../`, `~/` or `/`, or its first directory exists next to the importing file.
198
+ - GR011, GR014 and GR016 tell instructions from descriptions and examples. A match in prose that
199
+ describes something ("The scripts read `~/.npmrc`", "The harness runs Claude with
200
+ `bypassPermissions`") is at most `medium`; in a fenced block, in quotes or after "e.g.", "such
201
+ as", "a skill that ..." it is at most `low`; imperative text and decoded hidden text keep their
202
+ severity. A lowered finding says why.
203
+ - GR011: "do not tell the user to/which/what/how ..." is no longer concealment.
204
+ - GR014: the verb must govern the path (same clause, six words at most) and template files
205
+ (`.env.example`, `*.example`, `.env.ai-surfaces.example`) never fire.
206
+ - GR012: `curl ... | python -c`, `| python -m`, `| python script.py`, `| sh -c '...'` use stdin as
207
+ data and are no longer reported; `| python`, `| python -` and `| sh` still are. The Claude Code
208
+ installer (`https://claude.ai/install.sh`) is a known installer. GR105 and GR107 share these
209
+ patterns and follow.
210
+
211
+ ### Changed
212
+ - README: the new tagline is the only one (the old one opens the first paragraph), the import-chain
213
+ GIF comes first and the hidden-Unicode GIF sits further down, both by absolute URL.
214
+ - The original `SPEC.md`, `PLAN.md` and the per-version design documents moved to `docs/design/`
215
+ (design history, not kept up to date). `RULES.md`, `AGENT_MODELS.md` and `DECISIONS.md` stay in
216
+ `docs/`.
217
+
218
+ ## [0.2.0] - 2026-10-28
219
+
220
+ Know exactly what your agent reads: `ghostrules` now models how each agent loads its instructions,
221
+ scans exactly that, shows it, and pins it.
222
+
223
+ ### Added
224
+ - GitHub Action inputs `follow-imports` (default `true`) and `lock-check` (default `false`). With
225
+ `lock-check` the action runs `ghostrules lock --check`, puts the differences in the job summary
226
+ under "What your agents read changed in this PR" and fails the job if there are any; new output
227
+ `lock-exit-code`.
228
+ - Config keys `follow_imports`, `agents` and `lockfile`.
229
+ - `python scripts/make_demo.py --lock-scenario DEST` and the tapes `demo/imports.tape` and
230
+ `demo/lock.tape` for the 0.2 GIFs.
231
+ - `ghostrules lock`: writes `.ghostrules.lock`, a deterministic record (sorted keys, no timestamps,
232
+ CRLF-normalised hashes) of every file in each modelled agent's context, how it is reached, and
233
+ the text the agent actually receives, plus a hash of every MCP and agent settings file.
234
+ `lock --check` recomputes it and shows what changed (added, changed, removed, and changes that
235
+ only touch text an agent strips), with invisible characters revealed; exit 0 up to date, 1
236
+ changed, 2 error. `--format text|markdown|json`, `--update`, `--lockfile`; config key `lockfile`.
237
+ - `ghostrules context [TARGET]`: shows what an agent reads when it works on a file (the files it
238
+ loads at session start, the rules its `paths`/`globs` select, the directories that load on
239
+ demand, the imports it follows and the files it skips, with the reason) and scans exactly that.
240
+ Output as a tree, JSON or Markdown; `--agent`, `--cwd`, `--root`, `--show-text`, `--no-scan`,
241
+ `--home`, `--fail-on`.
242
+ - `examples/import-chain-repo`: a CLAUDE.md that looks clean and reaches a hidden payload through two
243
+ imports, plus a `.env` import and one outside the repository.
244
+ - `scan` follows `@path` imports by default: files an instruction file imports are scanned as
245
+ instructions, and their findings carry the import chain (`via`), the agents that load them and the
246
+ tag `reached-via-import`. `--no-follow-imports` (or `follow_imports = false`) turns it off.
247
+ - Rules GR020 (external import), GR021 (sensitive file imported), GR022 (import that silently does
248
+ not load), GR023 (import cycle), GR024 (tag for payloads reached through an import) and GR025
249
+ (symlinked instruction source).
250
+ - The files each modelled agent loads (including `.claude/rules/**`) are scanned even when the
251
+ discovery globs do not list them. New config keys `follow_imports` and `agents`.
252
+ - JSON findings gain optional `via`, `agents` and `tags`; SARIF results gain `relatedLocations` for
253
+ the chain and `properties.agents`/`tags`; the table and Markdown reports show the chain.
254
+
255
+ - `docs/AGENT_MODELS.md`: how each agent loads its instructions, with the documentation it is based on
256
+ and what is still unverified; `CONTRIBUTING.md` explains how to add a model.
257
+ - `ghostrules` locks its own `CLAUDE.md` (`.ghostrules.lock`), checked in CI.
258
+
259
+ ### Changed
260
+ - GR005 is agent-aware: it says which agents see a hidden comment. Claude Code strips block-level
261
+ comments from CLAUDE.md files, so the finding is info when no configured agent sees the comment.
262
+
263
+ ## [0.1.1] - 2026-10-27
264
+
265
+ ### Changed
266
+ - GR012 (remote code execution pattern) now sets its severity from context instead of reporting
267
+ every `curl ... | sh` as critical. A well-known installer in a code block is low, in prose
268
+ medium; an unknown domain is high in a code block and critical in prose. Plain `http://`, IP
269
+ literals, non-default ports, collector domains, opaque payloads (`base64 -d | sh`,
270
+ `powershell -enc`) and text hidden by invisible characters stay critical. This stops the default
271
+ `--fail-on high` from failing on real repositories that document `uv` or `rustup`.
272
+ GR105 and GR107 (MCP server commands and hooks) are unchanged.
273
+
274
+ ### Added
275
+ - Built-in list of well-known installers (uv/ruff, rustup, Bun, Deno, pnpm, Poetry, Homebrew, nvm,
276
+ SDKMAN, Docker, Ollama, Volta), matched on the exact host and optional path prefix, and
277
+ `ghostrules rules --installers` to print it.
278
+ - `trust_known_installers` option (default `true`); `false` restores the 0.1.0 behaviour.
279
+ - Inline code span awareness for GR012 (`ScanTarget.code_span_at`).
280
+
281
+ ## [0.1.0] - 2026-10-27
282
+
283
+ First release.
284
+
285
+ ### Added
286
+ - Scanner for the files AI coding agents read and obey (`AGENTS.md`, `CLAUDE.md`, `.cursorrules`,
287
+ Copilot instructions, skills, MCP configs, agent settings and more), with `--home` for
288
+ user-level configs and `--all-files` for hidden Unicode anywhere in a tree.
289
+ - 21 rules. Hidden content: Unicode tag characters (GR001), bidirectional controls (GR002),
290
+ zero-width characters (GR003), variation-selector steganography (GR004), hidden HTML comments
291
+ (GR005), mixed-script homoglyphs (GR006). Malicious instructions, English and Spanish: instruction
292
+ override (GR010), concealment (GR011), remote code execution (GR012), data exfiltration (GR013),
293
+ sensitive file access (GR014), encoded payloads (GR015), safety bypass (GR016). Configuration:
294
+ hardcoded secrets (GR101), unpinned packages (GR102), insecure transport (GR103), broad
295
+ filesystem scope (GR104), shell wrappers (GR105), dangerous Docker options (GR106),
296
+ over-permissive agent settings (GR107), auto-trusted MCP servers (GR108).
297
+ - Hidden text decoded by GR001, GR004 and GR015 is re-scanned by GR010-GR016 and reported with
298
+ one more level of severity.
299
+ - CLI: `scan` (the default command), `reveal`, `clean`, `rules`, `version`. Reports as a table
300
+ grouped by file with the decoded hidden text highlighted, JSON, SARIF 2.1.0 (validated against the
301
+ official schema) and Markdown. Exit codes: 0 clean, 1 findings at or above `--fail-on`, 2 error.
302
+ - Configuration through `.ghostrules.toml` or `[tool.ghostrules]`, and inline `ghostrules-ignore`
303
+ suppressions (never for GR001, GR002 or text found inside hidden characters).
304
+ - GitHub Action (SARIF upload to code scanning, job summary, `fail-on` gate), pre-commit hook, CI
305
+ with a smoke test and a self-scan, and a tag-triggered release workflow using PyPI Trusted
306
+ Publishing.
307
+ - Demo repositories `examples/poisoned-repo` (every rule fires) and `examples/clean-repo` (no
308
+ findings), and `demo/demo.tape` to record the README GIF.
309
+
310
+ ### Security
311
+ - Read-only: nothing found in a scanned file is executed, imported, downloaded or sent anywhere,
312
+ and the tool makes no network requests. Symbolic links are not followed.
313
+ - Secrets are never printed: every finding, warning and error passes through one masking step
314
+ (`ghp_****…a1b2`), and a test fails if a secret appears in any report format.
@@ -5,7 +5,7 @@
5
5
  machine) for **hidden instructions and risky configuration in the files AI coding agents read and
6
6
  obey**: `AGENTS.md`, `CLAUDE.md`, `.cursorrules`, Copilot instructions, skills, MCP configs, etc.
7
7
 
8
- Tagline: *"Find the instructions your AI agent sees but you don't."*
8
+ Tagline: *"Know exactly what your AI agent reads — and approve every change to it."*
9
9
 
10
10
  It is a **defensive** security tool. It only reads files and reports findings. It never executes
11
11
  anything it finds, never makes network requests, and never phones home.