plugin-scanner 2.0.124__tar.gz → 2.0.126__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 (382) hide show
  1. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/PKG-INFO +1 -1
  2. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/pyproject.toml +1 -1
  3. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/pyproject.toml.bak +1 -1
  4. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/config.py +1 -0
  5. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/daemon/server.py +39 -0
  6. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/store.py +7 -0
  7. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/store_approvals.py +145 -10
  8. plugin_scanner-2.0.126/src/codex_plugin_scanner/guard/store_evidence.py +217 -0
  9. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/version.py +1 -1
  10. plugin_scanner-2.0.126/tests/test_guard_approval_store_scale.py +510 -0
  11. plugin_scanner-2.0.126/tests/test_guard_evidence_store.py +286 -0
  12. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.clusterfuzzlite/Dockerfile +0 -0
  13. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.clusterfuzzlite/build.sh +0 -0
  14. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.clusterfuzzlite/project.yaml +0 -0
  15. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.clusterfuzzlite/requirements-atheris.txt +0 -0
  16. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.dockerignore +0 -0
  17. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.github/CODEOWNERS +0 -0
  18. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  19. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  20. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  21. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.github/dependabot.yml +0 -0
  22. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.github/workflows/ci.yml +0 -0
  23. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.github/workflows/codeql.yml +0 -0
  24. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.github/workflows/dependabot-uv-lock.yml +0 -0
  25. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.github/workflows/fuzz.yml +0 -0
  26. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.github/workflows/harness-smoke.yml +0 -0
  27. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.github/workflows/publish.yml +0 -0
  28. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.github/workflows/scorecard.yml +0 -0
  29. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.gitignore +0 -0
  30. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/.pre-commit-hooks.yaml +0 -0
  31. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/CONTRIBUTING.md +0 -0
  32. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/Dockerfile +0 -0
  33. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/LICENSE +0 -0
  34. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/README.md +0 -0
  35. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/SECURITY.md +0 -0
  36. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/index.html +0 -0
  37. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/package.json +0 -0
  38. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/pnpm-lock.yaml +0 -0
  39. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/public/apple-touch-icon.png +0 -0
  40. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
  41. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/public/brand/Logo_Whole.png +0 -0
  42. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/public/favicon-16x16.png +0 -0
  43. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/public/favicon-32x32.png +0 -0
  44. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/public/favicon.ico +0 -0
  45. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/src/app.tsx +0 -0
  46. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/src/approval-center-layout.tsx +0 -0
  47. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/src/approval-center-primitives.tsx +0 -0
  48. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/src/approval-center-utils.ts +0 -0
  49. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/src/data-flow-evidence-card.tsx +0 -0
  50. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/src/fleet-workspace.tsx +0 -0
  51. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/src/guard-api.test.ts +0 -0
  52. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/src/guard-api.ts +0 -0
  53. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/src/guard-demo.ts +0 -0
  54. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/src/guard-types.ts +0 -0
  55. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/src/main.tsx +0 -0
  56. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/src/receipts-workspace.tsx +0 -0
  57. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/src/runtime-overview.tsx +0 -0
  58. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/src/settings-workspace.tsx +0 -0
  59. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/src/styles.css +0 -0
  60. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/src/vite-env.d.ts +0 -0
  61. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/tsconfig.json +0 -0
  62. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/dashboard/vite.config.ts +0 -0
  63. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/docker-requirements.txt +0 -0
  64. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/docs/guard/approval-audit.md +0 -0
  65. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/docs/guard/architecture.md +0 -0
  66. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/docs/guard/get-started.md +0 -0
  67. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/docs/guard/harness-support.md +0 -0
  68. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/docs/guard/local-vs-cloud.md +0 -0
  69. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/docs/guard/testing-matrix.md +0 -0
  70. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/docs/trust/mcp-trust-draft.md +0 -0
  71. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/docs/trust/plugin-trust-draft.md +0 -0
  72. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/docs/trust/skill-trust-local.md +0 -0
  73. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/fuzzers/manifest_fuzzer.py +0 -0
  74. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/requirements.txt +0 -0
  75. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/schemas/plugin-quality.v1.json +0 -0
  76. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/schemas/scan-result.v1.json +0 -0
  77. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/schemas/verify-result.v1.json +0 -0
  78. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/__init__.py +0 -0
  79. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/action_runner.py +0 -0
  80. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/argparse_utils.py +0 -0
  81. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/checks/__init__.py +0 -0
  82. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
  83. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/checks/claude.py +0 -0
  84. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
  85. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
  86. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/checks/gemini.py +0 -0
  87. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/checks/manifest.py +0 -0
  88. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
  89. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
  90. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
  91. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/checks/opencode.py +0 -0
  92. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
  93. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/checks/security.py +0 -0
  94. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
  95. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/cli.py +0 -0
  96. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/cli_ui.py +0 -0
  97. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/config.py +0 -0
  98. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
  99. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
  100. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
  101. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
  102. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
  103. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
  104. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
  105. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
  106. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
  107. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/github_reporting.py +0 -0
  108. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/__init__.py +0 -0
  109. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/access_graph_events.py +0 -0
  110. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
  111. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
  112. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
  113. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
  114. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +0 -0
  115. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
  116. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
  117. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
  118. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
  119. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
  120. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
  121. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
  122. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
  123. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
  124. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
  125. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
  126. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
  127. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/approvals.py +0 -0
  128. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
  129. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
  130. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
  131. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
  132. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
  133. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/cli/commands.py +0 -0
  134. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
  135. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
  136. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
  137. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
  138. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
  139. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
  140. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
  141. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
  142. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
  143. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
  144. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
  145. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
  146. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
  147. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
  148. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
  149. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
  150. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
  151. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
  152. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
  153. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
  154. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
  155. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
  156. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/incident.py +0 -0
  157. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/launcher.py +0 -0
  158. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
  159. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/models.py +0 -0
  160. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
  161. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
  162. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/protect.py +0 -0
  163. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
  164. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
  165. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
  166. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
  167. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
  168. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
  169. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/redaction.py +0 -0
  170. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/risk.py +0 -0
  171. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
  172. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
  173. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/data_flow.py +0 -0
  174. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/data_flow_rules.py +0 -0
  175. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/data_flow_variables.py +0 -0
  176. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
  177. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/detectors.py +0 -0
  178. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/mcp_protection.py +0 -0
  179. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/prompt_injection.py +0 -0
  180. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
  181. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/safe_decode.py +0 -0
  182. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/sandbox.py +0 -0
  183. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
  184. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/secret_sensitivity.py +0 -0
  185. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/secret_sources.py +0 -0
  186. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/shell_commands.py +0 -0
  187. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
  188. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/skill_protection.py +0 -0
  189. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/supply_chain.py +0 -0
  190. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
  191. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/runtime/temp_files.py +0 -0
  192. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
  193. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
  194. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
  195. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
  196. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/shims.py +0 -0
  197. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
  198. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/guard/types.py +0 -0
  199. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
  200. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
  201. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
  202. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/lint_fixes.py +0 -0
  203. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/marketplace_support.py +0 -0
  204. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/models.py +0 -0
  205. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/path_support.py +0 -0
  206. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/policy.py +0 -0
  207. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/quality_artifact.py +0 -0
  208. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/repo_detect.py +0 -0
  209. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/reporting.py +0 -0
  210. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/rules/__init__.py +0 -0
  211. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/rules/registry.py +0 -0
  212. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/rules/specs.py +0 -0
  213. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/scanner.py +0 -0
  214. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/submission.py +0 -0
  215. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/suppressions.py +0 -0
  216. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
  217. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/trust_helpers.py +0 -0
  218. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
  219. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/trust_models.py +0 -0
  220. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
  221. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/trust_scoring.py +0 -0
  222. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
  223. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/trust_specs.py +0 -0
  224. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/src/codex_plugin_scanner/verification.py +0 -0
  225. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/__init__.py +0 -0
  226. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/conftest.py +0 -0
  227. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/__init__.py +0 -0
  228. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
  229. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/bad-plugin/.mcp.json +0 -0
  230. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/bad-plugin/secrets.js +0 -0
  231. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
  232. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
  233. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/claude-plugin-good/README.md +0 -0
  234. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
  235. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
  236. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
  237. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/code-quality-bad/evil.js +0 -0
  238. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/code-quality-bad/inject.js +0 -0
  239. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
  240. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
  241. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/gemini-extension-good/README.md +0 -0
  242. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
  243. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
  244. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
  245. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
  246. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/good-plugin/.codexignore +0 -0
  247. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/good-plugin/LICENSE +0 -0
  248. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/good-plugin/README.md +0 -0
  249. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/good-plugin/SECURITY.md +0 -0
  250. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
  251. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
  252. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
  253. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
  254. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
  255. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
  256. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
  257. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
  258. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
  259. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
  260. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
  261. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
  262. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
  263. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
  264. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
  265. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
  266. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
  267. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
  268. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
  269. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/mcp-canary-server.py +0 -0
  270. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
  271. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
  272. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/mit-license/LICENSE +0 -0
  273. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
  274. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
  275. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
  276. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
  277. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
  278. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
  279. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
  280. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
  281. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
  282. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
  283. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
  284. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
  285. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
  286. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
  287. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
  288. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
  289. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
  290. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
  291. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/opencode-good/LICENSE +0 -0
  292. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/opencode-good/README.md +0 -0
  293. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/opencode-good/SECURITY.md +0 -0
  294. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
  295. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
  296. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
  297. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
  298. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/supply-chain/benign-npm-package.json +0 -0
  299. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/supply-chain/benign-pnpm-package.json +0 -0
  300. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/supply-chain/benign-pyproject.toml +0 -0
  301. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/supply-chain/malicious-Dockerfile +0 -0
  302. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/supply-chain/malicious-action.yml +0 -0
  303. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/supply-chain/malicious-npm-package.json +0 -0
  304. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/supply-chain/malicious-setup.py +0 -0
  305. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
  306. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
  307. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/fixtures/with-marketplace/marketplace.json +0 -0
  308. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test-trust-scoring.py +0 -0
  309. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test-trust-specs.py +0 -0
  310. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_action_runner.py +0 -0
  311. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_best_practices.py +0 -0
  312. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_cisco_install_surfaces.py +0 -0
  313. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_cli.py +0 -0
  314. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_code_quality.py +0 -0
  315. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_config.py +0 -0
  316. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_coverage_remaining.py +0 -0
  317. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_ecosystems.py +0 -0
  318. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_edge_cases.py +0 -0
  319. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_final_coverage.py +0 -0
  320. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_access_graph.py +0 -0
  321. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_approvals.py +0 -0
  322. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_bootstrap.py +0 -0
  323. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_capabilities.py +0 -0
  324. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_claude_adapter.py +0 -0
  325. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_cli.py +0 -0
  326. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_cloud_local_sync.py +0 -0
  327. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_codex_e2e.py +0 -0
  328. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_codex_install.py +0 -0
  329. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_codex_proxy.py +0 -0
  330. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_config_paths.py +0 -0
  331. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_connect_flow.py +0 -0
  332. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_consumer_mode.py +0 -0
  333. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_copilot_adapter.py +0 -0
  334. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_copilot_proxy.py +0 -0
  335. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_daemon_manager.py +0 -0
  336. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_data_flow.py +0 -0
  337. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_event_schema_v1.py +0 -0
  338. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_events.py +0 -0
  339. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_launch_env.py +0 -0
  340. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_mcp_protection.py +0 -0
  341. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_opencode_proxy.py +0 -0
  342. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_product_flow.py +0 -0
  343. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_prompt_injection.py +0 -0
  344. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_protect.py +0 -0
  345. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_render.py +0 -0
  346. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_risk.py +0 -0
  347. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_runtime.py +0 -0
  348. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_runtime_action_harnesses.py +0 -0
  349. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_runtime_actions.py +0 -0
  350. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_runtime_decisions.py +0 -0
  351. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_runtime_detectors.py +0 -0
  352. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_runtime_signals.py +0 -0
  353. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_safe_decode.py +0 -0
  354. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_sandbox.py +0 -0
  355. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_skill_protection.py +0 -0
  356. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_store_migrations.py +0 -0
  357. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_supply_chain.py +0 -0
  358. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_surface_server.py +0 -0
  359. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_guard_verdicts.py +0 -0
  360. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_hermes_adapter.py +0 -0
  361. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_integration.py +0 -0
  362. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_lint_fixes.py +0 -0
  363. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_live_cisco_smoke.py +0 -0
  364. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_manifest.py +0 -0
  365. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_marketplace.py +0 -0
  366. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_mcp_security.py +0 -0
  367. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_openclaw_adapter.py +0 -0
  368. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_operational_security.py +0 -0
  369. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_policy.py +0 -0
  370. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_quality_artifact.py +0 -0
  371. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_rule_registry.py +0 -0
  372. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_scanner.py +0 -0
  373. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_schema_contracts.py +0 -0
  374. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_security.py +0 -0
  375. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_security_ops.py +0 -0
  376. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_skill_security.py +0 -0
  377. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_submission.py +0 -0
  378. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_trust_scoring.py +0 -0
  379. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_trust_specs.py +0 -0
  380. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_verification.py +0 -0
  381. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/tests/test_versioning.py +0 -0
  382. {plugin_scanner-2.0.124 → plugin_scanner-2.0.126}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 2.0.124
