plugin-scanner 2.0.150__tar.gz → 2.0.151__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 (451) hide show
  1. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/PKG-INFO +1 -1
  2. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/pyproject.toml +1 -1
  3. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/pyproject.toml.bak +1 -1
  4. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/detectors.py +171 -0
  5. plugin_scanner-2.0.151/src/codex_plugin_scanner/guard/runtime/false_positive_rules.py +226 -0
  6. plugin_scanner-2.0.151/src/codex_plugin_scanner/guard/runtime/persistence_rules.py +188 -0
  7. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/version.py +1 -1
  8. plugin_scanner-2.0.151/tests/test_guard_detector_fp.py +427 -0
  9. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.clusterfuzzlite/Dockerfile +0 -0
  10. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.clusterfuzzlite/build.sh +0 -0
  11. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.clusterfuzzlite/project.yaml +0 -0
  12. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.clusterfuzzlite/requirements-atheris.txt +0 -0
  13. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.dockerignore +0 -0
  14. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.github/CODEOWNERS +0 -0
  15. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  16. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  17. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  18. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.github/dependabot.yml +0 -0
  19. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.github/workflows/ci.yml +0 -0
  20. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.github/workflows/codeql.yml +0 -0
  21. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.github/workflows/dependabot-uv-lock.yml +0 -0
  22. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.github/workflows/fuzz.yml +0 -0
  23. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.github/workflows/harness-smoke.yml +0 -0
  24. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.github/workflows/publish.yml +0 -0
  25. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.github/workflows/scorecard.yml +0 -0
  26. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.gitignore +0 -0
  27. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/.pre-commit-hooks.yaml +0 -0
  28. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/CONTRIBUTING.md +0 -0
  29. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/Dockerfile +0 -0
  30. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/LICENSE +0 -0
  31. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/README.md +0 -0
  32. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/SECURITY.md +0 -0
  33. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/index.html +0 -0
  34. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/package.json +0 -0
  35. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/pnpm-lock.yaml +0 -0
  36. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/public/apple-touch-icon.png +0 -0
  37. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
  38. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/public/brand/Logo_Whole.png +0 -0
  39. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/public/favicon-16x16.png +0 -0
  40. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/public/favicon-32x32.png +0 -0
  41. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/public/favicon.ico +0 -0
  42. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/app.tsx +0 -0
  43. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/approval-center-layout.test.ts +0 -0
  44. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/approval-center-layout.tsx +0 -0
  45. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/approval-center-primitives.tsx +0 -0
  46. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/approval-center-review-cards.tsx +0 -0
  47. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/approval-center-utils.ts +0 -0
  48. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/data-flow-evidence-card.tsx +0 -0
  49. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/fleet-workspace.tsx +0 -0
  50. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/guard-api.test.ts +0 -0
  51. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/guard-api.ts +0 -0
  52. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/guard-demo.ts +0 -0
  53. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/guard-types.ts +0 -0
  54. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/home-dashboard.tsx +0 -0
  55. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/main.tsx +0 -0
  56. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/queue-chip-filter.tsx +0 -0
  57. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/queue-state.test.ts +0 -0
  58. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/queue-state.ts +0 -0
  59. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/receipts-workspace.test.ts +0 -0
  60. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/receipts-workspace.tsx +0 -0
  61. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/risk-signal-cards.test.ts +0 -0
  62. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/risk-signal-cards.tsx +0 -0
  63. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/runtime-overview.test.ts +0 -0
  64. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/runtime-overview.tsx +0 -0
  65. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/scanner-evidence-badge.tsx +0 -0
  66. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/settings-workspace.test.ts +0 -0
  67. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/settings-workspace.tsx +0 -0
  68. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/styles.css +0 -0
  69. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/vite-env.d.ts +0 -0
  70. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/src/watched-app-card.tsx +0 -0
  71. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/tsconfig.json +0 -0
  72. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/dashboard/vite.config.ts +0 -0
  73. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/docker-requirements.txt +0 -0
  74. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/docs/guard/approval-audit.md +0 -0
  75. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/docs/guard/architecture.md +0 -0
  76. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/docs/guard/get-started.md +0 -0
  77. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/docs/guard/harness-support.md +0 -0
  78. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/docs/guard/local-vs-cloud.md +0 -0
  79. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/docs/guard/release-checklist.md +0 -0
  80. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/docs/guard/release-notes.md +0 -0
  81. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/docs/guard/smoke-tests.md +0 -0
  82. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/docs/guard/testing-matrix.md +0 -0
  83. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/docs/trust/mcp-trust-draft.md +0 -0
  84. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/docs/trust/plugin-trust-draft.md +0 -0
  85. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/docs/trust/skill-trust-local.md +0 -0
  86. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/fuzzers/manifest_fuzzer.py +0 -0
  87. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/requirements.txt +0 -0
  88. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/schemas/plugin-quality.v1.json +0 -0
  89. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/schemas/scan-result.v1.json +0 -0
  90. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/schemas/verify-result.v1.json +0 -0
  91. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/__init__.py +0 -0
  92. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/action_runner.py +0 -0
  93. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/argparse_utils.py +0 -0
  94. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/checks/__init__.py +0 -0
  95. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
  96. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/checks/claude.py +0 -0
  97. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
  98. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
  99. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/checks/gemini.py +0 -0
  100. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/checks/manifest.py +0 -0
  101. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
  102. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
  103. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
  104. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/checks/opencode.py +0 -0
  105. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
  106. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/checks/security.py +0 -0
  107. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
  108. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/cli.py +0 -0
  109. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/cli_ui.py +0 -0
  110. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/config.py +0 -0
  111. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
  112. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
  113. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
  114. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
  115. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
  116. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
  117. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
  118. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
  119. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
  120. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/github_reporting.py +0 -0
  121. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/__init__.py +0 -0
  122. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/access_graph_events.py +0 -0
  123. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
  124. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
  125. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
  126. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
  127. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +0 -0
  128. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
  129. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/adapters/contracts.py +0 -0
  130. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
  131. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
  132. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
  133. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
  134. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
  135. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
  136. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
  137. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
  138. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
  139. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
  140. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
  141. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/approvals.py +0 -0
  142. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
  143. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
  144. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
  145. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
  146. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
  147. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/cli/commands.py +0 -0
  148. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
  149. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
  150. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
  151. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
  152. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
  153. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
  154. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
  155. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/config.py +0 -0
  156. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
  157. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
  158. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
  159. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
  160. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
  161. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
  162. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
  163. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
  164. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
  165. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
  166. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
  167. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
  168. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
  169. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
  170. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
  171. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
  172. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/incident.py +0 -0
  173. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/launcher.py +0 -0
  174. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
  175. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/models.py +0 -0
  176. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
  177. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
  178. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/protect.py +0 -0
  179. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
  180. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
  181. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
  182. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
  183. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
  184. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
  185. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/redaction.py +0 -0
  186. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/risk.py +0 -0
  187. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
  188. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/action_identity.py +0 -0
  189. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
  190. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/advisory_escalation.py +0 -0
  191. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/advisory_matchers.py +0 -0
  192. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/cisco_evidence.py +0 -0
  193. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/cisco_preflight.py +0 -0
  194. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/data_flow.py +0 -0
  195. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/data_flow_rules.py +0 -0
  196. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/data_flow_variables.py +0 -0
  197. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
  198. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/mcp_protection.py +0 -0
  199. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/prompt_injection.py +0 -0
  200. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
  201. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/safe_decode.py +0 -0
  202. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/sandbox.py +0 -0
  203. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/scanner_cache.py +0 -0
  204. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
  205. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/secret_sensitivity.py +0 -0
  206. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/secret_sources.py +0 -0
  207. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/shell_commands.py +0 -0
  208. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
  209. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/skill_protection.py +0 -0
  210. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/supply_chain.py +0 -0
  211. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
  212. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/temp_files.py +0 -0
  213. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/runtime/threat_intel.py +0 -0
  214. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
  215. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
  216. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
  217. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
  218. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/shims.py +0 -0
  219. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/store.py +0 -0
  220. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
  221. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
  222. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/store_evidence.py +0 -0
  223. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/store_threat_intel.py +0 -0
  224. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/guard/types.py +0 -0
  225. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
  226. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
  227. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
  228. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/lint_fixes.py +0 -0
  229. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/marketplace_support.py +0 -0
  230. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/models.py +0 -0
  231. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/path_support.py +0 -0
  232. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/policy.py +0 -0
  233. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/quality_artifact.py +0 -0
  234. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/repo_detect.py +0 -0
  235. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/reporting.py +0 -0
  236. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/rules/__init__.py +0 -0
  237. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/rules/registry.py +0 -0
  238. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/rules/specs.py +0 -0
  239. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/scanner.py +0 -0
  240. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/submission.py +0 -0
  241. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/suppressions.py +0 -0
  242. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
  243. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/trust_helpers.py +0 -0
  244. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
  245. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/trust_models.py +0 -0
  246. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
  247. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/trust_scoring.py +0 -0
  248. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
  249. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/trust_specs.py +0 -0
  250. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/src/codex_plugin_scanner/verification.py +0 -0
  251. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/__init__.py +0 -0
  252. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/conftest.py +0 -0
  253. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/__init__.py +0 -0
  254. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
  255. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/bad-plugin/.mcp.json +0 -0
  256. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/bad-plugin/secrets.js +0 -0
  257. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
  258. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
  259. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/claude-plugin-good/README.md +0 -0
  260. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
  261. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
  262. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
  263. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/code-quality-bad/evil.js +0 -0
  264. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/code-quality-bad/inject.js +0 -0
  265. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
  266. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
  267. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/gemini-extension-good/README.md +0 -0
  268. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
  269. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
  270. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
  271. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
  272. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/good-plugin/.codexignore +0 -0
  273. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/good-plugin/LICENSE +0 -0
  274. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/good-plugin/README.md +0 -0
  275. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/good-plugin/SECURITY.md +0 -0
  276. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
  277. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
  278. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
  279. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
  280. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
  281. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/README.md +0 -0
  282. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/benign-docs-fake-token.py +0 -0
  283. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/benign-health-endpoint.py +0 -0
  284. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/benign-nvmrc-fake-creds.py +0 -0
  285. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/benign-source-search.py +0 -0
  286. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/canary-exfil-encoded.py +0 -0
  287. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/canary-exfil.py +0 -0
  288. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/expected-decisions.json +0 -0
  289. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/malicious-dockerfile.txt +0 -0
  290. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/malicious-encoded-shell-exfil.py +0 -0
  291. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/malicious-github-action.yml +0 -0
  292. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/malicious-mcp-delete.md +0 -0
  293. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/malicious-mcp-secret-read.md +0 -0
  294. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/malicious-mcp-skill-exfil.md +0 -0
  295. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/malicious-npm-postinstall.js +0 -0
  296. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/malicious-prompt-env-read.md +0 -0
  297. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/malicious-prompt-guard-bypass.md +0 -0
  298. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/malicious-prompt-npmrc-read.md +0 -0
  299. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/malicious-python-setup.py +0 -0
  300. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/guard-red-team/smoke-evidence-template.json +0 -0
  301. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
  302. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
  303. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
  304. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
  305. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
  306. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
  307. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
  308. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
  309. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
  310. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
  311. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
  312. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
  313. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
  314. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
  315. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/mcp-canary-server.py +0 -0
  316. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
  317. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
  318. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/mit-license/LICENSE +0 -0
  319. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
  320. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
  321. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
  322. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
  323. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
  324. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
  325. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
  326. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
  327. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
  328. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
  329. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
  330. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
  331. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
  332. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
  333. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
  334. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
  335. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
  336. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
  337. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/opencode-good/LICENSE +0 -0
  338. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/opencode-good/README.md +0 -0
  339. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/opencode-good/SECURITY.md +0 -0
  340. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
  341. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
  342. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
  343. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
  344. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/supply-chain/benign-npm-package.json +0 -0
  345. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/supply-chain/benign-pnpm-package.json +0 -0
  346. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/supply-chain/benign-pyproject.toml +0 -0
  347. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/supply-chain/malicious-Dockerfile +0 -0
  348. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/supply-chain/malicious-action.yml +0 -0
  349. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/supply-chain/malicious-npm-package.json +0 -0
  350. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/supply-chain/malicious-setup.py +0 -0
  351. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
  352. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
  353. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/fixtures/with-marketplace/marketplace.json +0 -0
  354. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test-trust-scoring.py +0 -0
  355. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test-trust-specs.py +0 -0
  356. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_action_runner.py +0 -0
  357. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_best_practices.py +0 -0
  358. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_cisco_install_surfaces.py +0 -0
  359. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_cli.py +0 -0
  360. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_code_quality.py +0 -0
  361. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_config.py +0 -0
  362. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_coverage_remaining.py +0 -0
  363. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_ecosystems.py +0 -0
  364. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_edge_cases.py +0 -0
  365. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_final_coverage.py +0 -0
  366. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_access_graph.py +0 -0
  367. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_action_identity.py +0 -0
  368. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_advisory_escalation.py +0 -0
  369. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_approval_continuity.py +0 -0
  370. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_approval_copy_commands.py +0 -0
  371. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_approval_store_dedup.py +0 -0
  372. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_approval_store_scale.py +0 -0
  373. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_approvals.py +0 -0
  374. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_bootstrap.py +0 -0
  375. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_canary_fixtures.py +0 -0
  376. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_capabilities.py +0 -0
  377. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_cisco_evidence.py +0 -0
  378. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_cisco_runtime_cli.py +0 -0
  379. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_claude_adapter.py +0 -0
  380. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_cli.py +0 -0
  381. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_cloud_local_sync.py +0 -0
  382. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_codex_e2e.py +0 -0
  383. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_codex_install.py +0 -0
  384. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_codex_proxy.py +0 -0
  385. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_config_paths.py +0 -0
  386. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_connect_flow.py +0 -0
  387. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_consumer_mode.py +0 -0
  388. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_copilot_adapter.py +0 -0
  389. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_copilot_proxy.py +0 -0
  390. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_daemon_manager.py +0 -0
  391. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_daemon_perf.py +0 -0
  392. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_daemon_repair_perf.py +0 -0
  393. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_data_flow.py +0 -0
  394. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_decision_propagation.py +0 -0
  395. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_event_schema_v1.py +0 -0
  396. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_events.py +0 -0
  397. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_evidence_store.py +0 -0
  398. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_harness_contracts.py +0 -0
  399. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_harness_setup.py +0 -0
  400. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_harness_smoke.py +0 -0
  401. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_launch_env.py +0 -0
  402. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_mcp_protection.py +0 -0
  403. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_opencode_proxy.py +0 -0
  404. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_policy_dedup.py +0 -0
  405. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_product_flow.py +0 -0
  406. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_prompt_injection.py +0 -0
  407. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_protect.py +0 -0
  408. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_queue_api_contract.py +0 -0
  409. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_queue_contract.py +0 -0
  410. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_red_team.py +0 -0
  411. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_render.py +0 -0
  412. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_resolution_copy.py +0 -0
  413. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_risk.py +0 -0
  414. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_runtime.py +0 -0
  415. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_runtime_action_harnesses.py +0 -0
  416. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_runtime_actions.py +0 -0
  417. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_runtime_decisions.py +0 -0
  418. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_runtime_detectors.py +0 -0
  419. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_runtime_signals.py +0 -0
  420. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_safe_decode.py +0 -0
  421. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_sandbox.py +0 -0
  422. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_skill_protection.py +0 -0
  423. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_store_migrations.py +0 -0
  424. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_supply_chain.py +0 -0
  425. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_surface_server.py +0 -0
  426. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_threat_intel.py +0 -0
  427. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_verdicts.py +0 -0
  428. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_guard_web_recovery.py +0 -0
  429. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_hermes_adapter.py +0 -0
  430. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_integration.py +0 -0
  431. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_lint_fixes.py +0 -0
  432. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_live_cisco_smoke.py +0 -0
  433. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_manifest.py +0 -0
  434. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_marketplace.py +0 -0
  435. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_mcp_security.py +0 -0
  436. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_openclaw_adapter.py +0 -0
  437. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_operational_security.py +0 -0
  438. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_policy.py +0 -0
  439. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_quality_artifact.py +0 -0
  440. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_rule_registry.py +0 -0
  441. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_scanner.py +0 -0
  442. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_schema_contracts.py +0 -0
  443. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_security.py +0 -0
  444. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_security_ops.py +0 -0
  445. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_skill_security.py +0 -0
  446. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_submission.py +0 -0
  447. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_trust_scoring.py +0 -0
  448. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_trust_specs.py +0 -0
  449. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_verification.py +0 -0
  450. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/tests/test_versioning.py +0 -0
  451. {plugin_scanner-2.0.150 → plugin_scanner-2.0.151}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 2.0.150
