plugin-scanner 2.0.70__tar.gz → 2.0.71__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 (331) hide show
  1. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/PKG-INFO +1 -1
  2. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docs/guard/harness-support.md +14 -0
  3. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docs/guard/testing-matrix.md +4 -0
  4. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/pyproject.toml +1 -1
  5. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/pyproject.toml.bak +1 -1
  6. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/copilot.py +1 -1
  7. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/cursor.py +7 -0
  8. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/gemini.py +5 -0
  9. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/opencode.py +5 -0
  10. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/commands.py +12 -26
  11. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/runtime/runner.py +175 -30
  12. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/version.py +1 -1
  13. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_claude_adapter.py +8 -2
  14. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_copilot_adapter.py +3 -0
  15. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_launch_env.py +193 -1
  16. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_runtime.py +205 -6
  17. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_surface_server.py +7 -2
  18. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.clusterfuzzlite/Dockerfile +0 -0
  19. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.clusterfuzzlite/build.sh +0 -0
  20. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.clusterfuzzlite/project.yaml +0 -0
  21. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.clusterfuzzlite/requirements-atheris.txt +0 -0
  22. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.dockerignore +0 -0
  23. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/CODEOWNERS +0 -0
  24. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  25. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  26. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  27. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/dependabot.yml +0 -0
  28. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/workflows/ci.yml +0 -0
  29. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/workflows/codeql.yml +0 -0
  30. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/workflows/dependabot-uv-lock.yml +0 -0
  31. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/workflows/fuzz.yml +0 -0
  32. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/workflows/harness-smoke.yml +0 -0
  33. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/workflows/publish.yml +0 -0
  34. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/workflows/scorecard.yml +0 -0
  35. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.gitignore +0 -0
  36. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.pre-commit-hooks.yaml +0 -0
  37. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/CONTRIBUTING.md +0 -0
  38. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/Dockerfile +0 -0
  39. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/LICENSE +0 -0
  40. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/README.md +0 -0
  41. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/SECURITY.md +0 -0
  42. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/index.html +0 -0
  43. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/package.json +0 -0
  44. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/pnpm-lock.yaml +0 -0
  45. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/public/apple-touch-icon.png +0 -0
  46. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
  47. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/public/brand/Logo_Whole.png +0 -0
  48. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/public/favicon-16x16.png +0 -0
  49. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/public/favicon-32x32.png +0 -0
  50. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/public/favicon.ico +0 -0
  51. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/app.tsx +0 -0
  52. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/approval-center-layout.tsx +0 -0
  53. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/approval-center-primitives.tsx +0 -0
  54. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/approval-center-utils.ts +0 -0
  55. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/fleet-workspace.tsx +0 -0
  56. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/guard-api.ts +0 -0
  57. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/guard-demo.ts +0 -0
  58. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/guard-types.ts +0 -0
  59. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/main.tsx +0 -0
  60. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/receipts-workspace.tsx +0 -0
  61. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/runtime-overview.tsx +0 -0
  62. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/settings-workspace.tsx +0 -0
  63. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/styles.css +0 -0
  64. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/vite-env.d.ts +0 -0
  65. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/tsconfig.json +0 -0
  66. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/vite.config.ts +0 -0
  67. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docker-requirements.txt +0 -0
  68. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docs/guard/approval-audit.md +0 -0
  69. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docs/guard/architecture.md +0 -0
  70. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docs/guard/get-started.md +0 -0
  71. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docs/guard/local-vs-cloud.md +0 -0
  72. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docs/trust/mcp-trust-draft.md +0 -0
  73. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docs/trust/plugin-trust-draft.md +0 -0
  74. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docs/trust/skill-trust-local.md +0 -0
  75. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/fuzzers/manifest_fuzzer.py +0 -0
  76. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/requirements.txt +0 -0
  77. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/schemas/plugin-quality.v1.json +0 -0
  78. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/schemas/scan-result.v1.json +0 -0
  79. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/schemas/verify-result.v1.json +0 -0
  80. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/__init__.py +0 -0
  81. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/action_runner.py +0 -0
  82. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/argparse_utils.py +0 -0
  83. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/__init__.py +0 -0
  84. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
  85. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/claude.py +0 -0
  86. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
  87. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
  88. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/gemini.py +0 -0
  89. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/manifest.py +0 -0
  90. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
  91. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
  92. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
  93. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/opencode.py +0 -0
  94. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
  95. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/security.py +0 -0
  96. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
  97. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/cli.py +0 -0
  98. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/cli_ui.py +0 -0
  99. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/config.py +0 -0
  100. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
  101. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
  102. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
  103. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
  104. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
  105. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
  106. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
  107. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
  108. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
  109. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/github_reporting.py +0 -0
  110. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/__init__.py +0 -0
  111. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
  112. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
  113. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
  114. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
  115. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
  116. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
  117. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
  118. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
  119. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/approvals.py +0 -0
  120. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
  121. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
  122. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
  123. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
  124. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
  125. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
  126. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
  127. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
  128. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
  129. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
  130. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
  131. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
  132. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/config.py +0 -0
  133. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
  134. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
  135. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
  136. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
  137. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
  138. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
  139. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
  140. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
  141. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
  142. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
  143. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
  144. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
  145. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
  146. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
  147. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
  148. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
  149. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/incident.py +0 -0
  150. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/launcher.py +0 -0
  151. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
  152. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/models.py +0 -0
  153. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
  154. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
  155. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/protect.py +0 -0
  156. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
  157. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
  158. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
  159. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
  160. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
  161. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
  162. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/risk.py +0 -0
  163. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
  164. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
  165. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
  166. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
  167. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
  168. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
  169. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
  170. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/shims.py +0 -0
  171. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/store.py +0 -0
  172. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
  173. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
  174. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/types.py +0 -0
  175. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
  176. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
  177. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
  178. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/lint_fixes.py +0 -0
  179. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/marketplace_support.py +0 -0
  180. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/models.py +0 -0
  181. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/path_support.py +0 -0
  182. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/policy.py +0 -0
  183. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/quality_artifact.py +0 -0
  184. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/repo_detect.py +0 -0
  185. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/reporting.py +0 -0
  186. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/rules/__init__.py +0 -0
  187. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/rules/registry.py +0 -0
  188. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/rules/specs.py +0 -0
  189. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/scanner.py +0 -0
  190. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/submission.py +0 -0
  191. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/suppressions.py +0 -0
  192. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
  193. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/trust_helpers.py +0 -0
  194. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
  195. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/trust_models.py +0 -0
  196. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
  197. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/trust_scoring.py +0 -0
  198. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
  199. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/trust_specs.py +0 -0
  200. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/verification.py +0 -0
  201. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/__init__.py +0 -0
  202. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/conftest.py +0 -0
  203. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/__init__.py +0 -0
  204. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
  205. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/bad-plugin/.mcp.json +0 -0
  206. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/bad-plugin/secrets.js +0 -0
  207. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
  208. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
  209. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/claude-plugin-good/README.md +0 -0
  210. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
  211. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
  212. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
  213. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/code-quality-bad/evil.js +0 -0
  214. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/code-quality-bad/inject.js +0 -0
  215. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
  216. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
  217. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/gemini-extension-good/README.md +0 -0
  218. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
  219. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
  220. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
  221. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
  222. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/good-plugin/.codexignore +0 -0
  223. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/good-plugin/LICENSE +0 -0
  224. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/good-plugin/README.md +0 -0
  225. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/good-plugin/SECURITY.md +0 -0
  226. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
  227. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
  228. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
  229. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
  230. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
  231. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
  232. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
  233. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
  234. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
  235. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
  236. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
  237. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
  238. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
  239. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
  240. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
  241. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
  242. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
  243. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
  244. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
  245. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/mcp-canary-server.py +0 -0
  246. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
  247. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
  248. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/mit-license/LICENSE +0 -0
  249. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
  250. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
  251. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
  252. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
  253. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
  254. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
  255. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
  256. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
  257. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
  258. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
  259. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
  260. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
  261. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
  262. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
  263. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
  264. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
  265. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
  266. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
  267. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/opencode-good/LICENSE +0 -0
  268. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/opencode-good/README.md +0 -0
  269. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/opencode-good/SECURITY.md +0 -0
  270. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
  271. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
  272. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
  273. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
  274. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
  275. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
  276. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/with-marketplace/marketplace.json +0 -0
  277. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test-trust-scoring.py +0 -0
  278. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test-trust-specs.py +0 -0
  279. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_action_runner.py +0 -0
  280. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_best_practices.py +0 -0
  281. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_cisco_install_surfaces.py +0 -0
  282. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_cli.py +0 -0
  283. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_code_quality.py +0 -0
  284. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_config.py +0 -0
  285. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_coverage_remaining.py +0 -0
  286. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_ecosystems.py +0 -0
  287. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_edge_cases.py +0 -0
  288. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_final_coverage.py +0 -0
  289. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_approvals.py +0 -0
  290. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_bootstrap.py +0 -0
  291. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_capabilities.py +0 -0
  292. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_cli.py +0 -0
  293. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_codex_e2e.py +0 -0
  294. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_codex_install.py +0 -0
  295. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_codex_proxy.py +0 -0
  296. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_config_paths.py +0 -0
  297. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_connect_flow.py +0 -0
  298. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_consumer_mode.py +0 -0
  299. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_copilot_proxy.py +0 -0
  300. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_daemon_manager.py +0 -0
  301. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_event_schema_v1.py +0 -0
  302. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_events.py +0 -0
  303. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_opencode_proxy.py +0 -0
  304. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_product_flow.py +0 -0
  305. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_protect.py +0 -0
  306. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_render.py +0 -0
  307. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_risk.py +0 -0
  308. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_store_migrations.py +0 -0
  309. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_verdicts.py +0 -0
  310. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_hermes_adapter.py +0 -0
  311. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_integration.py +0 -0
  312. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_lint_fixes.py +0 -0
  313. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_live_cisco_smoke.py +0 -0
  314. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_manifest.py +0 -0
  315. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_marketplace.py +0 -0
  316. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_mcp_security.py +0 -0
  317. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_operational_security.py +0 -0
  318. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_policy.py +0 -0
  319. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_quality_artifact.py +0 -0
  320. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_rule_registry.py +0 -0
  321. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_scanner.py +0 -0
  322. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_schema_contracts.py +0 -0
  323. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_security.py +0 -0
  324. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_security_ops.py +0 -0
  325. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_skill_security.py +0 -0
  326. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_submission.py +0 -0
  327. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_trust_scoring.py +0 -0
  328. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_trust_specs.py +0 -0
  329. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_verification.py +0 -0
  330. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_versioning.py +0 -0
  331. {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 2.0.70
3
+ Version: 2.0.71
4
4
  Summary: Lint, verify, and gate plugin ecosystems for maintainers, CI, and publish workflows.
5
5
  Project-URL: Homepage, https://github.com/hashgraph-online/ai-plugin-scanner
6
6
  Project-URL: Repository, https://github.com/hashgraph-online/ai-plugin-scanner
@@ -8,11 +8,13 @@ Current Guard support in this repo:
8
8
  - parses configured MCP servers
9
9
  - installs Guard-owned Codex `PreToolUse` Bash hooks so native shell commands can be denied before execution even when Codex itself is running in YOLO mode
10
10
  - supports wrapper-mode `guard run codex`
11
+ - wrapper prompt screening now suppresses copied debug and incident context while still escalating risky prompt intent
11
12
  - uses same-chat MCP elicitation for live managed MCP tool approvals in the interactive CLI and Codex App
12
13
  - falls back to the local approval center only for nonresponsive or headless Codex sessions such as `codex exec`
13
14
  - `claude-code`
14
15
  - detects global and project settings, hooks, `.mcp.json`, and workspace agents
15
16
  - supports local hook install and uninstall in `.claude/settings.local.json`
17
+ - has native `UserPromptSubmit` and `PreToolUse` Guard hook coverage
16
18
  - is the best current harness for graceful approval deferral
17
19
  - `copilot`
18
20
  - detects read-only user config in `~/.copilot/config.json` and `~/.copilot/mcp-config.json`
@@ -20,9 +22,11 @@ Current Guard support in this repo:
20
22
  - detects repo-local Copilot CLI hooks from `.github/hooks/*.json`
21
23
  - installs and removes Guard-owned repo hooks in `.github/hooks/hol-guard-copilot.json`
22
24
  - supports wrapper-mode `guard run copilot`
25
+ - has native `userPromptSubmitted`, `preToolUse`, and `postToolUse` hook coverage normalized onto the shared Guard runtime
23
26
  - `cursor`
24
27
  - detects global and project `mcp.json`
25
28
  - supports wrapper-mode management state
29
+ - wrapper prompt screening is covered for benign debug prompts and risky secret-read prompts
26
30
  - leaves native Cursor tool approval in place and focuses Guard on artifact trust
27
31
  - `antigravity`
28
32
  - detects Antigravity user settings, installed extension profiles, and Antigravity-owned MCP and skill roots
@@ -31,6 +35,7 @@ Current Guard support in this repo:
31
35
  - `gemini`
32
36
  - detects `.gemini/settings.json`, local extension manifests, embedded MCP declarations, hooks, and Gemini skill directories
33
37
  - supports wrapper-mode management state
38
+ - wrapper prompt screening is covered for benign debug prompts and risky secret-read prompts
34
39
  - falls back to the local approval center when Guard blocks a launch
35
40
  - `hermes`
36
41
  - detects Hermes skills plus MCP servers from `~/.hermes/config.yaml` and `~/.hermes/mcp_servers.json`
@@ -42,6 +47,7 @@ Current Guard support in this repo:
42
47
  plugin files, and OpenCode-compatible skill directories
43
48
  - supports wrapper-mode management state plus a Guard-owned runtime overlay for native skill approval prompts
44
49
  - supports wrapper-mode `guard run opencode`
50
+ - wrapper prompt screening is covered for benign debug prompts and risky secret-read prompts
45
51
  - keeps managed MCP tools on OpenCode native ask so the user can allow once, allow for the session, or reject inline
46
52
  - blocks newly introduced OpenCode MCP, plugin, and skill artifacts before launch when local Guard policy requires
47
53
  approval
@@ -54,6 +60,14 @@ Approval tiers:
54
60
 
55
61
  The harness adapters are designed to prefer discovery and reversible overlay behavior over invasive config mutation.
56
62
 
63
+ The Guard Surface Server now provides one shared runtime shape across harnesses:
64
+
65
+ - session attach
66
+ - operation start and status updates
67
+ - approval request items
68
+ - approval-center lease and heartbeat tracking
69
+ - resume or completion after approval
70
+
57
71
  Runtime intent protections:
58
72
 
59
73
  - Guard evaluates prompt and tool intent for secret-bearing files beyond `.env`, including SSH, AWS, kubeconfig, Docker, npm, and Python credential files.
@@ -4,6 +4,8 @@ Automated coverage in this phase includes:
4
4
 
5
5
  - Guard CLI behavior tests for detect, scan, run, diff, receipts, install, uninstall, login, and sync
6
6
  - Guard product-flow tests for `hol-guard start`, `hol-guard status`, and launcher shim creation
7
+ - prompt-risk regressions for Codex, Cursor, Gemini, and OpenCode wrapper launches
8
+ - native prompt-hook regressions for Claude Code and Copilot hook events
7
9
  - SQLite persistence through real command execution in temporary homes and workspaces
8
10
  - consumer-mode JSON contract generation against scanner fixtures
9
11
  - local HTTP sync against a live in-process server instead of mocked transport
@@ -20,6 +22,8 @@ Manual verification should include:
20
22
  - `hol-guard detect opencode --json`
21
23
  - `hol-guard install opencode --json`
22
24
  - `hol-guard update --dry-run --json`
25
+ - `hol-guard run cursor --dry-run --default-action allow --json`
26
+ - `hol-guard run gemini --dry-run --default-action allow --json`
23
27
  - `hol-guard run opencode --dry-run --default-action allow --json`
24
28
  - `hol-guard run opencode --default-action require-reapproval --json`
25
29
  - `hol-guard approvals --json`
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "plugin-scanner"
7
- version = "2.0.70"
7
+ version = "2.0.71"
8
8
  description = "Lint, verify, and gate plugin ecosystems for maintainers, CI, and publish workflows."
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "hol-guard"
7
- version = "2.0.70"
7
+ version = "2.0.71"
8
8
  description = "Protect local AI harnesses with HOL Guard and run scanner checks for Codex, Claude, Cursor, Gemini, and OpenCode."
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -25,7 +25,7 @@ from .mcp_servers import (
25
25
  skipped_stdio_server_names,
26
26
  )
27
27
 
28
- _MANAGED_HOOK_EVENTS = ("preToolUse", "postToolUse", "permissionRequest")
28
+ _MANAGED_HOOK_EVENTS = ("userPromptSubmitted", "preToolUse", "postToolUse", "permissionRequest")
29
29
  _DETECTABLE_HOOK_EVENTS = (
30
30
  "sessionStart",
31
31
  "sessionEnd",
@@ -2,6 +2,8 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from pathlib import Path
6
+
5
7
  from ..models import GuardArtifact, HarnessDetection
6
8
  from .base import HarnessAdapter, HarnessContext, _command_available, _json_payload, _run_command_probe
7
9
 
@@ -25,6 +27,11 @@ class CursorHarnessAdapter(HarnessAdapter):
25
27
  return "project"
26
28
  return "global"
27
29
 
30
+ def policy_path(self, context: HarnessContext) -> Path:
31
+ if context.workspace_dir is not None:
32
+ return context.workspace_dir / ".cursor" / "mcp.json"
33
+ return context.home_dir / ".cursor" / "mcp.json"
34
+
28
35
  def detect(self, context: HarnessContext) -> HarnessDetection:
29
36
  config_paths = [context.home_dir / ".cursor" / "mcp.json"]
30
37
  if context.workspace_dir is not None:
@@ -39,6 +39,11 @@ class GeminiHarnessAdapter(HarnessAdapter):
39
39
  return ()
40
40
  return tuple(str(value) for value in raw_args if isinstance(value, str))
41
41
 
42
+ def policy_path(self, context: HarnessContext) -> Path:
43
+ if context.workspace_dir is not None:
44
+ return context.workspace_dir / ".gemini" / "settings.json"
45
+ return context.home_dir / ".gemini" / "settings.json"
46
+
42
47
  def detect(self, context: HarnessContext) -> HarnessDetection:
43
48
  artifacts: list[GuardArtifact] = []
44
49
  found_paths: list[str] = []
@@ -97,6 +97,11 @@ class OpenCodeHarnessAdapter(HarnessAdapter):
97
97
  return "project"
98
98
  return "global"
99
99
 
100
+ def policy_path(self, context: HarnessContext) -> Path:
101
+ if context.workspace_dir is not None:
102
+ return context.workspace_dir / "opencode.json"
103
+ return context.home_dir / ".config" / "opencode" / "opencode.json"
104
+
100
105
  def detect(self, context: HarnessContext) -> HarnessDetection:
101
106
  artifacts = []
102
107
  found_paths: list[str] = []
@@ -1484,14 +1484,6 @@ def run_guard_command(
1484
1484
  artifact=runtime_artifact,
1485
1485
  artifact_hash=runtime_artifact_hash,
1486
1486
  )
1487
- if _should_allow_claude_user_prompt_submit_without_output(
1488
- args,
1489
- event_name=event_name,
1490
- policy_action=policy_action,
1491
- artifact=runtime_artifact,
1492
- output_stream=output_stream,
1493
- ):
1494
- return 0
1495
1487
  if _should_emit_copilot_hook_response(args):
1496
1488
  _emit_copilot_hook_response(
1497
1489
  policy_action=policy_action,
@@ -1866,23 +1858,6 @@ def _should_emit_prequeue_native_hook_response(
1866
1858
  return output_stream is not None
1867
1859
 
1868
1860
 
1869
- def _should_allow_claude_user_prompt_submit_without_output(
1870
- args: argparse.Namespace,
1871
- *,
1872
- event_name: str,
1873
- policy_action: str,
1874
- artifact: GuardArtifact,
1875
- output_stream: TextIO | None,
1876
- ) -> bool:
1877
- return (
1878
- _canonical_harness_name(args.harness) == "claude-code"
1879
- and event_name == "UserPromptSubmit"
1880
- and policy_action == "require-reapproval"
1881
- and not _prompt_requires_hard_block(artifact)
1882
- and (not getattr(args, "json", False) or output_stream is not None)
1883
- )
1884
-
1885
-
1886
1861
  def _emit_claude_permission_request_passthrough(*, output_stream: TextIO | None = None) -> None:
1887
1862
  if output_stream is not None:
1888
1863
  output_stream.write("")
@@ -3070,6 +3045,8 @@ def _emit_native_hook_response(
3070
3045
  "hookEventName": event_name,
3071
3046
  "additionalContext": additional_context,
3072
3047
  }
3048
+ elif _canonical_harness_name(harness) in {"claude-code", "codex"}:
3049
+ payload["hookSpecificOutput"] = {"hookEventName": event_name}
3073
3050
  if payload:
3074
3051
  _write_json_line(payload, output_stream=output_stream)
3075
3052
  return
@@ -3432,11 +3409,20 @@ def _optional_string(value: object | None) -> str | None:
3432
3409
  return None
3433
3410
 
3434
3411
 
3412
+ _HOOK_EVENT_NAME_MAP = {
3413
+ "userpromptsubmitted": "UserPromptSubmit",
3414
+ "pretooluse": "PreToolUse",
3415
+ "posttooluse": "PostToolUse",
3416
+ "permissionrequest": "PermissionRequest",
3417
+ }
3418
+
3419
+
3435
3420
  def _hook_event_name(payload: dict[str, object]) -> str | None:
3436
3421
  for key in ("event", "hook_event_name", "hookEventName", "hook_name"):
3437
3422
  value = payload.get(key)
3438
3423
  if isinstance(value, str) and value.strip():
3439
- return value.strip()
3424
+ normalized = value.strip()
3425
+ return _HOOK_EVENT_NAME_MAP.get(normalized.lower(), normalized)
3440
3426
  return None
3441
3427
 
3442
3428
 
@@ -58,22 +58,87 @@ _SECRET_ABSOLUTE_HINTS: tuple[tuple[str, str], ...] = (
58
58
  ("/.kube/config", "kubeconfig"),
59
59
  ("/.docker/config.json", "Docker credentials"),
60
60
  )
61
- _EXFIL_PROMPT_PATTERN = re.compile(
62
- r"\b(upload|exfiltrate|send|post|sync|webhook|paste|gist|transfer)\b",
61
+ _SECRET_READ_INTENT_PATTERN = re.compile(
62
+ r"\b("
63
+ r"read|open|print|show|dump|cat|head|tail|less|copy|cp|scp|reveal|display|summari[sz]e|inspect|extract|"
64
+ r"contain(?:s)?|contents?\s+of|what(?:'s| is)\s+in"
65
+ r")\b",
63
66
  re.IGNORECASE,
64
67
  )
65
- _DESTRUCTIVE_PROMPT_PATTERN = re.compile(
66
- r"\b(rm\s+-rf|rm\s+|del\s+|truncate\s+|chmod\s+|chown\s+|mv\s+|overwrite)\b",
67
- re.IGNORECASE,
68
+ _EXFIL_PROMPT_PATTERNS: tuple[re.Pattern[str], ...] = (
69
+ re.compile(
70
+ r"\b(?:upload|exfiltrate|transfer|paste|gist|webhook)\b.{0,80}\b"
71
+ r"(?:file|contents?|data|payload|secret|token|key|credential|credentials|config|output)\b",
72
+ re.IGNORECASE,
73
+ ),
74
+ re.compile(
75
+ r"\b(?:send|post|upload|transfer|paste|sync)\b.{0,80}\b"
76
+ r"(?:contents?|data|payload|file|secret|token|key|credential|credentials|config|output)\b"
77
+ r"(?:.{0,40}\b(?:to|into|onto|via|through)\b)?",
78
+ re.IGNORECASE,
79
+ ),
80
+ re.compile(
81
+ r"\b(?:send|post|upload|transfer|paste|sync)\b.{0,80}\b"
82
+ r"(?:to|into|onto|via|through)\b.{0,40}\b"
83
+ r"(?:webhook|gist|pastebin|slack|discord|telegram|server|endpoint|url)\b",
84
+ re.IGNORECASE,
85
+ ),
86
+ re.compile(
87
+ r"\b(?:send|post|upload|transfer|paste|sync)\b.{0,120}"
88
+ r"(?:"
89
+ r"(?<![\w-])\.env(?:\.[\w.-]+)?\b|"
90
+ r"(?:^|[\s'\"`])~?/.ssh(?:/|\b)|"
91
+ r"(?:^|[\s'\"`])~?/.aws/(?:credentials|config)\b|"
92
+ r"(?:^|[\s'\"`])~?/.kube/config\b|"
93
+ r"(?:^|[\s'\"`])~?/.docker/config\.json\b|"
94
+ r"(?<![\w-])\.npmrc\b|"
95
+ r"(?<![\w-])\.pypirc\b|"
96
+ r"(?<![\w-])\.git-credentials\b|"
97
+ r"/.ssh/|"
98
+ r"/.aws/credentials|"
99
+ r"/.aws/config|"
100
+ r"/.kube/config|"
101
+ r"/.docker/config\.json"
102
+ r")"
103
+ r".{0,80}\b(?:to|into|onto|via|through)\b.{0,80}"
104
+ r"(?:[a-z][a-z0-9+.-]*://|webhook|gist|pastebin|slack|discord|telegram|server|endpoint|url)\b",
105
+ re.IGNORECASE,
106
+ ),
68
107
  )
69
- _SUBPROCESS_PROMPT_PATTERN = re.compile(
70
- r"\b(?:bash\s+-c|sh\s+-c|zsh\s+-c|powershell|cmd\s+/c|subprocess)\b|(?:exec|spawn)\s*\(",
71
- re.IGNORECASE,
108
+ _DESTRUCTIVE_PROMPT_PATTERNS: tuple[re.Pattern[str], ...] = (
109
+ re.compile(
110
+ r"\b(?:run|execute|use|call|invoke)\b.{0,40}\b(?:rm\s+-rf|rm\s+|del\s+|truncate\s+|chmod\s+|chown\s+|mv\s+)",
111
+ re.IGNORECASE,
112
+ ),
113
+ re.compile(
114
+ r"(?:^|[\s'\"`(])(?:rm\s+-rf|rm\s+\S|del\s+\S|truncate\s+\S|chmod\s+\S|chown\s+\S|mv\s+\S)",
115
+ re.IGNORECASE,
116
+ ),
117
+ re.compile(
118
+ r"\b(?:delete|remove|overwrite|truncate)\b.{0,60}\b(?:file|directory|repo|workspace|contents?)\b",
119
+ re.IGNORECASE,
120
+ ),
121
+ )
122
+ _SUBPROCESS_PROMPT_PATTERNS: tuple[re.Pattern[str], ...] = (
123
+ re.compile(
124
+ r"\b(?:run|execute|use|call|invoke|launch|spawn)\b.{0,60}\b"
125
+ r"(?:bash\s+-c|sh\s+-c|zsh\s+-c|powershell|cmd\s+/c|subprocess|exec\(|spawn\()",
126
+ re.IGNORECASE,
127
+ ),
128
+ re.compile(
129
+ r"(?:^|[\s'\"`(])(?:bash\s+-c\b|sh\s+-c\b|zsh\s+-c\b|powershell(?:\.exe)?(?:\s|$)|cmd\s+/c(?:\s|$)|subprocess\.(?:run|Popen|call|check_call|check_output)\b|exec\(|spawn\()",
130
+ re.IGNORECASE,
131
+ ),
132
+ re.compile(
133
+ r"\b(?:use|call|invoke)\b.{0,40}\bsubprocess\b",
134
+ re.IGNORECASE,
135
+ ),
72
136
  )
73
137
  _GUARD_BYPASS_PROMPT_PATTERN = re.compile(
74
138
  r"\b(hol-guard\s+(?:disable|off|uninstall)|disable\s+hol-guard|approval_policy\s*=\s*\"never\"|guard[_-]?bypass)\b",
75
139
  re.IGNORECASE,
76
140
  )
141
+ _PROMPT_SENTENCE_BOUNDARY_PATTERN = re.compile(r"[!?;]|[.](?=\s|$)")
77
142
  _GUARD_SYNC_USER_AGENT = f"hol-guard/{__version__}"
78
143
  _SYNC_HTTP_TIMEOUT_SECONDS = 20
79
144
  _SYNC_HTTP_RETRY_TIMEOUT_SECONDS = 120
@@ -91,6 +156,55 @@ class GuardSyncNotAvailableError(RuntimeError):
91
156
  """Raised when the sync endpoint returns 403 (free-plan restriction)."""
92
157
 
93
158
 
159
+ def _prompt_sentence_start(text: str, index: int) -> int:
160
+ matches = list(_PROMPT_SENTENCE_BOUNDARY_PATTERN.finditer(text, 0, index))
161
+ return matches[-1].end() if matches else 0
162
+
163
+
164
+ def _prompt_sentence_end(text: str, index: int) -> int:
165
+ match = _PROMPT_SENTENCE_BOUNDARY_PATTERN.search(text, index)
166
+ return match.end() if match is not None else len(text)
167
+
168
+
169
+ def _prompt_secret_intent_region(text: str, *, start: int, end: int) -> str:
170
+ current_sentence_start = _prompt_sentence_start(text, start)
171
+ region_start = _prompt_sentence_start(text, max(0, current_sentence_start - 1))
172
+ first_sentence_end = _prompt_sentence_end(text, end)
173
+ second_sentence_end = (
174
+ _prompt_sentence_end(text, first_sentence_end) if first_sentence_end < len(text) else first_sentence_end
175
+ )
176
+ return text[region_start:second_sentence_end]
177
+
178
+
179
+ def _prompt_has_secret_read_intent(prompt_text: str, *, start: int, end: int) -> bool:
180
+ return (
181
+ _SECRET_READ_INTENT_PATTERN.search(
182
+ _prompt_secret_intent_region(prompt_text, start=start, end=end),
183
+ )
184
+ is not None
185
+ )
186
+
187
+
188
+ def _first_match(patterns: tuple[re.Pattern[str], ...], text: str) -> re.Match[str] | None:
189
+ for pattern in patterns:
190
+ match = pattern.search(text)
191
+ if match is not None:
192
+ return match
193
+ return None
194
+
195
+
196
+ def _iter_hint_occurrences(text: str, hint: str) -> list[tuple[int, int]]:
197
+ occurrences: list[tuple[int, int]] = []
198
+ current_pos = 0
199
+ while True:
200
+ start = text.find(hint, current_pos)
201
+ if start == -1:
202
+ return occurrences
203
+ end = start + len(hint)
204
+ occurrences.append((start, end))
205
+ current_pos = start + 1
206
+
207
+
94
208
  def guard_run(
95
209
  harness: str,
96
210
  context: HarnessContext,
@@ -122,6 +236,12 @@ def guard_run(
122
236
  if key in pending_evaluation:
123
237
  reevaluated[key] = pending_evaluation[key]
124
238
  evaluation = reevaluated
239
+ if "config_paths" not in evaluation:
240
+ evaluation["config_paths"] = list(detection.config_paths) or _guard_run_config_paths(
241
+ detection=detection,
242
+ context=context,
243
+ passthrough_args=passthrough_args,
244
+ )
125
245
  if evaluation["blocked"] or dry_run:
126
246
  evaluation["launched"] = False
127
247
  evaluation["launch_command"] = []
@@ -147,6 +267,20 @@ def guard_run(
147
267
  return evaluation
148
268
 
149
269
 
270
+ def _guard_run_config_paths(
271
+ *,
272
+ detection: HarnessDetection,
273
+ context: HarnessContext,
274
+ passthrough_args: list[str],
275
+ ) -> list[str]:
276
+ if detection.config_paths:
277
+ return list(detection.config_paths)
278
+ prompt_text = " ".join(value.strip() for value in passthrough_args if value.strip())
279
+ if prompt_text:
280
+ return [str(_prompt_policy_path(detection, context))]
281
+ return []
282
+
283
+
150
284
  def _detection_with_prompt_artifacts(
151
285
  detection: HarnessDetection,
152
286
  context: HarnessContext,
@@ -210,20 +344,25 @@ def extract_prompt_requests(prompt_text: str) -> list[PromptRequest]:
210
344
  )
211
345
 
212
346
  for pattern, label in _SECRET_REQUEST_PATTERNS:
213
- match = pattern.search(normalized_prompt)
214
- if match is None:
215
- continue
216
- add_secret_request(label=label, matched=match.group(0).strip())
347
+ for match in pattern.finditer(normalized_prompt):
348
+ if not _prompt_has_secret_read_intent(normalized_prompt, start=match.start(), end=match.end()):
349
+ continue
350
+ add_secret_request(label=label, matched=match.group(0).strip())
351
+ break
217
352
  for hint, label in _SECRET_ABSOLUTE_HINTS:
218
- if hint in lowered:
219
- add_secret_request(label=label, matched=hint)
220
- if _EXFIL_PROMPT_PATTERN.search(normalized_prompt):
353
+ for start, end in _iter_hint_occurrences(lowered, hint):
354
+ if _prompt_has_secret_read_intent(normalized_prompt, start=start, end=end):
355
+ add_secret_request(label=label, matched=hint)
356
+ break
357
+ exfil_match = _first_match(_EXFIL_PROMPT_PATTERNS, normalized_prompt)
358
+ if exfil_match is not None:
359
+ matched_text = exfil_match.group(0).strip()
221
360
  requests.append(
222
361
  PromptRequest(
223
- request_id=_prompt_request_id("exfil_intent", "exfil", lowered),
362
+ request_id=_prompt_request_id("exfil_intent", matched_text, lowered),
224
363
  request_class="exfil_intent",
225
364
  summary="Prompt includes exfiltration-oriented transfer intent.",
226
- matched_text="exfil-transfer",
365
+ matched_text=matched_text,
227
366
  severity=8,
228
367
  confidence=0.84,
229
368
  remediation=(
@@ -236,13 +375,19 @@ def extract_prompt_requests(prompt_text: str) -> list[PromptRequest]:
236
375
  ),
237
376
  )
238
377
  )
239
- if _DESTRUCTIVE_PROMPT_PATTERN.search(normalized_prompt):
378
+ destructive_match = _first_match(_DESTRUCTIVE_PROMPT_PATTERNS, normalized_prompt)
379
+ if destructive_match is not None:
380
+ matched_text = destructive_match.group(0).strip()
240
381
  requests.append(
241
382
  PromptRequest(
242
- request_id=_prompt_request_id("destructive_intent", "destructive", lowered),
383
+ request_id=_prompt_request_id(
384
+ "destructive_intent",
385
+ matched_text,
386
+ lowered,
387
+ ),
243
388
  request_class="destructive_intent",
244
389
  summary="Prompt includes destructive filesystem mutation intent.",
245
- matched_text="destructive-operation",
390
+ matched_text=matched_text,
246
391
  severity=8,
247
392
  confidence=0.87,
248
393
  remediation=(
@@ -259,13 +404,19 @@ def extract_prompt_requests(prompt_text: str) -> list[PromptRequest]:
259
404
  ),
260
405
  )
261
406
  )
262
- if _SUBPROCESS_PROMPT_PATTERN.search(normalized_prompt):
407
+ subprocess_match = _first_match(_SUBPROCESS_PROMPT_PATTERNS, normalized_prompt)
408
+ if subprocess_match is not None:
409
+ matched_text = subprocess_match.group(0).strip()
263
410
  requests.append(
264
411
  PromptRequest(
265
- request_id=_prompt_request_id("subprocess_intent", "subprocess", lowered),
412
+ request_id=_prompt_request_id(
413
+ "subprocess_intent",
414
+ matched_text,
415
+ lowered,
416
+ ),
266
417
  request_class="subprocess_intent",
267
418
  summary="Prompt asks for subprocess or shell-wrapper execution.",
268
- matched_text="subprocess-shell",
419
+ matched_text=matched_text,
269
420
  severity=7,
270
421
  confidence=0.8,
271
422
  remediation=(
@@ -377,13 +528,7 @@ def _prompt_policy_path(detection: HarnessDetection, context: HarnessContext) ->
377
528
  return candidate
378
529
  if config_candidates:
379
530
  return Path(config_candidates[0])
380
- if detection.harness == "opencode":
381
- if context.workspace_dir is not None:
382
- return context.workspace_dir / "opencode.json"
383
- return context.home_dir / ".config" / "opencode" / "opencode.json"
384
- if context.workspace_dir is not None:
385
- return context.workspace_dir / ".codex" / "config.toml"
386
- return context.home_dir / ".codex" / "config.toml"
531
+ return get_adapter(detection.harness).policy_path(context)
387
532
 
388
533
 
389
534
  def _prompt_config_candidates(detection: HarnessDetection, context: HarnessContext) -> tuple[str, ...]:
@@ -1,3 +1,3 @@
1
1
  """Single source of truth for tool version."""
2
2
 
3
- __version__ = "2.0.70"
3
+ __version__ = "2.0.71"
@@ -371,7 +371,7 @@ def test_claude_daemon_hook_command_survives_shell_execution(tmp_path):
371
371
 
372
372
  assert result.returncode == 0
373
373
  assert result.stderr == ""
374
- assert result.stdout == ""
374
+ assert json.loads(result.stdout) == {"hookSpecificOutput": {"hookEventName": "UserPromptSubmit"}}
375
375
 
376
376
 
377
377
  def test_claude_daemon_hook_command_falls_back_without_blocking_prompt_on_daemon_miss(tmp_path):
@@ -394,7 +394,13 @@ def test_claude_daemon_hook_command_falls_back_without_blocking_prompt_on_daemon
394
394
  )
395
395
  assert result.returncode == 0
396
396
  assert result.stderr == ""
397
- assert result.stdout == ""
397
+ payload = json.loads(result.stdout)
398
+ assert payload["systemMessage"].startswith("HOL Guard intercepted this prompt")
399
+ assert payload["hookSpecificOutput"]["hookEventName"] == "UserPromptSubmit"
400
+ assert (
401
+ "HOL Guard will intercept Claude's next attempt to access local secrets"
402
+ in (payload["hookSpecificOutput"]["additionalContext"])
403
+ )
398
404
 
399
405
 
400
406
  def test_claude_daemon_hook_command_falls_back_to_native_ask_on_daemon_miss(tmp_path):
@@ -219,6 +219,7 @@ def test_copilot_install_and_uninstall_manage_inline_config_hooks_idempotently(t
219
219
  assert first_install["active"] is True
220
220
  assert second_install["active"] is True
221
221
  assert first_install["config_path"] == str(config_path)
222
+ assert len(managed_hooks["userPromptSubmitted"]) == 1
222
223
  assert len(managed_hooks["preToolUse"]) == 1
223
224
  assert len(managed_hooks["postToolUse"]) == 1
224
225
  assert len(managed_hooks["permissionRequest"]) == 1
@@ -230,8 +231,10 @@ def test_copilot_install_and_uninstall_manage_inline_config_hooks_idempotently(t
230
231
  assert "copilot" in managed_hooks["preToolUse"][0]["bash"]
231
232
  assert "--workspace" not in managed_hooks["preToolUse"][0]["bash"]
232
233
  assert "from codex_plugin_scanner.cli import main" in managed_hooks["preToolUse"][0]["powershell"]
234
+ assert "from codex_plugin_scanner.cli import main" in managed_hooks["userPromptSubmitted"][0]["bash"]
233
235
  assert managed_hooks["postToolUse"][0]["type"] == "command"
234
236
  assert "from codex_plugin_scanner.cli import main" in managed_hooks["postToolUse"][0]["bash"]
237
+ assert len(managed_workspace_hooks["userPromptSubmitted"]) == 1
235
238
  assert len(managed_workspace_hooks["preToolUse"]) == 1
236
239
  assert len(managed_workspace_hooks["postToolUse"]) == 1
237
240
  assert len(managed_workspace_hooks["permissionRequest"]) == 1