ghostrules 0.3.0__tar.gz → 0.4.1__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 (281) hide show
  1. {ghostrules-0.3.0 → ghostrules-0.4.1}/.ghostrules.lock +7 -7
  2. ghostrules-0.4.1/.github/dependabot.yml +10 -0
  3. {ghostrules-0.3.0 → ghostrules-0.4.1}/.github/workflows/ci.yml +2 -2
  4. {ghostrules-0.3.0 → ghostrules-0.4.1}/.github/workflows/corpus.yml +10 -9
  5. {ghostrules-0.3.0 → ghostrules-0.4.1}/.github/workflows/release.yml +27 -6
  6. {ghostrules-0.3.0 → ghostrules-0.4.1}/.github/workflows/self-test.yml +8 -2
  7. {ghostrules-0.3.0 → ghostrules-0.4.1}/.gitignore +3 -0
  8. {ghostrules-0.3.0 → ghostrules-0.4.1}/CHANGELOG.md +141 -0
  9. {ghostrules-0.3.0 → ghostrules-0.4.1}/CLAUDE.md +1 -1
  10. {ghostrules-0.3.0 → ghostrules-0.4.1}/CONTRIBUTING.md +15 -1
  11. ghostrules-0.4.1/PKG-INFO +245 -0
  12. ghostrules-0.4.1/README.md +185 -0
  13. ghostrules-0.4.1/action-requirements.in +3 -0
  14. ghostrules-0.4.1/action-requirements.txt +60 -0
  15. ghostrules-0.4.1/action.yml +320 -0
  16. ghostrules-0.4.1/assets/banner-dark.png +0 -0
  17. ghostrules-0.4.1/assets/banner-light.png +0 -0
  18. ghostrules-0.4.1/assets/logo.svg +7 -0
  19. ghostrules-0.4.1/assets/social-preview.png +0 -0
  20. ghostrules-0.4.1/bench/.cache-run.log +1 -0
  21. ghostrules-0.4.1/bench/README.md +44 -0
  22. ghostrules-0.4.1/bench/RESULTS.md +103 -0
  23. ghostrules-0.4.1/bench/attacks/context-and-config.toml +246 -0
  24. ghostrules-0.4.1/bench/attacks/prose.toml +463 -0
  25. ghostrules-0.4.1/bench/attacks/sources.toml +42 -0
  26. ghostrules-0.4.1/bench/attacks/unicode.toml +212 -0
  27. ghostrules-0.4.1/bench/attacks/w5.toml +237 -0
  28. ghostrules-0.4.1/bench/heldout-labels.toml +130 -0
  29. ghostrules-0.4.1/bench/heldout-results.json +116 -0
  30. ghostrules-0.4.1/bench/heldout.toml +315 -0
  31. ghostrules-0.4.1/bench/lib.py +220 -0
  32. ghostrules-0.4.1/bench/run.py +357 -0
  33. {ghostrules-0.3.0 → ghostrules-0.4.1}/docs/AGENT_MODELS.md +69 -4
  34. {ghostrules-0.3.0 → ghostrules-0.4.1}/docs/DECISIONS.md +255 -3
  35. {ghostrules-0.3.0 → ghostrules-0.4.1}/docs/RULES.md +127 -2
  36. ghostrules-0.3.0/README.md → ghostrules-0.4.1/docs/USAGE.md +260 -210
  37. ghostrules-0.4.1/docs/design/v0.3/CORPUS.md +82 -0
  38. ghostrules-0.4.1/docs/design/v0.3/PLAN.md +40 -0
  39. ghostrules-0.4.1/docs/design/v0.3/PLAYGROUND.md +53 -0
  40. ghostrules-0.4.1/docs/design/v0.3/STUDY.md +56 -0
  41. ghostrules-0.4.1/docs/design/v0.4/REMEDIATION.md +186 -0
  42. ghostrules-0.4.1/docs/v0.2.1/FIXES.md +116 -0
  43. {ghostrules-0.3.0 → ghostrules-0.4.1}/pyproject.toml +1 -0
  44. ghostrules-0.4.1/release-notes.md +27 -0
  45. {ghostrules-0.3.0 → ghostrules-0.4.1}/scripts/gen_rules_table.py +13 -15
  46. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/__init__.py +1 -1
  47. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/agents/__init__.py +11 -1
  48. ghostrules-0.4.1/src/ghostrules/agents/codex.py +122 -0
  49. ghostrules-0.4.1/src/ghostrules/agents/gemini_cli.py +97 -0
  50. ghostrules-0.4.1/src/ghostrules/baseline.py +70 -0
  51. ghostrules-0.4.1/src/ghostrules/changeset.py +35 -0
  52. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/cli.py +231 -7
  53. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/config.py +13 -3
  54. ghostrules-0.4.1/src/ghostrules/context.py +59 -0
  55. ghostrules-0.4.1/src/ghostrules/firstparty.py +83 -0
  56. ghostrules-0.4.1/src/ghostrules/gitref.py +109 -0
  57. ghostrules-0.4.1/src/ghostrules/ignores.py +36 -0
  58. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/models.py +28 -1
  59. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/playground.py +4 -3
  60. ghostrules-0.4.1/src/ghostrules/reach.py +274 -0
  61. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/reporters/common.py +3 -0
  62. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/reporters/json_.py +1 -0
  63. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/reporters/sarif.py +1 -1
  64. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/rules/__init__.py +11 -1
  65. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/rules/agent_settings.py +54 -0
  66. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/rules/context_rules.py +14 -0
  67. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/rules/directive.py +6 -4
  68. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/rules/injection.py +45 -1
  69. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/rules/known_installers.py +19 -3
  70. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/rules/patterns.py +2 -1
  71. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/rules/registry.py +35 -3
  72. ghostrules-0.4.1/src/ghostrules/rules/scanner_config.py +165 -0
  73. ghostrules-0.4.1/src/ghostrules/rules/scripts.py +362 -0
  74. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/rules/unicode.py +1 -1
  75. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/scanner.py +253 -18
  76. ghostrules-0.4.1/src/ghostrules/schemas/context.schema.json +107 -0
  77. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/targets.py +8 -0
  78. ghostrules-0.4.1/src/ghostrules/visibility.py +85 -0
  79. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/analyze.py +2 -2
  80. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/charts.py +2 -2
  81. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/data/precision_by_rule.csv +1 -1
  82. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/label_classes.py +13 -10
  83. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/labels.toml +249 -249
  84. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/report.md +93 -32
  85. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/report.py +91 -35
  86. ghostrules-0.4.1/tests/pr_helpers.py +121 -0
  87. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_agents_others.py +1 -1
  88. ghostrules-0.4.1/tests/test_baseline.py +125 -0
  89. ghostrules-0.4.1/tests/test_bench.py +197 -0
  90. ghostrules-0.4.1/tests/test_bench_heldout.py +32 -0
  91. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_ci_files.py +420 -14
  92. ghostrules-0.4.1/tests/test_codex_gemini.py +275 -0
  93. ghostrules-0.4.1/tests/test_context_api.py +59 -0
  94. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_corpus_tools.py +50 -2
  95. ghostrules-0.4.1/tests/test_crlf.py +26 -0
  96. ghostrules-0.4.1/tests/test_cross_sentence.py +44 -0
  97. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_directive.py +1 -1
  98. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_docs.py +131 -51
  99. ghostrules-0.4.1/tests/test_gr030.py +205 -0
  100. ghostrules-0.4.1/tests/test_hidden_ignores.py +106 -0
  101. ghostrules-0.4.1/tests/test_hook_scripts.py +289 -0
  102. ghostrules-0.4.1/tests/test_lock_base.py +98 -0
  103. ghostrules-0.4.1/tests/test_noise_fixes.py +174 -0
  104. ghostrules-0.4.1/tests/test_pr_mode.py +207 -0
  105. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_precision_study.py +1 -1
  106. ghostrules-0.4.1/tests/test_referenced_files.py +116 -0
  107. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_reporters.py +1 -1
  108. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_rules_injection.py +4 -3
  109. ghostrules-0.4.1/tests/test_script_own_service.py +211 -0
  110. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_study.py +2 -2
  111. ghostrules-0.4.1/tests/test_visibility.py +152 -0
  112. ghostrules-0.3.0/PKG-INFO +0 -603
  113. ghostrules-0.3.0/action.yml +0 -146
  114. ghostrules-0.3.0/release-notes.md +0 -50
  115. {ghostrules-0.3.0 → ghostrules-0.4.1}/.ghostrules.toml +0 -0
  116. {ghostrules-0.3.0 → ghostrules-0.4.1}/.gitattributes +0 -0
  117. {ghostrules-0.3.0 → ghostrules-0.4.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  118. {ghostrules-0.3.0 → ghostrules-0.4.1}/.github/ISSUE_TEMPLATE/false-positive.yml +0 -0
  119. {ghostrules-0.3.0 → ghostrules-0.4.1}/.github/ISSUE_TEMPLATE/new-rule.yml +0 -0
  120. {ghostrules-0.3.0 → ghostrules-0.4.1}/.github/workflows/pages.yml +0 -0
  121. {ghostrules-0.3.0 → ghostrules-0.4.1}/.pre-commit-hooks.yaml +0 -0
  122. {ghostrules-0.3.0 → ghostrules-0.4.1}/LICENSE +0 -0
  123. {ghostrules-0.3.0 → ghostrules-0.4.1}/SECURITY.md +0 -0
  124. {ghostrules-0.3.0 → ghostrules-0.4.1}/demo/README.md +0 -0
  125. {ghostrules-0.3.0 → ghostrules-0.4.1}/demo/demo.gif +0 -0
  126. {ghostrules-0.3.0 → ghostrules-0.4.1}/demo/demo.tape +0 -0
  127. {ghostrules-0.3.0 → ghostrules-0.4.1}/demo/imports.gif +0 -0
  128. {ghostrules-0.3.0 → ghostrules-0.4.1}/demo/imports.tape +0 -0
  129. {ghostrules-0.3.0 → ghostrules-0.4.1}/demo/lock.tape +0 -0
  130. {ghostrules-0.3.0 → ghostrules-0.4.1}/docs/design/PLAN.md +0 -0
  131. {ghostrules-0.3.0 → ghostrules-0.4.1}/docs/design/SPEC.md +0 -0
  132. {ghostrules-0.3.0 → ghostrules-0.4.1}/docs/design/v0.1.1/GR012-FIX.md +0 -0
  133. {ghostrules-0.3.0 → ghostrules-0.4.1}/docs/design/v0.2/PLAN.md +0 -0
  134. {ghostrules-0.3.0 → ghostrules-0.4.1}/docs/design/v0.2/RULES.md +0 -0
  135. {ghostrules-0.3.0 → ghostrules-0.4.1}/docs/design/v0.2/SPEC.md +0 -0
  136. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/clean-repo/.claude/settings.json +0 -0
  137. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/clean-repo/.mcp.json +0 -0
  138. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/clean-repo/AGENTS.md +0 -0
  139. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/clean-repo/CLAUDE.md +0 -0
  140. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/clean-repo/README.md +0 -0
  141. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/import-chain-repo/.claude/rules/api.md +0 -0
  142. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/import-chain-repo/.env +0 -0
  143. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/import-chain-repo/AGENTS.md +0 -0
  144. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/import-chain-repo/CLAUDE.md +0 -0
  145. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/import-chain-repo/README.md +0 -0
  146. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/import-chain-repo/docs/setup.md +0 -0
  147. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/import-chain-repo/docs/style.md +0 -0
  148. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/import-chain-repo/shared/team-rules.md +0 -0
  149. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/import-chain-repo/src/api/users.ts +0 -0
  150. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/import-chain-repo/src/legacy/CLAUDE.md +0 -0
  151. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/poisoned-repo/.claude/settings.json +0 -0
  152. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/poisoned-repo/.claude/skills/setup/SKILL.md +0 -0
  153. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/poisoned-repo/.cursorrules +0 -0
  154. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/poisoned-repo/.github/copilot-instructions.md +0 -0
  155. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/poisoned-repo/.mcp.json +0 -0
  156. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/poisoned-repo/AGENTS.md +0 -0
  157. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/poisoned-repo/CLAUDE.md +0 -0
  158. {ghostrules-0.3.0 → ghostrules-0.4.1}/examples/poisoned-repo/README.md +0 -0
  159. {ghostrules-0.3.0 → ghostrules-0.4.1}/scripts/build_site.py +0 -0
  160. {ghostrules-0.3.0 → ghostrules-0.4.1}/scripts/changelog_section.py +0 -0
  161. {ghostrules-0.3.0 → ghostrules-0.4.1}/scripts/make_demo.py +0 -0
  162. {ghostrules-0.3.0 → ghostrules-0.4.1}/scripts/make_fixtures.py +0 -0
  163. {ghostrules-0.3.0 → ghostrules-0.4.1}/scripts/set_owner.py +0 -0
  164. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/_compat.py +0 -0
  165. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/agents/base.py +0 -0
  166. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/agents/claude_code.py +0 -0
  167. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/agents/copilot_cli.py +0 -0
  168. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/agents/cursor.py +0 -0
  169. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/agents/generic.py +0 -0
  170. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/agents/repo.py +0 -0
  171. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/clean.py +0 -0
  172. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/context_command.py +0 -0
  173. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/contextscan.py +0 -0
  174. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/globs.py +0 -0
  175. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/imports.py +0 -0
  176. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/jsonloc.py +0 -0
  177. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/lock.py +0 -0
  178. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/markdown_utils.py +0 -0
  179. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/mcp_config.py +0 -0
  180. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/py.typed +0 -0
  181. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/reporters/__init__.py +0 -0
  182. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/reporters/context.py +0 -0
  183. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/reporters/context_data.py +0 -0
  184. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/reporters/lock.py +0 -0
  185. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/reporters/markdown.py +0 -0
  186. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/reporters/table.py +0 -0
  187. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/reveal.py +0 -0
  188. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/reveal_data.py +0 -0
  189. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/rules/helpers.py +0 -0
  190. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/rules/mcp.py +0 -0
  191. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/scancontext.py +0 -0
  192. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/secrets.py +0 -0
  193. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/sensitive.py +0 -0
  194. {ghostrules-0.3.0 → ghostrules-0.4.1}/src/ghostrules/unicode_utils.py +0 -0
  195. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/charts/01-adoption-dark.svg +0 -0
  196. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/charts/01-adoption-light.svg +0 -0
  197. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/charts/02-tools-per-repo-dark.svg +0 -0
  198. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/charts/02-tools-per-repo-light.svg +0 -0
  199. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/charts/03-claude-agents-dark.svg +0 -0
  200. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/charts/03-claude-agents-light.svg +0 -0
  201. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/charts/04-what-agents-read-dark.svg +0 -0
  202. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/charts/04-what-agents-read-light.svg +0 -0
  203. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/charts/05-risk-dark.svg +0 -0
  204. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/charts/05-risk-light.svg +0 -0
  205. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/charts/06-precision-dark.svg +0 -0
  206. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/charts/06-precision-light.svg +0 -0
  207. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/data/adoption_families.csv +0 -0
  208. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/data/claude_agents_relation.csv +0 -0
  209. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/data/conditional_rules.csv +0 -0
  210. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/data/findings_by_rule.csv +0 -0
  211. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/data/headline.json +0 -0
  212. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/data/imports.csv +0 -0
  213. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/data/instruction_file_lines.csv +0 -0
  214. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/data/numbers.csv +0 -0
  215. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/data/precision_runs.csv +0 -0
  216. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/data/risk_indicators.csv +0 -0
  217. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/data/sample.csv +0 -0
  218. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/data/skills_concentration.csv +0 -0
  219. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/data/tools_per_repo.csv +0 -0
  220. {ghostrules-0.3.0 → ghostrules-0.4.1}/study/features.py +0 -0
  221. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/conftest.py +0 -0
  222. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/corpus_fakes.py +0 -0
  223. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/data/sarif-schema-2.1.0.json +0 -0
  224. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr001_flag_forged/AGENTS.md +0 -0
  225. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr001_flag_ok/AGENTS.md +0 -0
  226. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr001_tags/AGENTS.md +0 -0
  227. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr002_bidi/AGENTS.md +0 -0
  228. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr002_rtl_medium/AGENTS.md +0 -0
  229. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr003_bom_midfile/AGENTS.md +0 -0
  230. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr003_bom_ok/AGENTS.md +0 -0
  231. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr003_emoji_zwj_ok/AGENTS.md +0 -0
  232. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr003_indic_ok/AGENTS.md +0 -0
  233. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr003_persian_ok/AGENTS.md +0 -0
  234. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr003_soft_hyphen/AGENTS.md +0 -0
  235. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr003_zw_file_high/AGENTS.md +0 -0
  236. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr003_zw_line_high/AGENTS.md +0 -0
  237. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr003_zw_medium/AGENTS.md +0 -0
  238. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr004_vs_bytes/AGENTS.md +0 -0
  239. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr004_vs_ok/AGENTS.md +0 -0
  240. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr005_benign_ok/CLAUDE.md +0 -0
  241. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr005_comment_imperative/CLAUDE.md +0 -0
  242. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr005_comment_injection/CLAUDE.md +0 -0
  243. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr005_comment_multiline/CLAUDE.md +0 -0
  244. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr005_in_code_block_ok/CLAUDE.md +0 -0
  245. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr005_short_ok/CLAUDE.md +0 -0
  246. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr005_unterminated/CLAUDE.md +0 -0
  247. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr006_ok/AGENTS.md +0 -0
  248. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr006_url/AGENTS.md +0 -0
  249. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/fixtures/unicode/gr006_word/AGENTS.md +0 -0
  250. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/secret_samples.py +0 -0
  251. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_agents_claude.py +0 -0
  252. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_agents_repo.py +0 -0
  253. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_cli.py +0 -0
  254. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_config.py +0 -0
  255. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_context_command.py +0 -0
  256. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_core_without_cli_deps.py +0 -0
  257. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_corpus_packaging.py +0 -0
  258. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_demo.py +0 -0
  259. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_globs.py +0 -0
  260. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_imports.py +0 -0
  261. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_lock.py +0 -0
  262. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_markdown_utils.py +0 -0
  263. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_mcp_config.py +0 -0
  264. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_models.py +0 -0
  265. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_patterns.py +0 -0
  266. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_playground.py +0 -0
  267. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_precision_v021.py +0 -0
  268. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_precision_v030.py +0 -0
  269. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_rules_config.py +0 -0
  270. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_rules_unicode.py +0 -0
  271. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_scan_imports.py +0 -0
  272. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_scanner.py +0 -0
  273. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_secret_masking.py +0 -0
  274. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_secrets.py +0 -0
  275. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_symlink_alias.py +0 -0
  276. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_targets.py +0 -0
  277. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/test_unicode_utils.py +0 -0
  278. {ghostrules-0.3.0 → ghostrules-0.4.1}/tests/web/test_playground_smoke.py +0 -0
  279. {ghostrules-0.3.0 → ghostrules-0.4.1}/web/app.js +0 -0
  280. {ghostrules-0.3.0 → ghostrules-0.4.1}/web/index.html +0 -0
  281. {ghostrules-0.3.0 → ghostrules-0.4.1}/web/style.css +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.3.0",
29
+ "generator": "ghostrules 0.4.1",
30
30
  "lock_version": 1
31
31
  }