3
+ Version: 2.0.126
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.124"
7
+ version = "2.0.126"
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.124"
7
+ version = "2.0.126"
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"
@@ -254,6 +254,7 @@ class GuardConfig:
254
254
  harness_actions: dict[str, GuardAction] | None = None
255
255
  publisher_actions: dict[str, GuardAction] | None = None
256
256
  artifact_actions: dict[str, GuardAction] | None = None
257
+ evidence_retain_days: int = 90
257
258
 
258
259
  def resolve_action_override(
259
260
  self,
@@ -23,6 +23,11 @@ from ..config import editable_guard_settings, load_guard_config, update_guard_se
23
23
  from ..models import DECISION_SCOPE_VALUES, GUARD_ACTION_VALUES
24
24
  from ..runtime.surface_server import GuardSurfaceRuntime
25
25
  from ..store import GuardStore
26
+ from ..store_evidence import (
27
+ count_evidence,
28
+ export_evidence_json,
29
+ list_evidence,
30
+ )
26
31
  from .manager import (
27
32
  GUARD_DAEMON_COMPATIBILITY_VERSION,
28
33
  clear_guard_daemon_state,
@@ -182,6 +187,40 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
182
187
  {"items": store.list_policy_decisions(harness=harness if isinstance(harness, str) else None)}
183
188
  )
184
189
  return
190
+ if parsed.path == "/v1/evidence":
191
+ query = parse_qs(parsed.query)
192
+ harness_q = query.get("harness", [None])[-1]
193
+ category_q = query.get("category", [None])[-1]
194
+ severity_q = query.get("severity", [None])[-1]
195
+ before_q = query.get("before", [None])[-1]
196
+ limit_q = query.get("limit", ["100"])[-1]
197
+ try:
198
+ limit_v = min(int(limit_q), 500)
199
+ except (ValueError, TypeError):
200
+ limit_v = 100
201
+ with store._connect() as conn:
202
+ records = list_evidence(
203
+ conn,
204
+ harness=harness_q if isinstance(harness_q, str) else None,
205
+ category=category_q if isinstance(category_q, str) else None,
206
+ severity=severity_q if isinstance(severity_q, str) else None,
207
+ before_cursor=before_q if isinstance(before_q, str) else None,
208
+ limit=limit_v,
209
+ )
210
+ total = count_evidence(conn)
211
+ self._write_json({
212
+ "items": [vars(r) for r in records],
213
+ "total": total,
214
+ })
215
+ return
216
+ if parsed.path == "/v1/evidence/export":
217
+ with store._connect() as conn:
218
+ payload = export_evidence_json(conn, limit=10_000)
219
+ self.send_response(200)
220
+ self.send_header("Content-Type", "application/json")
221
+ self.end_headers()
222
+ self.wfile.write(payload.encode("utf-8"))
223
+ return
185
224
  if len(path_parts) == 4 and path_parts[:3] == ["v1", "artifacts", path_parts[2]] and path_parts[3] == "diff":
186
225
  query = parse_qs(parsed.query)
187
226
  harness = query.get("harness", [None])[-1]
@@ -71,6 +71,10 @@ from .store_connect import (
71
71
  from .store_connect import (
72
72
  mark_connect_result as persist_connect_result,
73
73
  )
74
+ from .store_evidence import (
75
+ evidence_index_statements,
76
+ evidence_schema_statement,
77
+ )
74
78
  from .types import CapabilitySet
75
79
 
76
80
  _SYNC_TOKEN_REF = "guard-cloud-token"
@@ -646,10 +650,13 @@ class GuardStore:
646
650
  connect_request_schema_statement(),
647
651
  connect_state_schema_statement(),
648
652
  approval_schema_statement(),
653
+ evidence_schema_statement(),
649
654
  )
650
655
  with self._connect() as connection:
651
656
  for statement in statements:
652
657
  connection.execute(statement)
658
+ for idx_stmt in evidence_index_statements():
659
+ connection.execute(idx_stmt)
653
660
  self._ensure_policy_column(connection, "publisher", "text")
654
661
  self._ensure_policy_column(connection, "artifact_hash", "text")
655
662
  self._ensure_policy_column(connection, "owner", "text")
@@ -175,6 +175,10 @@ def list_approval_requests(
175
175
  status: str | None = "pending",
176
176
  harness: str | None = None,
177
177
  limit: int | None = 50,
178
+ before_cursor: str | None = None,
179
+ search: str | None = None,
180
+ created_after: str | None = None,
181
+ created_before: str | None = None,
178
182
  ) -> list[dict[str, object]]:
179
183
  clauses = []
180
184
  params: list[object] = []
@@ -184,6 +188,24 @@ def list_approval_requests(
184
188
  if harness is not None:
185
189
  clauses.append("harness = ?")
186
190
  params.append(harness)
191
+ if before_cursor is not None:
192
+ clauses.append("created_at < ?")
193
+ params.append(before_cursor)
194
+ if created_after is not None:
195
+ clauses.append("created_at > ?")
196
+ params.append(created_after)
197
+ if created_before is not None:
198
+ clauses.append("created_at < ?")
199
+ params.append(created_before)
200
+ if search is not None:
201
+ search_clause = (
202
+ "(lower(artifact_name) like lower(?)"
203
+ " or lower(artifact_id) like lower(?)"
204
+ " or lower(coalesce(risk_summary, '')) like lower(?))"
205
+ )
206
+ clauses.append(search_clause)
207
+ pattern = f"%{search}%"
208
+ params.extend([pattern, pattern, pattern])
187
209
  where_clause = f"where {' and '.join(clauses)}" if clauses else ""
188
210
  query = f"""
189
211
  select request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher, policy_action,
@@ -243,14 +265,22 @@ def resolve_approval_request(
243
265
  )
244
266
 
245
267
 
246
- def count_approval_requests(connection: sqlite3.Connection, *, status: str | None = "pending") -> int:
247
- if status is None:
248
- row = connection.execute("select count(*) as total from approval_requests").fetchone()
249
- else:
250
- row = connection.execute(
251
- "select count(*) as total from approval_requests where status = ?",
252
- (status,),
253
- ).fetchone()
268
+ def count_approval_requests(
269
+ connection: sqlite3.Connection,
270
+ *,
271
+ status: str | None = "pending",
272
+ harness: str | None = None,
273
+ ) -> int:
274
+ clauses = []
275
+ params: list[object] = []
276
+ if status is not None:
277
+ clauses.append("status = ?")
278
+ params.append(status)
279
+ if harness is not None:
280
+ clauses.append("harness = ?")
281
+ params.append(harness)
282
+ where_clause = f"where {' and '.join(clauses)}" if clauses else ""
283
+ row = connection.execute(f"select count(*) as total from approval_requests {where_clause}", params).fetchone()
254
284
  return int(row["total"]) if row is not None else 0
255
285
 
256
286
 
@@ -265,14 +295,14 @@ def _row_to_payload(row: sqlite3.Row) -> dict[str, object]:
265
295
  "publisher": row["publisher"],
266
296
  "policy_action": str(row["policy_action"]),
267
297
  "recommended_scope": str(row["recommended_scope"]),
268
- "changed_fields": json.loads(str(row["changed_fields_json"])),
298
+ "changed_fields": _safe_json_list(row["changed_fields_json"]),
269
299
  "source_scope": str(row["source_scope"]),
270
300
  "config_path": str(row["config_path"]),
271
301
  "workspace": row["workspace"],
272
302
  "launch_target": row["launch_target"],
273
303
  "transport": row["transport"],
274
304
  "risk_summary": row["risk_summary"],
275
- "risk_signals": json.loads(str(row["risk_signals_json"])),
305
+ "risk_signals": _safe_json_list(row["risk_signals_json"]),
276
306
  "artifact_label": row["artifact_label"],
277
307
  "source_label": row["source_label"],
278
308
  "trigger_summary": row["trigger_summary"],
@@ -292,6 +322,111 @@ def _row_to_payload(row: sqlite3.Row) -> dict[str, object]:
292
322
  }
293
323
 
294
324
 
325
+ def _safe_json_list(value: object) -> list[object]:
326
+ if value is None:
327
+ return []
328
+ try:
329
+ parsed = json.loads(str(value))
330
+ except (json.JSONDecodeError, TypeError, ValueError):
331
+ return []
332
+ return list(parsed) if isinstance(parsed, list) else []
333
+
334
+
335
+ def approval_index_statements() -> list[str]:
336
+ return [
337
+ "create index if not exists idx_approval_status_created on approval_requests(status, created_at desc)",
338
+ "create index if not exists idx_approval_harness_status on approval_requests(harness, status)",
339
+ "create index if not exists idx_approval_artifact_hash on approval_requests(artifact_hash)",
340
+ "create index if not exists idx_approval_workspace_status on approval_requests(workspace, status)",
341
+ "create index if not exists idx_approval_policy_action on approval_requests(policy_action)",
342
+ "create index if not exists idx_approval_resolution on approval_requests(resolution_action, resolved_at)",
343
+ ]
344
+
345
+
346
+ def bulk_resolve_approval_requests(
347
+ connection: sqlite3.Connection,
348
+ request_ids: list[str],
349
+ *,
350
+ resolution_action: str,
351
+ resolution_scope: str,
352
+ reason: str | None,
353
+ resolved_at: str,
354
+ ) -> None:
355
+ if not request_ids:
356
+ return
357
+ placeholders = ",".join("?" for _ in request_ids)
358
+ connection.execute(
359
+ f"""
360
+ update approval_requests
361
+ set status = 'resolved',
362
+ resolution_action = ?,
363
+ resolution_scope = ?,
364
+ reason = ?,
365
+ resolved_at = ?
366
+ where request_id in ({placeholders})
367
+ and status = 'pending'
368
+ """,
369
+ [resolution_action, resolution_scope, reason, resolved_at, *request_ids],
370
+ )
371
+
372
+
373
+ def clear_approval_requests_by_harness(connection: sqlite3.Connection, harness: str) -> int:
374
+ cursor = connection.execute(
375
+ "delete from approval_requests where harness = ? and status = 'resolved'",
376
+ (harness,),
377
+ )
378
+ return cursor.rowcount
379
+
380
+
381
+ def clear_approval_requests_by_workspace(connection: sqlite3.Connection, workspace: str) -> int:
382
+ cursor = connection.execute(
383
+ "delete from approval_requests where workspace = ? and status = 'resolved'",
384
+ (workspace,),
385
+ )
386
+ return cursor.rowcount
387
+
388
+
389
+ def clear_approval_requests_by_scope(connection: sqlite3.Connection, source_scope: str) -> int:
390
+ cursor = connection.execute(
391
+ "delete from approval_requests where source_scope = ? and status = 'resolved'",
392
+ (source_scope,),
393
+ )
394
+ return cursor.rowcount
395
+
396
+
397
+ def clear_resolved_approval_requests_before(connection: sqlite3.Connection, before_timestamp: str) -> int:
398
+ cursor = connection.execute(
399
+ "delete from approval_requests where status = 'resolved' and resolved_at < ?",
400
+ (before_timestamp,),
401
+ )
402
+ return cursor.rowcount
403
+
404
+
405
+ def compact_approval_requests(connection: sqlite3.Connection) -> int:
406
+ rows = connection.execute(
407
+ """
408
+ select artifact_id, max(created_at) as latest_created
409
+ from approval_requests
410
+ where status = 'resolved'
411
+ group by artifact_id
412
+ having count(*) > 1
413
+ """
414
+ ).fetchall()
415
+ total_removed = 0
416
+ for row in rows:
417
+ cursor = connection.execute(
418
+ """
419
+ delete from approval_requests
420
+ where artifact_id = ?
421
+ and status = 'resolved'
422
+ and created_at < ?
423
+ """,
424
+ (row["artifact_id"], row["latest_created"]),
425
+ )
426
+ total_removed += cursor.rowcount
427
+ return total_removed
428
+
429
+
295
430
  def _optional_json_object(value: object) -> dict[str, object] | None:
296
431
  if value is None:
297
432
  return None
@@ -0,0 +1,217 @@
1
+ """Phase 15: Evidence store — table, indexes, CRUD, search, export, compaction."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import sqlite3
7
+ from dataclasses import dataclass, field
8
+ from datetime import datetime, timedelta, timezone
9
+
10
+
11
+ def _now_iso() -> str:
12
+ return datetime.now(timezone.utc).isoformat(timespec="microseconds").replace("+00:00", "Z")
13
+
14
+
15
+ @dataclass(frozen=True, slots=True)
16
+ class EvidenceRecord:
17
+ evidence_id: str
18
+ action_id: str
19
+ request_id: str
20
+ harness: str
21
+ workspace: str
22
+ signal_id: str
23
+ category: str
24
+ severity: str
25
+ confidence: float
26
+ summary: str
27
+ details: dict[str, object] = field(default_factory=dict)
28
+ created_at: str = field(default_factory=_now_iso)
29
+
30
+
31
+ def evidence_schema_statement() -> str:
32
+ return """
33
+ create table if not exists guard_evidence (
34
+ evidence_id text not null primary key,
35
+ action_id text not null default '',
36
+ request_id text not null default '',
37
+ harness text not null default '',
38
+ workspace text not null default '',
39
+ signal_id text not null default '',
40
+ category text not null default '',
41
+ severity text not null default '',
42
+ confidence real not null default 0.0,
43
+ summary text not null default '',
44
+ details_json text not null default '{}',
45
+ created_at text not null
46
+ )
47
+ """
48
+
49
+
50
+ def evidence_index_statements() -> list[str]:
51
+ return [
52
+ "create index if not exists idx_evidence_created on guard_evidence(created_at desc)",
53
+ "create index if not exists idx_evidence_request on guard_evidence(request_id)",
54
+ "create index if not exists idx_evidence_action on guard_evidence(action_id)",
55
+ "create index if not exists idx_evidence_category_severity on guard_evidence(category, severity)",
56
+ "create index if not exists idx_evidence_harness_workspace on guard_evidence(harness, workspace)",
57
+ ]
58
+
59
+
60
+ def _row_to_record(row: sqlite3.Row) -> EvidenceRecord:
61
+ try:
62
+ details: dict[str, object] = json.loads(row["details_json"])
63
+ except (json.JSONDecodeError, TypeError):
64
+ details = {}
65
+ return EvidenceRecord(
66
+ evidence_id=row["evidence_id"],
67
+ action_id=row["action_id"],
68
+ request_id=row["request_id"],
69
+ harness=row["harness"],
70
+ workspace=row["workspace"],
71
+ signal_id=row["signal_id"],
72
+ category=row["category"],
73
+ severity=row["severity"],
74
+ confidence=row["confidence"],
75
+ summary=row["summary"],
76
+ details=details,
77
+ created_at=row["created_at"],
78
+ )
79
+
80
+
81
+ def store_evidence(conn: sqlite3.Connection, record: EvidenceRecord) -> EvidenceRecord:
82
+ conn.execute(
83
+ """
84
+ insert or replace into guard_evidence
85
+ (evidence_id, action_id, request_id, harness, workspace, signal_id,
86
+ category, severity, confidence, summary, details_json, created_at)
87
+ values (?,?,?,?,?,?,?,?,?,?,?,?)
88
+ """,
89
+ (
90
+ record.evidence_id,
91
+ record.action_id,
92
+ record.request_id,
93
+ record.harness,
94
+ record.workspace,
95
+ record.signal_id,
96
+ record.category,
97
+ record.severity,
98
+ record.confidence,
99
+ record.summary,
100
+ json.dumps(record.details),
101
+ record.created_at,
102
+ ),
103
+ )
104
+ conn.commit()
105
+ return record
106
+
107
+
108
+ def list_evidence(
109
+ conn: sqlite3.Connection,
110
+ *,
111
+ harness: str | None = None,
112
+ category: str | None = None,
113
+ severity: str | None = None,
114
+ request_id: str | None = None,
115
+ before_cursor: str | None = None,
116
+ limit: int = 100,
117
+ ) -> list[EvidenceRecord]:
118
+ clauses: list[str] = []
119
+ params: list[object] = []
120
+
121
+ if harness is not None:
122
+ clauses.append("harness = ?")
123
+ params.append(harness)
124
+ if category is not None:
125
+ clauses.append("category = ?")
126
+ params.append(category)
127
+ if severity is not None:
128
+ clauses.append("severity = ?")
129
+ params.append(severity)
130
+ if request_id is not None:
131
+ clauses.append("request_id = ?")
132
+ params.append(request_id)
133
+ if before_cursor is not None:
134
+ clauses.append("created_at < ?")
135
+ params.append(before_cursor)
136
+
137
+ where = f"where {' and '.join(clauses)}" if clauses else ""
138
+ params.append(limit)
139
+ rows = conn.execute(
140
+ f"select * from guard_evidence {where} order by created_at desc limit ?",
141
+ params,
142
+ ).fetchall()
143
+ return [_row_to_record(r) for r in rows]
144
+
145
+
146
+ def search_evidence(
147
+ conn: sqlite3.Connection,
148
+ query: str,
149
+ *,
150
+ limit: int = 100,
151
+ ) -> list[EvidenceRecord]:
152
+ pattern = f"%{query}%"
153
+ rows = conn.execute(
154
+ "select * from guard_evidence where lower(summary) like lower(?) order by created_at desc limit ?",
155
+ (pattern, limit),
156
+ ).fetchall()
157
+ return [_row_to_record(r) for r in rows]
158
+
159
+
160
+ def count_evidence(
161
+ conn: sqlite3.Connection,
162
+ *,
163
+ harness: str | None = None,
164
+ category: str | None = None,
165
+ ) -> int:
166
+ clauses: list[str] = []
167
+ params: list[object] = []
168
+ if harness is not None:
169
+ clauses.append("harness = ?")
170
+ params.append(harness)
171
+ if category is not None:
172
+ clauses.append("category = ?")
173
+ params.append(category)
174
+ where = f"where {' and '.join(clauses)}" if clauses else ""
175
+ row = conn.execute(f"select count(*) from guard_evidence {where}", params).fetchone()
176
+ return int(row[0])
177
+
178
+
179
+ def export_evidence_json(
180
+ conn: sqlite3.Connection,
181
+ *,
182
+ limit: int = 10_000,
183
+ ) -> str:
184
+ records = list_evidence(conn, limit=limit)
185
+ return json.dumps(
186
+ [
187
+ {
188
+ "evidence_id": r.evidence_id,
189
+ "action_id": r.action_id,
190
+ "request_id": r.request_id,
191
+ "harness": r.harness,
192
+ "workspace": r.workspace,
193
+ "signal_id": r.signal_id,
194
+ "category": r.category,
195
+ "severity": r.severity,
196
+ "confidence": r.confidence,
197
+ "summary": r.summary,
198
+ "created_at": r.created_at,
199
+ }
200
+ for r in records
201
+ ],
202
+ indent=2,
203
+ )
204
+
205
+
206
+ def compact_evidence(conn: sqlite3.Connection, *, retain_days: int = 90) -> int:
207
+ cutoff = (
208
+ (datetime.now(timezone.utc) - timedelta(days=retain_days))
209
+ .isoformat(timespec="microseconds")
210
+ .replace("+00:00", "Z")
211
+ )
212
+ cursor = conn.execute(
213
+ "delete from guard_evidence where created_at < ?",
214
+ (cutoff,),
215
+ )
216
+ conn.commit()
217
+ return cursor.rowcount
@@ -1,3 +1,3 @@
1
1
  """Single source of truth for tool version."""
2
2
 
3
- __version__ = "2.0.124"
3
+ __version__ = "2.0.126"