3
+ Version: 2.0.151
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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "plugin-scanner"
7
- version = "2.0.150"
7
+ version = "2.0.151"
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.150"
7
+ version = "2.0.151"
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"
@@ -12,6 +12,14 @@ from codex_plugin_scanner.guard.config import GuardConfig
12
12
  from codex_plugin_scanner.guard.runtime.actions import GuardActionEnvelope
13
13
  from codex_plugin_scanner.guard.runtime.cisco_preflight import CiscoMcpPreflightDetector, CiscoSkillPreflightDetector
14
14
  from codex_plugin_scanner.guard.runtime.data_flow_rules import detect_data_flow_exfiltration
15
+ from codex_plugin_scanner.guard.runtime.false_positive_rules import (
16
+ classify_docs_example_source,
17
+ classify_health_endpoint_fetch,
18
+ classify_package_metadata_access,
19
+ classify_source_search_command,
20
+ classify_version_file_access,
21
+ )
22
+ from codex_plugin_scanner.guard.runtime.persistence_rules import detect_persistence_mechanisms
15
23
  from codex_plugin_scanner.guard.runtime.prompt_injection import detect_prompt_injection_requests
16
24
  from codex_plugin_scanner.guard.runtime.safe_decode import decode_layers
17
25
  from codex_plugin_scanner.guard.runtime.secret_sensitivity import SecretPathMatch, classify_secret_path