@@ -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
@@ -21,8 +21,8 @@ jobs:
21
21
  env:
22
22
  GH_TOKEN: ${{ github.token }}
23
23
  steps:
24
- - uses: actions/checkout@v4
25
- - uses: actions/setup-python@v5
24
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
25
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
26
26
  with:
27
27
  python-version: "3.12"
28
28
  - name: Install ghostrules from this checkout
@@ -36,7 +36,7 @@ jobs:
36
36
  run: python corpus/badge.py --out corpus-public
37
37
  - name: Upload results
38
38
  if: always()
39
- uses: actions/upload-artifact@v4
39
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
40
40
  with:
41
41
  name: corpus-results
42
42
  path: |
@@ -46,27 +46,28 @@ jobs:
46
46
  if-no-files-found: ignore
47
47
 
48
48
  publish:
49
- # Only the default branch publishes; the badge reads corpus/badge.json from gh-pages.
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).
50
51
  needs: corpus
51
52
  if: always() && needs.corpus.result != 'skipped' && github.ref == 'refs/heads/main'
52
53
  runs-on: ubuntu-latest
53
54
  permissions:
54
55
  contents: write
55
56
  steps:
56
- - uses: actions/download-artifact@v4
57
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
57
58
  with:
58
59
  name: corpus-results