@@ -286,6 +294,163 @@ class SafeDecodeDetector:
286
294
  return tuple(signals)
287
295
 
288
296
 
297
+ class FalsePositiveSuppressorDetector:
298
+ """Detects patterns that are commonly benign, emitting advisory false_positive signals.
299
+
300
+ These signals do not directly change policy action but provide hints that
301
+ policy composition rules and operators can use to reduce unnecessary blocks.
302
+ """
303
+
304
+ detector_id = "false_positive.suppressor"
305
+ categories: tuple[RiskSignalCategory, ...] = ("false_positive",)
306
+
307
+ def detect(self, action: GuardActionEnvelope, context: DetectorContext) -> tuple[RiskSignalV2, ...]:
308
+ del context
309
+ signals: list[RiskSignalV2] = []
310
+
311
+ if action.action_type == "shell_command" and action.command is not None:
312
+ classification = classify_source_search_command(action.command)
313
+ if classification.is_source_search:
314
+ signals.append(
315
+ RiskSignalV2(
316
+ signal_id=f"fp:source-search:{classification.tool}",
317
+ category="false_positive",
318
+ severity="info",
319
+ confidence="strong",
320
+ detector=self.detector_id,
321
+ title="Read-only code or filesystem search",
322
+ plain_reason=(
323
+ f"This command uses '{classification.tool}' to search code or the filesystem "
324
+ "and does not access secret files or pipe output to the network."
325
+ ),
326
+ technical_detail=classification.reason,
327
+ evidence_ref="command",
328
+ redaction_level="none",
329
+ false_positive_hint=None,
330
+ advisory_id=None,
331
+ )
332
+ )
333
+
334
+ if classify_health_endpoint_fetch(action.command):
335
+ signals.append(
336
+ RiskSignalV2(
337
+ signal_id="fp:health-endpoint-fetch",
338
+ category="false_positive",
339
+ severity="info",
340
+ confidence="strong",
341
+ detector=self.detector_id,
342
+ title="Localhost health or readiness check",
343
+ plain_reason=(
344
+ "This command fetches a localhost health or readiness endpoint,"
345
+ " which is a normal development pattern."
346
+ ),
347
+ technical_detail="matched localhost health endpoint pattern",
348
+ evidence_ref="command",
349
+ redaction_level="none",
350
+ false_positive_hint=None,
351
+ advisory_id=None,
352
+ )
353
+ )
354
+
355
+ if action.action_type == "file_read" and action.target_paths:
356
+ if classify_version_file_access(list(action.target_paths)):
357
+ signals.append(
358
+ RiskSignalV2(
359
+ signal_id="fp:version-file-access",
360
+ category="false_positive",
361
+ severity="info",
362
+ confidence="strong",
363
+ detector=self.detector_id,
364
+ title="Version pin file access",
365
+ plain_reason=(
366
+ "Reading a version pin file (.nvmrc, .python-version, etc.) is a normal"
367
+ " toolchain operation with no sensitive data."
368
+ ),
369
+ technical_detail="matched version pin file pattern",
370
+ evidence_ref="target_paths",
371
+ redaction_level="none",
372
+ false_positive_hint=None,
373
+ advisory_id=None,
374
+ )
375
+ )
376
+
377
+ if classify_package_metadata_access(list(action.target_paths)):
378
+ signals.append(
379
+ RiskSignalV2(
380
+ signal_id="fp:package-metadata-access",
381
+ category="false_positive",
382
+ severity="info",
383
+ confidence="strong",
384
+ detector=self.detector_id,
385
+ title="Package manifest or lock file access",
386
+ plain_reason=(
387
+ "Reading package.json, requirements.txt, or similar manifests is a normal"
388
+ " dependency management operation."
389
+ ),
390
+ technical_detail="matched package metadata file pattern",
391
+ evidence_ref="target_paths",
392
+ redaction_level="none",
393
+ false_positive_hint=None,
394
+ advisory_id=None,
395
+ )
396
+ )
397
+
398
+ for path in action.target_paths:
399
+ if classify_docs_example_source(path):
400
+ signals.append(
401
+ RiskSignalV2(
402
+ signal_id=f"fp:docs-example-source:{path[:40]}",
403
+ category="false_positive",
404
+ severity="info",
405
+ confidence="strong",
406
+ detector=self.detector_id,
407
+ title="Access to docs or example file",
408
+ plain_reason=(
409
+ "The file path points to documentation, examples, or fixture data,"
410
+ " which rarely contains real credentials or sensitive content."
411
+ ),
412
+ technical_detail=f"matched docs/example path: {path}",
413
+ evidence_ref="target_paths",
414
+ redaction_level="none",
415
+ false_positive_hint=None,
416
+ advisory_id=None,
417
+ )
418
+ )
419
+ break
420
+
421
+ return tuple(signals)
422
+
423
+
424
+ class PersistenceDetector:
425
+ """Detects commands that install persistence mechanisms on the host system."""
426
+
427
+ detector_id = "persistence.mechanism"
428
+ categories: tuple[RiskSignalCategory, ...] = ("persistence",)
429
+
430
+ def detect(self, action: GuardActionEnvelope, context: DetectorContext) -> tuple[RiskSignalV2, ...]:
431
+ del context
432
+ if action.action_type != "shell_command" or action.command is None:
433
+ return ()
434
+ matches = detect_persistence_mechanisms(action.command)
435
+ return tuple(
436
+ RiskSignalV2(
437
+ signal_id=f"persistence:{match.mechanism}",
438
+ category="persistence",
439
+ severity="high",
440
+ confidence="moderate",
441
+ detector=self.detector_id,
442
+ title=f"Persistence via {match.mechanism.replace('_', ' ')}",
443
+ plain_reason=match.plain_reason,
444
+ technical_detail=f"mechanism: {match.mechanism}",
445
+ evidence_ref="command",
446
+ redaction_level="summary",
447
+ false_positive_hint=match.false_positive_hint,
448
+ advisory_id=None,
449
+ )
450
+ for match in matches
451
+ )
452
+
453
+
289
454
  def register_default_detectors() -> tuple[GuardDetector, ...]:
290
455
  """Return the default ordered detector list.
291
456
 
@@ -293,11 +458,17 @@ def register_default_detectors() -> tuple[GuardDetector, ...]:
293
458
  before native data-flow and prompt detectors evaluate the same action.
294
459
  This ordering is intentional: scanner evidence can influence policy before
295
460
  runtime detectors produce additional signals.
461
+
462
+ FalsePositiveSuppressorDetector runs early to annotate benign patterns
463
+ before risk detectors evaluate the same action, so policy resolution can
464
+ factor in FP signals when composing the final action.
296
465
  """
297
466
  return (
298
467
  CiscoMcpPreflightDetector(),
299
468
  CiscoSkillPreflightDetector(),
469
+ FalsePositiveSuppressorDetector(),
300
470
  DataFlowExfiltrationDetector(),
471
+ PersistenceDetector(),
301
472
  PromptInjectionDetector(),
302
473
  SafeDecodeDetector(),
303
474
  SecretPathDetector(),
@@ -0,0 +1,226 @@
1
+ """False-positive classification rules for Guard runtime detectors."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from collections.abc import Sequence
7
+ from dataclasses import dataclass
8
+
9
+ _SOURCE_SEARCH_TOOLS = frozenset(
10
+ {
11
+ "rg",
12
+ "ripgrep",
13
+ "grep",
14
+ "egrep",
15
+ "fgrep",
16
+ "fd",
17
+ "find",
18
+ }
19
+ )
20
+
21
+ _READ_ONLY_INLINE_TOOLS = frozenset({"jq", "yq", "awk", "sed"})
22
+
23
+ _SECRET_FILE_NAMES = re.compile(
24
+ r"(?<![A-Za-z0-9_.-])"
25
+ r"(?:\.env(?:\.[A-Za-z0-9_-]+)?|\.npmrc|\.pypirc|\.netrc|\.git-credentials"
26
+ r"|id_rsa|id_ed25519|id_ecdsa|credentials|wallet\.key|private[_-]?key\.pem|terraform\.tfvars)"
27
+ r"(?![A-Za-z0-9_.-])",
28
+ re.IGNORECASE,
29
+ )
30
+
31
+ _PIPE_TO_EXFIL = re.compile(
32
+ r"[|;]\s*(?:curl|wget|nc|ncat|netcat|scp|rsync|aws\s+s3|gsutil|gcloud)\b",
33
+ re.IGNORECASE,
34
+ )
35
+
36
+ _FIND_MUTATING_FLAGS = re.compile(
37
+ r"(?:^|[\s])-(?:delete|exec\s+rm|exec\s+unlink|exec\s+shred|execdir\s+rm)\b"
38
+ r"|(?:^|[\s])-exec\s+\S+[^\r\n;&|]{0,100}\{.*\}\s*(?:\\;|;|\+)",
39
+ re.IGNORECASE,
40
+ )
41
+
42
+ _OUTPUT_REDIRECT_TO_EXFIL = re.compile(
43
+ r">\s*(?:/proc/\S+|/dev/tcp/|/dev/udp/)",
44
+ re.IGNORECASE,
45
+ )
46
+
47
+ _CLIPBOARD_PIPE = re.compile(
48
+ r"[|;]\s*(?:pbcopy|xclip|xsel|wl-copy|clip)\b",
49
+ re.IGNORECASE,
50
+ )
51
+
52
+ _LOCALHOST_HEALTH_PATTERN = re.compile(
53
+ r"(?:^|[\s;&|])"
54
+ r"(?:curl|wget|fetch|http\.get|requests\.get)"
55
+ r"\b[^\r\n;&|]{0,80}"
56
+ r"(?:localhost|127\.0\.0\.1|::1|\[::1\]|0\.0\.0\.0)"
57
+ r"(?::\d{1,5})?"
58
+ r"(?:/(?:healthz?|readiness|ready|liveness|live|ping|status|metrics|info|version))?"
59
+ r"(?:\s|$|[;&|'\"])",
60
+ re.IGNORECASE,
61
+ )
62
+
63
+ _FAKE_CREDENTIAL_PATTERNS: tuple[re.Pattern[str], ...] = (
64
+ re.compile(
65
+ r"(?i)(?:your[_-]?api[_-]?key|example[_-]?token|fake[_-]?(?:secret|token|key|credential)|"
66
+ r"placeholder|<[A-Z_]{2,}(?:[_-][A-Z]+)*>|x{4,}|\b1234(?:5678)?\b|test[_-]?token|dummy[_-]?(?:key|secret|token)|"
67
+ r"replace[_-]?me|insert[_-]?(?:your|token)|changeme|secret123|password123|"
68
+ r"\babc123\b|my[_-]?(?:secret|key|token|api[_-]?key)|sample[_-]?(?:key|token|credential))"
69
+ ),
70
+ re.compile(r"(?i)\b(?:todo|fixme|hack|stub|mock|fake|demo|sample|example)\b.*?(?:key|token|secret|credential)"),
71
+ )
72
+
73
+ _DOCS_EXAMPLE_CONTEXT = re.compile(
74
+ r"(?:README|CHANGELOG|CONTRIBUTING|SECURITY|LICENSE|NOTICE|\.md|\.rst|\.txt|\.adoc)"
75
+ r"|(?:example|demo|tutorial|sample|docs?/|documentation/|spec/|test/fixtures?/)",
76
+ re.IGNORECASE,
77
+ )
78
+
79
+ _VERSION_FILE_NAMES = re.compile(
80
+ r"(?<![A-Za-z0-9_.-])"
81
+ r"(?:\.nvmrc|\.node-version|\.python-version|\.ruby-version|\.tool-versions|\.java-version)"
82
+ r"(?![A-Za-z0-9_.-])",
83
+ re.IGNORECASE,
84
+ )
85
+
86
+ _PACKAGE_METADATA_FILES = re.compile(
87
+ r"(?<![A-Za-z0-9_.-])"
88
+ r"(?:package\.json|package-lock\.json|yarn\.lock|pnpm-lock\.yaml|"
89
+ r"requirements\.txt|setup\.py|setup\.cfg|pyproject\.toml|Pipfile(?:\.lock)?|"
90
+ r"go\.(?:mod|sum)|Cargo\.(?:toml|lock)|composer\.json|Gemfile(?:\.lock)?)"
91
+ r"(?![A-Za-z0-9_.-])",
92
+ re.IGNORECASE,
93
+ )
94
+
95
+
96
+ @dataclass(frozen=True, slots=True)
97
+ class SourceSearchClassification:
98
+ """Result of classifying a shell command as a read-only source search."""
99
+
100
+ is_source_search: bool
101
+ reason: str | None
102
+ tool: str | None
103
+
104
+
105
+ def classify_source_search_command(command: str) -> SourceSearchClassification:
106
+ """Return whether *command* is a benign read-only code/filesystem search.
107
+
108
+ A source search is a command that:
109
+ - Uses known search tools (rg, grep, fd, find)
110
+ - Does not target actual secret files
111
+ - Does not pipe output to network, clipboard, or other exfiltration sinks
112
+ - Does not use read-inline tools (jq, awk, sed) to extract and relay data
113
+ """
114
+ stripped = command.strip()
115
+ if not stripped:
116
+ return SourceSearchClassification(is_source_search=False, reason=None, tool=None)
117
+
118
+ parts = stripped.split()
119
+ if not parts:
120
+ return SourceSearchClassification(is_source_search=False, reason=None, tool=None)
121
+
122
+ tool = _leading_tool(parts)
123
+ if tool is None:
124
+ return SourceSearchClassification(is_source_search=False, reason=None, tool=None)
125
+
126
+ if _PIPE_TO_EXFIL.search(command):
127
+ return SourceSearchClassification(
128
+ is_source_search=False,
129
+ reason="piped to network tool",
130
+ tool=tool,
131
+ )
132
+
133
+ if _OUTPUT_REDIRECT_TO_EXFIL.search(command):
134
+ return SourceSearchClassification(
135
+ is_source_search=False,
136
+ reason="output redirected to device/proc",
137
+ tool=tool,
138
+ )
139
+
140
+ if _CLIPBOARD_PIPE.search(command):
141
+ return SourceSearchClassification(
142
+ is_source_search=False,
143
+ reason="piped to clipboard",
144
+ tool=tool,
145
+ )
146
+
147
+ if _SECRET_FILE_NAMES.search(command):
148
+ return SourceSearchClassification(
149
+ is_source_search=False,
150
+ reason="targets secret file",
151
+ tool=tool,
152
+ )
153
+
154
+ if tool == "find" and _FIND_MUTATING_FLAGS.search(command):
155
+ return SourceSearchClassification(
156
+ is_source_search=False,
157
+ reason="find with mutating action flag",
158
+ tool=tool,
159
+ )
160
+
161
+ return SourceSearchClassification(
162
+ is_source_search=True,
163
+ reason="read-only code/filesystem search",
164
+ tool=tool,
165
+ )
166
+
167
+
168
+ def classify_fake_credential_pattern(text: str) -> bool:
169
+ """Return True if *text* matches known fake/example/placeholder credential patterns."""
170
+ return any(pattern.search(text) for pattern in _FAKE_CREDENTIAL_PATTERNS)
171
+
172
+
173
+ def classify_health_endpoint_fetch(command: str) -> bool:
174
+ """Return True if *command* is a benign localhost health/readiness check."""
175
+ return bool(_LOCALHOST_HEALTH_PATTERN.search(command))
176
+
177
+
178
+ def classify_docs_example_source(source_hint: str) -> bool:
179
+ """Return True if *source_hint* (path or context label) is a docs/example location."""
180
+ return bool(_DOCS_EXAMPLE_CONTEXT.search(source_hint))
181
+
182
+
183
+ def classify_version_file_access(paths: Sequence[str]) -> bool:
184
+ """Return True if all *paths* are benign version-pin files with no sensitive data."""
185
+ if not paths:
186
+ return False
187
+ return all(_VERSION_FILE_NAMES.search(p) for p in paths)
188
+
189
+
190
+ def classify_package_metadata_access(paths: Sequence[str]) -> bool:
191
+ """Return True if all *paths* are package manifest/lock files (no secrets in them)."""
192
+ if not paths:
193
+ return False
194
+ return all(_PACKAGE_METADATA_FILES.search(p) for p in paths)
195
+
196
+
197
+ def _leading_tool(parts: list[str]) -> str | None:
198
+ """Return the base command name if it is a known source-search tool, else None."""
199
+ if not parts:
200
+ return None
201
+ base = _strip_path_prefix(parts[0]).lower()
202
+ if base in _SOURCE_SEARCH_TOOLS:
203
+ return base
204
+ if base in _READ_ONLY_INLINE_TOOLS and _has_no_write_flags(parts):
205
+ return base
206
+ return None
207
+
208
+
209
+ def _strip_path_prefix(token: str) -> str:
210
+ return token.rsplit("/", 1)[-1].rsplit("\\", 1)[-1]
211
+
212
+
213
+ def _has_no_write_flags(parts: list[str]) -> bool:
214
+ """Return True if awk/sed/jq are used read-only (no in-place or write flags).
215
+
216
+ Handles suffixed in-place forms (``-i.bak``, ``-i ''``) and clustered
217
+ short options that include ``i`` (e.g. ``-ni``).
218
+ """
219
+ write_flags = {"--in-place", "-w", "--write"}
220
+ for p in parts[1:]:
221
+ tok = p.split("=")[0]
222
+ if tok in write_flags:
223
+ return False
224
+ if len(tok) >= 2 and tok[0] == "-" and tok[1] != "-" and "i" in tok[1:]:
225
+ return False
226
+ return True
@@ -0,0 +1,188 @@
1
+ """Persistence mechanism detection rules for Guard runtime shell actions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from dataclasses import dataclass
7
+
8
+ _GIT_HOOK_PATHS = re.compile(
9
+ r"(?<![A-Za-z0-9_.-])"
10
+ r"\.git/hooks/(?:pre-commit|post-commit|pre-push|post-merge|post-checkout|"
11
+ r"pre-receive|post-receive|update|commit-msg|prepare-commit-msg)"
12
+ r"(?![A-Za-z0-9_.-])",
13
+ re.IGNORECASE,
14
+ )
15
+
16
+ _CRON_WRITE_PATTERN = re.compile(
17
+ r"(?:^|[\s;&|])"
18
+ r"(?:"
19
+ r"crontab\s+(?:-u\s+\S+\s+)?(?:-e\b|-\s*$|[^-\r\n\s][^\r\n;&|]{0,100})|"
20
+ r"crontab\s*<\s*\S+|"
21
+ r"(?:echo|printf|cat|tee)\b[^\r\n;&|]{0,200}(?:>|\|\s*tee)\s*/(?:var/spool/cron|etc/cron[^'\"]*?)"
22
+ r")",
23
+ re.IGNORECASE,
24
+ )
25
+
26
+ _LAUNCH_AGENT_PATHS = re.compile(
27
+ r"(?<![A-Za-z0-9_.-])"
28
+ r"(?:~/Library/LaunchAgents/|/Library/LaunchAgents/|/Library/LaunchDaemons/|"
29
+ r"/System/Library/LaunchAgents/|/System/Library/LaunchDaemons/)"
30
+ r"[^'\"\s\\]{3,}\.plist"
31
+ r"(?![A-Za-z0-9_.-])",
32
+ re.IGNORECASE,
33
+ )
34
+
35
+ _SYSTEMD_WRITE_PATTERN = re.compile(
36
+ r"(?<![A-Za-z0-9_.-])"
37
+ r"(?:/etc/systemd/system/|/usr/lib/systemd/system/|/run/systemd/system/|"
38
+ r"~?/\.config/systemd/user/|"
39
+ r"(?:/home/[^/\s]+|\$HOME)/\.config/systemd/user/)"
40
+ r"[^'\"\s\\]{3,}\.(?:service|timer|socket|path|mount|target)"
41
+ r"(?![A-Za-z0-9_.-])",
42
+ re.IGNORECASE,
43
+ )
44
+
45
+ _VSCODE_TASKS_PATTERN = re.compile(
46
+ r"(?<![A-Za-z0-9_.-])"
47
+ r"\.vscode/(?:tasks|launch|settings)\.json"
48
+ r"(?![A-Za-z0-9_.-])",
49
+ re.IGNORECASE,
50
+ )
51
+
52
+ _REGISTRY_WRITE_PATTERN = re.compile(
53
+ r"(?:^|[\s;&|])(?:reg\s+(?:add|import|copy)|regini)\b",
54
+ re.IGNORECASE,
55
+ )
56
+
57
+ _AT_JOB_WRITE_PATTERN = re.compile(
58
+ r"(?:^|[\s;&|])"
59
+ r"(?:"
60
+ r"at\s+(?:-f\s+\S+\s+)?(?:now|midnight|noon|tomorrow|\d+(?::\d+)?(?:am|pm)?)\b|"
61
+ r"(?:echo|printf)\b[^\r\n;&|]{0,200}\|\s*at\b"
62
+ r")",
63
+ re.IGNORECASE,
64
+ )
65
+
66
+
67
+ @dataclass(frozen=True, slots=True)
68
+ class PersistenceMatch:
69
+ """Describes a detected persistence mechanism."""
70
+
71
+ mechanism: str
72
+ plain_reason: str
73
+ false_positive_hint: str
74
+
75
+
76
+ def detect_persistence_mechanisms(command: str) -> tuple[PersistenceMatch, ...]:
77
+ """Return persistence mechanism matches found in *command*."""
78
+ matches: list[PersistenceMatch] = []
79
+
80
+ if _SHELL_PROFILE_WRITE.search(command):
81
+ matches.append(
82
+ PersistenceMatch(
83
+ mechanism="shell_profile_write",
84
+ plain_reason=(
85
+ "Command writes to a shell profile or startup file, which runs on every new terminal session."
86
+ ),
87
+ false_positive_hint="Allow if this is setting up a legitimate development environment or PATH entry.",
88
+ )
89
+ )
90
+
91
+ if _GIT_HOOK_PATHS.search(command) and _is_write_operation(command):
92
+ matches.append(
93
+ PersistenceMatch(
94
+ mechanism="git_hook_write",
95
+ plain_reason="Command installs or modifies a git hook, which runs automatically on git events.",
96
+ false_positive_hint="Allow if this is installing a project-standard code quality or signing hook.",
97
+ )
98
+ )
99
+
100
+ if _CRON_WRITE_PATTERN.search(command):
101
+ matches.append(
102
+ PersistenceMatch(
103
+ mechanism="cron_write",
104
+ plain_reason=(
105
+ "Command modifies scheduled tasks (cron), allowing code to run automatically at set times."
106
+ ),
107
+ false_positive_hint="Allow if this is setting up a legitimate periodic maintenance task.",
108
+ )
109
+ )
110
+
111
+ if _LAUNCH_AGENT_PATHS.search(command) and _is_write_operation(command):
112
+ matches.append(
113
+ PersistenceMatch(
114
+ mechanism="launch_agent_write",
115
+ plain_reason=(
116
+ "Command installs a macOS Launch Agent or Daemon, which runs automatically on login or boot."
117
+ ),
118
+ false_positive_hint="Allow if this is installing a known legitimate background service.",
119
+ )
120
+ )
121
+
122
+ if _SYSTEMD_WRITE_PATTERN.search(command) and _is_write_operation(command):
123
+ matches.append(
124
+ PersistenceMatch(
125
+ mechanism="systemd_unit_write",
126
+ plain_reason="Command installs a systemd service unit, which can run automatically at boot or login.",
127
+ false_positive_hint="Allow if this is installing a known legitimate system service.",
128
+ )
129
+ )
130
+
131
+ if _VSCODE_TASKS_PATTERN.search(command) and _is_write_operation(command):
132
+ matches.append(
133
+ PersistenceMatch(
134
+ mechanism="vscode_tasks_write",
135
+ plain_reason=(
136
+ "Command modifies VS Code tasks or launch configuration, which run automatically in the IDE."
137
+ ),
138
+ false_positive_hint="Allow if this is setting up legitimate project build or debug tasks.",
139
+ )
140
+ )
141
+
142
+ if _REGISTRY_WRITE_PATTERN.search(command):
143
+ matches.append(
144
+ PersistenceMatch(
145
+ mechanism="registry_write",
146
+ plain_reason=(
147
+ "Command writes to the Windows Registry, which can configure autostart or persistent settings."
148
+ ),
149
+ false_positive_hint="Allow if this is a known legitimate software installer or configuration step.",
150
+ )
151
+ )
152
+
153
+ if _AT_JOB_WRITE_PATTERN.search(command):
154
+ matches.append(
155
+ PersistenceMatch(
156
+ mechanism="at_job_schedule",
157
+ plain_reason=(
158
+ "Command schedules a one-time deferred job via `at`,"
159
+ " which runs automatically at the specified time."
160
+ ),
161
+ false_positive_hint="Allow if this is scheduling a legitimate maintenance or notification task.",
162
+ )
163
+ )
164
+
165
+ return tuple(matches)
166
+
167
+
168
+ _SHELL_PROFILE_WRITE = re.compile(
169
+ r"(?:^|[\s;&|])"
170
+ r"(?:echo|printf|cat|tee|append|heredoc)\b[^\r\n;&|]{0,300}"
171
+ r"(?:>>|>\s*>?|\|\s*(?:tee\s+(?:-a\s+)?)?)\s*"
172
+ r"~?/?(?:"
173
+ r"\.bashrc|\.bash_profile|\.bash_login|\.profile|\.zshrc|\.zprofile|\.zlogin|"
174
+ r"\.zshenv|\.kshrc|\.config/fish/config\.fish"
175
+ r")",
176
+ re.IGNORECASE,
177
+ )
178
+
179
+
180
+ def _is_write_operation(command: str) -> bool:
181
+ """Return True if the command contains a write indicator (output redirect, tee, cp, mv, install)."""
182
+ return bool(
183
+ re.search(
184
+ r"(?:>>?|tee\b|\bcp\b|\bmv\b|\binstall\b|\bwrite\b|\bcat\s*>)",
185
+ command,
186
+ re.IGNORECASE,
187
+ )
188
+ )
@@ -1,3 +1,3 @@
1
1
  """Single source of truth for tool version."""
2
2
 
3
- __version__ = "2.0.150"
3
+ __version__ = "2.0.151"