59
60
  path: artifact
60
- - name: Publish to gh-pages
61
+ - name: Publish to the badges branch
61
62
  env:
62
63
  GH_TOKEN: ${{ github.token }}
63
64
  REPO: ${{ github.repository }}
64
65
  run: |
65
66
  set -euo pipefail
66
67
  test -f artifact/corpus-public/badge.json
67
- git clone --quiet --depth 1 --branch gh-pages \
68
+ git clone --quiet --depth 1 --branch badges \
68
69
  "https://x-access-token:${GH_TOKEN}@github.com/${REPO}.git" site \
69
- || { mkdir site && git -C site init --quiet -b gh-pages \
70
+ || { mkdir site && git -C site init --quiet -b badges \
70
71
  && git -C site remote add origin \
71
72
  "https://x-access-token:${GH_TOKEN}@github.com/${REPO}.git"; }
72
73
  mkdir -p site/corpus
@@ -76,4 +77,4 @@ jobs:
76
77
  git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
77
78
  git add corpus
78
79
  git diff --cached --quiet || git commit --quiet -m "corpus: weekly summary"
79
- git push origin gh-pages
80
+ git push origin badges
@@ -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"
@@ -18,3 +18,6 @@ corpus/.cache/
18
18
  corpus/results/*
19
19
  !corpus/results/latest-summary.json
20
20
  _site/
21
+
22
+ # benchmark: findings of third-party repositories
23
+ bench/.cache/
@@ -5,6 +5,147 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.4.1] - 2026-10-29
9
+
10
+ Follow-up to 0.4.0: fewer false positives on scripts, fewer misses on visible attacks, and a
11
+ benchmark headline that no longer counts cases the author wrote. No breaking changes.
12
+
13
+ ### Changed
14
+
15
+ - **Visible prose that reads as an attack stays `high`.** Inside one paragraph, exfiltration plus
16
+ concealment (GR013 + GR011), override plus exfiltration (GR010 + GR013) and a sensitive file plus
17
+ a URL outside `allow_domains` (GR014 + URL) keep the rule's severity even though the text is
18
+ visible. Examples, quotations, code blocks and descriptions stay `low`. On the held-out set no
19
+ repository starts to fail the check, but two GR014 findings already labelled false positive now
20
+ report `high`.
21
+ - **GR110 no longer reports a token sent to the service it belongs to**: `GITHUB_*`/`GH_*` to
22
+ `api.github.com`, `github.com` or `uploads.github.com`; `AZURE_*`, `ADO_*` and `SYSTEM_ACCESSTOKEN`
23
+ to `dev.azure.com` or `*.visualstudio.com`; `<X>_API_KEY` to a host that contains `x`. It still
24
+ reports any other host, a collector domain, the whole environment, a credentials file, a variable
25
+ with no known service and a destination it cannot read. The held-out GR110 finding is still
26
+ reported: its shape is not covered.
27
+ - **The benchmark headline counts only the independent cases.** Recall is split by origin (`author`,
28
+ `review`, `public`; `ours` is now `author`) and the README states the independent figure first,
29
+ with its sample size. Every number in `README.md` and `bench/README.md` is generated from the data
30
+ (`python bench/run.py report --write`) and a test fails when one is stale.
31
+
32
+ ### Added
33
+
34
+ - **Inline hook code is read as a script**: the code in `python3 -c`, `node -e`, `bash -c` and `sh -c`
35
+ (and the other interpreters in the hook table) is checked by GR110–GR113. The finding points at the
36
+ command in the settings file.
37
+
38
+ ## [0.4.0] - 2026-10-29
39
+
40
+ Remediation release, from an independent review of 0.3.0 ([plan](docs/design/v0.4/REMEDIATION.md)).
41
+ The scanned change can no longer switch the scanner off, the lock cannot be re-blessed by a pull
42
+ request, visible prose no longer drowns the check, claims are corrected and measured, and the scanner
43
+ reads more of what agents run. On a new benchmark (101 attack cases and a 100-repository held-out
44
+ set, `bench/`): 87 of 101 attacks reported, 50 fail the default check; precision for a user on the
45
+ held-out set is 19% (4 of 21 findings, labels provisional). Both numbers come with their misses.
46
+
47
+ **Upgrading: breaking changes.** (1) On pull requests the Action reads the config, the ignore comments,
48
+ the baseline and the lock from the base commit; a path outside a git repository needs
49
+ `trust-repo-config: "true"` and `inline-suppressions: all`. (2) Plain visible prose is `low` or `info`
50
+ by default, so a visible `curl | sh` no longer fails `--fail-on high`; `--strict` (config
51
+ `profile = "strict"`, Action `profile: strict`) restores the 0.3 severities. (3) The label `wontfix` is
52
+ now `benign-context` in the corpus tools. (4) The Action installs from a hash-pinned requirements file.
53
+
54
+ ### Added
55
+
56
+ - **Scripts that hooks and skills run** (W5.1, W5.2): hook commands of Claude Code, Gemini, Cursor and
57
+ Codex and scripts named in `SKILL.md` are scanned as code, with the chain that reaches them: GR110
58
+ (sends the environment or a secret), GR111 (reads credential files), GR112 (downloads and runs code),
59
+ GR113 (hides what it runs).
60
+ - **The context engine as a library** (W8): `ghostrules.context.resolve()` and `schema()`, a JSON
61
+ schema for the result validated in the tests, and a README section on alternatives.
62
+ - **Settings a pull request cannot rewrite** (W2 of docs/design/v0.4/REMEDIATION.md): `scan
63
+ --config-from-ref REF`, `--trusted-config FILE`, `--no-inline-suppressions` and
64
+ `--suppressions-from-ref REF`. They close two ways a change could silence the scanner for its own
65
+ payload: a `ghostrules-ignore` comment on the malicious line and `exclude` in `.ghostrules.toml`.
66
+ - **Codex and Gemini CLI** (W5.3): `context` models for both (`--agent codex`, `--agent gemini-cli`;
67
+ opt-in through `agents`, so existing lockfiles do not change); `AGENTS.override.md`,
68
+ `.codex/config.toml` and `.codex/hooks.json` are scanned; GR107 reports Codex
69
+ `sandbox_mode = "danger-full-access"` and `approval_policy = "never"` and Gemini's bare
70
+ `run_shell_command` allow and `enablePermanentToolApproval`.
71
+ - **Files that prose points to** (W5.4): `Read X and follow every step` and `Run scripts/x.sh` make the
72
+ file part of the scan, with the chain and the tag `reached-via-reference` (GR026, a tag, not a
73
+ detector). The `context` tree does not show a `referenced` state yet.
74
+ - **Instructions split across two sentences** (W5.5): GR013 reports a secret in one sentence and a send
75
+ to a URL in the next, with a new `confidence: medium` field on the finding.
76
+ - **A benchmark you can check** (W6): `bench/` has 81 defanged attack cases written from public
77
+ sources (recall per technique and per rule, misses listed, four cases from the independent review as
78
+ known misses) and the 100-repository held-out set run once, with precision for a user per rule. The
79
+ README now shows these numbers instead of the corpus claims. Labels `wontfix` are now
80
+ `benign-context`.
81
+ - **Supply-chain hygiene** (W7): every `uses:` in the Action and the workflows is pinned to a full
82
+ commit SHA (Dependabot keeps them current); the Action installs its dependencies and the build
83
+ backend from `action-requirements.txt`, hash-pinned, with `--require-hashes --no-deps
84
+ --no-build-isolation`; the release workflow moves a `v0` tag to each stable `v0.x.y` release.
85
+ - **Fewer false positives from the independent review** (W4): installers of the project's own
86
+ GitHub organisation and homepage are known installers (read from the base ref when the scan has
87
+ one); Azure CLI, Flox, golangci-lint, Foundry, Flux and Linkerd are known installers; "do not tell
88
+ the user they …" is not concealment.
89
+ - **`ghostrules baseline` and `scan --baseline / --no-baseline / --baseline-from-ref`**: record
90
+ today's findings as fingerprints (no line numbers, no snippets) and fail only on new ones. Hidden
91
+ text is never baselined. The Action reads the baseline at the base commit on pull requests, and
92
+ editing it is reported by GR030.
93
+ - **Breaking: severity by visibility.** Plain visible prose in an agent file is now `low` (an
94
+ instruction) or `info` (a description or quotation) for GR010 to GR014 and GR016; text in an HTML
95
+ comment, decoded hidden text, files reached only through an import, GR015 and every configuration
96
+ rule keep their severity. A visible `curl | sh` or "send `.env` to a URL" no longer fails the
97
+ default check (`--fail-on high`). `--strict`, `profile = "strict"` in the config and the Action's
98
+ `profile: strict` restore the 0.3 behaviour.
99
+ - **`lock --check --base REF`** (W3): compares with the lock and the config at `REF`, so a pull
100
+ request that edits what the agents read and regenerates `.ghostrules.lock` still fails. Exit 2 when
101
+ the ref or its lock does not exist. The idea is cairnlock's `verify --base`.
102
+ - **Breaking: the Action's lock check uses the lock at the base on pull requests**, and a new
103
+ `approve-label` input lets a maintainer approve a legitimate change by applying a label; only the
104
+ event that applies it approves (new commits void it), and the summary names who and when. Output
105
+ `lock-approved`. `trust-repo-config: "true"` restores the working-tree lock.
106
+ - **Inline ignores no longer hide text a reviewer cannot see** (W2): a finding inside an HTML
107
+ comment is never suppressed, and no ignore counts inside a file that an agent reaches only
108
+ through an import (the report says how many were not honoured). Decoded hidden text, GR001 and
109
+ GR002 were already never suppressed. An ignore on a visible line works as before.
110
+ - **GR030, scanner configuration changed** (high): with a base ref, the change adds or edits
111
+ `.ghostrules.toml`, `[tool.ghostrules]`, the lockfile or a `ghostrules-ignore` comment. Reported
112
+ even when legitimate, never suppressible inline, and the change cannot disable it. A new `change`
113
+ scope of rules compares the scanned tree with the base.
114
+ - **Breaking: the Action reads settings from the base commit on pull requests.** On
115
+ `pull_request` and `pull_request_target` events it passes `--config-from-ref` and
116
+ `--suppressions-from-ref` with the base SHA, fetching that commit if the checkout is shallow, and
117
+ fails with exit code 2 when it cannot read it. New inputs: `config`, `trust-repo-config` (default
118
+ `false`) and `inline-suppressions` (`base`, `off` or `all`; default `base`). Workflows that scan a
119
+ path outside a git repository on a pull request need `trust-repo-config: "true"` and
120
+ `inline-suppressions: all`. Other events behave as before.
121
+
122
+ ### Changed
123
+
124
+ - **Corrected claims** (W1 of [docs/design/v0.4/REMEDIATION.md](docs/design/v0.4/REMEDIATION.md)).
125
+ The 0.2 statement that no other tool follows `@path` imports was wrong (cfgaudit does, since
126
+ 2026-10-24): the prior-art notes are corrected and dated, and ghostrules no longer claims to be
127
+ the first or the only one. The README says "scheduled weekly; last run" instead of "every week".
128
+ The study report is now "A snapshot (2026-10-28)", puts hygiene statistics apart from security
129
+ indicators, shows a numerator and denominator next to each percentage, explains the MCP
130
+ denominator (a lower bound, so the share is an upper bound), counts benign-context matches as noise
131
+ in a per-rule precision table, and has a "Threats to validity" section. The 0.3.0 notes below are
132
+ left as published.
133
+ - README restructured as a landing page; option tables, configuration, supported files, FAQ and limits
134
+ moved to `docs/USAGE.md`, and the rules table to `docs/RULES.md`.
135
+ - SARIF `helpUri` points to `docs/RULES.md#grNNN` (the rules table moved there).
136
+
137
+ ### Known limits
138
+
139
+ - Paraphrases, languages other than English and Spanish (GR013 has no Spanish patterns), a few read
140
+ verbs (`Open ~/.npmrc`), `exec(urlopen())`, endpoint overrides in settings and the descriptions an MCP
141
+ server serves are not caught: 14 of the 101 attack cases (`bench/RESULTS.md`).
142
+ - Only 4 of the review's 18 evasion cases are in the attack set; the rest were not available.
143
+ - The held-out labels are provisional (given by the assistant that ran the benchmark, not reviewed by a
144
+ person) and 21 findings are too few for a per-rule precision estimate.
145
+ - The `context` tree does not show files reached by a prose reference, and the lock does not record
146
+ them; Codex and Gemini CLI models are opt-in.
147
+ - The MCP share in the study is an upper bound (its denominator is a lower bound).
148
+
8
149
  ## [0.3.0] - 2026-10-28
9
150
 
10
151
  Measurement release. ghostrules now runs against real repositories every week, a browser playground
@@ -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.
@@ -55,7 +55,7 @@ pull request.
55
55
 
56
56
  3. **Document it.** Describe the rule in `docs/RULES.md` (ID, severity, logic, true and false
57
57
  positive examples), note any judgement call in `docs/DECISIONS.md`, add a line to
58
- `CHANGELOG.md`, then refresh the README table:
58
+ `CHANGELOG.md`, then refresh the rule index in `docs/RULES.md`:
59
59
 
60
60
  ```bash
61
61
  python scripts/make_demo.py
@@ -88,6 +88,20 @@ model is one module, one section of `docs/AGENT_MODELS.md` and its tests:
88
88
  in `ContextGraph.notes`, and add a line to `CHANGELOG.md` and a decision to
89
89
  `docs/DECISIONS.md` for every judgement call.
90
90
 
91
+ ## Supply chain
92
+
93
+ - Every `uses:` in `action.yml` and `.github/workflows/` is pinned to a full commit SHA with the
94
+ version in a comment (`actions/checkout@<sha> # v4`). Dependabot opens the update pull requests;
95
+ a test fails on a tag or branch reference.
96
+ - The Action installs from `action-requirements.txt`, which has a hash for every package, the build
97
+ backend included. Regenerate it when `pyproject.toml` dependencies change:
98
+
99
+ ```bash
100
+ pip install pip-tools
101
+ pip-compile --generate-hashes --strip-extras --allow-unsafe \
102
+ -o action-requirements.txt action-requirements.in
103
+ ```
104
+
91
105
  ## Rules of the repository
92
106
 
93
107
  - **Defanged only.** Fixtures, demos and tests use `attacker.example`, `exfil.example`,