plugin-scanner 2.0.96__tar.gz → 2.0.97__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 (341) hide show
  1. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/PKG-INFO +1 -1
  2. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/pyproject.toml +1 -1
  3. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/pyproject.toml.bak +1 -1
  4. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/approvals.py +9 -0
  5. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/commands.py +35 -0
  6. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/models.py +2 -0
  7. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/runtime/runner.py +63 -0
  8. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/store.py +1 -0
  9. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/store_approvals.py +35 -19
  10. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/version.py +1 -1
  11. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_approvals.py +181 -0
  12. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_runtime.py +4 -0
  13. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.clusterfuzzlite/Dockerfile +0 -0
  14. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.clusterfuzzlite/build.sh +0 -0
  15. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.clusterfuzzlite/project.yaml +0 -0
  16. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.clusterfuzzlite/requirements-atheris.txt +0 -0
  17. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.dockerignore +0 -0
  18. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/CODEOWNERS +0 -0
  19. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  20. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  21. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  22. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/dependabot.yml +0 -0
  23. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/workflows/ci.yml +0 -0
  24. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/workflows/codeql.yml +0 -0
  25. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/workflows/dependabot-uv-lock.yml +0 -0
  26. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/workflows/fuzz.yml +0 -0
  27. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/workflows/harness-smoke.yml +0 -0
  28. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/workflows/publish.yml +0 -0
  29. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/workflows/scorecard.yml +0 -0
  30. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.gitignore +0 -0
  31. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.pre-commit-hooks.yaml +0 -0
  32. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/CONTRIBUTING.md +0 -0
  33. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/Dockerfile +0 -0
  34. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/LICENSE +0 -0
  35. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/README.md +0 -0
  36. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/SECURITY.md +0 -0
  37. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/index.html +0 -0
  38. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/package.json +0 -0
  39. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/pnpm-lock.yaml +0 -0
  40. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/public/apple-touch-icon.png +0 -0
  41. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
  42. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/public/brand/Logo_Whole.png +0 -0
  43. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/public/favicon-16x16.png +0 -0
  44. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/public/favicon-32x32.png +0 -0
  45. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/public/favicon.ico +0 -0
  46. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/app.tsx +0 -0
  47. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/approval-center-layout.tsx +0 -0
  48. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/approval-center-primitives.tsx +0 -0
  49. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/approval-center-utils.ts +0 -0
  50. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/fleet-workspace.tsx +0 -0
  51. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/guard-api.test.ts +0 -0
  52. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/guard-api.ts +0 -0
  53. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/guard-demo.ts +0 -0
  54. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/guard-types.ts +0 -0
  55. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/main.tsx +0 -0
  56. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/receipts-workspace.tsx +0 -0
  57. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/runtime-overview.tsx +0 -0
  58. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/settings-workspace.tsx +0 -0
  59. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/styles.css +0 -0
  60. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/vite-env.d.ts +0 -0
  61. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/tsconfig.json +0 -0
  62. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/vite.config.ts +0 -0
  63. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docker-requirements.txt +0 -0
  64. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docs/guard/approval-audit.md +0 -0
  65. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docs/guard/architecture.md +0 -0
  66. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docs/guard/get-started.md +0 -0
  67. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docs/guard/harness-support.md +0 -0
  68. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docs/guard/local-vs-cloud.md +0 -0
  69. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docs/guard/testing-matrix.md +0 -0
  70. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docs/trust/mcp-trust-draft.md +0 -0
  71. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docs/trust/plugin-trust-draft.md +0 -0
  72. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docs/trust/skill-trust-local.md +0 -0
  73. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/fuzzers/manifest_fuzzer.py +0 -0
  74. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/requirements.txt +0 -0
  75. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/schemas/plugin-quality.v1.json +0 -0
  76. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/schemas/scan-result.v1.json +0 -0
  77. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/schemas/verify-result.v1.json +0 -0
  78. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/__init__.py +0 -0
  79. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/action_runner.py +0 -0
  80. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/argparse_utils.py +0 -0
  81. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/__init__.py +0 -0
  82. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
  83. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/claude.py +0 -0
  84. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
  85. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
  86. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/gemini.py +0 -0
  87. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/manifest.py +0 -0
  88. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
  89. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
  90. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
  91. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/opencode.py +0 -0
  92. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
  93. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/security.py +0 -0
  94. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
  95. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/cli.py +0 -0
  96. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/cli_ui.py +0 -0
  97. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/config.py +0 -0
  98. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
  99. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
  100. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
  101. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
  102. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
  103. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
  104. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
  105. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
  106. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
  107. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/github_reporting.py +0 -0
  108. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/__init__.py +0 -0
  109. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
  110. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
  111. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
  112. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
  113. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
  114. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
  115. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
  116. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
  117. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
  118. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
  119. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
  120. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
  121. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
  122. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
  123. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
  124. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
  125. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
  126. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
  127. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
  128. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
  129. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
  130. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
  131. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
  132. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
  133. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
  134. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
  135. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
  136. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
  137. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/config.py +0 -0
  138. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
  139. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
  140. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
  141. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
  142. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
  143. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
  144. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
  145. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
  146. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
  147. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
  148. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
  149. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
  150. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
  151. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
  152. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
  153. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
  154. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/incident.py +0 -0
  155. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/launcher.py +0 -0
  156. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
  157. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
  158. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
  159. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/protect.py +0 -0
  160. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
  161. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
  162. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
  163. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
  164. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
  165. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
  166. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/redaction.py +0 -0
  167. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/risk.py +0 -0
  168. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
  169. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
  170. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
  171. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
  172. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
  173. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
  174. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
  175. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
  176. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/shims.py +0 -0
  177. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
  178. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/types.py +0 -0
  179. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
  180. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
  181. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
  182. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/lint_fixes.py +0 -0
  183. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/marketplace_support.py +0 -0
  184. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/models.py +0 -0
  185. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/path_support.py +0 -0
  186. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/policy.py +0 -0
  187. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/quality_artifact.py +0 -0
  188. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/repo_detect.py +0 -0
  189. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/reporting.py +0 -0
  190. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/rules/__init__.py +0 -0
  191. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/rules/registry.py +0 -0
  192. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/rules/specs.py +0 -0
  193. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/scanner.py +0 -0
  194. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/submission.py +0 -0
  195. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/suppressions.py +0 -0
  196. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
  197. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/trust_helpers.py +0 -0
  198. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
  199. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/trust_models.py +0 -0
  200. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
  201. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/trust_scoring.py +0 -0
  202. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
  203. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/trust_specs.py +0 -0
  204. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/verification.py +0 -0
  205. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/__init__.py +0 -0
  206. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/conftest.py +0 -0
  207. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/__init__.py +0 -0
  208. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
  209. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/bad-plugin/.mcp.json +0 -0
  210. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/bad-plugin/secrets.js +0 -0
  211. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
  212. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
  213. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/claude-plugin-good/README.md +0 -0
  214. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
  215. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
  216. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
  217. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/code-quality-bad/evil.js +0 -0
  218. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/code-quality-bad/inject.js +0 -0
  219. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
  220. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
  221. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/gemini-extension-good/README.md +0 -0
  222. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
  223. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
  224. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
  225. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
  226. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/good-plugin/.codexignore +0 -0
  227. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/good-plugin/LICENSE +0 -0
  228. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/good-plugin/README.md +0 -0
  229. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/good-plugin/SECURITY.md +0 -0
  230. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
  231. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
  232. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
  233. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
  234. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
  235. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
  236. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
  237. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
  238. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
  239. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
  240. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
  241. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
  242. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
  243. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
  244. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
  245. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
  246. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
  247. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
  248. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
  249. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/mcp-canary-server.py +0 -0
  250. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
  251. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
  252. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/mit-license/LICENSE +0 -0
  253. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
  254. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
  255. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
  256. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
  257. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
  258. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
  259. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
  260. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
  261. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
  262. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
  263. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
  264. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
  265. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
  266. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
  267. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
  268. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
  269. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
  270. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
  271. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/opencode-good/LICENSE +0 -0
  272. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/opencode-good/README.md +0 -0
  273. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/opencode-good/SECURITY.md +0 -0
  274. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
  275. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
  276. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
  277. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
  278. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
  279. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
  280. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/with-marketplace/marketplace.json +0 -0
  281. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test-trust-scoring.py +0 -0
  282. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test-trust-specs.py +0 -0
  283. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_action_runner.py +0 -0
  284. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_best_practices.py +0 -0
  285. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_cisco_install_surfaces.py +0 -0
  286. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_cli.py +0 -0
  287. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_code_quality.py +0 -0
  288. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_config.py +0 -0
  289. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_coverage_remaining.py +0 -0
  290. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_ecosystems.py +0 -0
  291. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_edge_cases.py +0 -0
  292. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_final_coverage.py +0 -0
  293. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_bootstrap.py +0 -0
  294. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_capabilities.py +0 -0
  295. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_claude_adapter.py +0 -0
  296. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_cli.py +0 -0
  297. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_codex_e2e.py +0 -0
  298. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_codex_install.py +0 -0
  299. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_codex_proxy.py +0 -0
  300. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_config_paths.py +0 -0
  301. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_connect_flow.py +0 -0
  302. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_consumer_mode.py +0 -0
  303. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_copilot_adapter.py +0 -0
  304. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_copilot_proxy.py +0 -0
  305. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_daemon_manager.py +0 -0
  306. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_event_schema_v1.py +0 -0
  307. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_events.py +0 -0
  308. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_launch_env.py +0 -0
  309. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_opencode_proxy.py +0 -0
  310. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_product_flow.py +0 -0
  311. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_protect.py +0 -0
  312. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_render.py +0 -0
  313. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_risk.py +0 -0
  314. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_runtime_action_harnesses.py +0 -0
  315. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_runtime_actions.py +0 -0
  316. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_store_migrations.py +0 -0
  317. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_surface_server.py +0 -0
  318. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_verdicts.py +0 -0
  319. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_hermes_adapter.py +0 -0
  320. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_integration.py +0 -0
  321. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_lint_fixes.py +0 -0
  322. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_live_cisco_smoke.py +0 -0
  323. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_manifest.py +0 -0
  324. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_marketplace.py +0 -0
  325. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_mcp_security.py +0 -0
  326. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_openclaw_adapter.py +0 -0
  327. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_operational_security.py +0 -0
  328. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_policy.py +0 -0
  329. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_quality_artifact.py +0 -0
  330. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_rule_registry.py +0 -0
  331. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_scanner.py +0 -0
  332. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_schema_contracts.py +0 -0
  333. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_security.py +0 -0
  334. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_security_ops.py +0 -0
  335. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_skill_security.py +0 -0
  336. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_submission.py +0 -0
  337. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_trust_scoring.py +0 -0
  338. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_trust_specs.py +0 -0
  339. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_verification.py +0 -0
  340. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_versioning.py +0 -0
  341. {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 2.0.96
3
+ Version: 2.0.97
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.96"
7
+ version = "2.0.97"
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.96"
7
+ version = "2.0.97"
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"
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import time
6
6
  import uuid
7
+ from collections.abc import Mapping
7
8
  from dataclasses import replace
8
9
  from datetime import datetime, timezone
9
10
  from pathlib import Path
@@ -86,6 +87,7 @@ def queue_blocked_approvals(
86
87
  why_now=incident["why_now"],
87
88
  launch_summary=incident["launch_summary"],
88
89
  risk_headline=incident["risk_headline"],
90
+ action_envelope_json=_item_action_envelope_json(item),
89
91
  )
90
92
  persisted_request_id = store.add_approval_request(request, timestamp)
91
93
  if persisted_request_id != request.request_id:
@@ -333,6 +335,13 @@ def _item_risk_signals(item: dict[str, object], artifact) -> tuple[str, ...]:
333
335
  return artifact_risk_signals(artifact) if artifact is not None else ()
334
336
 
335
337
 
338
+ def _item_action_envelope_json(item: dict[str, object]) -> dict[str, object] | None:
339
+ value = item.get("action_envelope_json")
340
+ if not isinstance(value, Mapping):
341
+ return None
342
+ return {str(key): item_value for key, item_value in value.items() if isinstance(key, str)}
343
+
344
+
336
345
  def _string_list(value: object) -> list[str]:
337
346
  if not isinstance(value, list):
338
347
  return []
@@ -80,6 +80,7 @@ from ..proxy import (
80
80
  )
81
81
  from ..receipts import build_receipt
82
82
  from ..risk import artifact_risk_signals, artifact_risk_summary
83
+ from ..runtime.actions import GuardActionEnvelope, normalize_harness_payload
83
84
  from ..runtime.runner import (
84
85
  GuardSyncNotConfiguredError,
85
86
  extract_prompt_requests,
@@ -1206,6 +1207,12 @@ def run_guard_command(
1206
1207
  runtime_workspace = current_workspace
1207
1208
  if args.harness == "copilot":
1208
1209
  runtime_workspace = _resolve_copilot_workspace_root(runtime_workspace)
1210
+ action_envelope = _hook_action_envelope(
1211
+ harness=args.harness,
1212
+ payload=payload,
1213
+ home_dir=context.home_dir,
1214
+ workspace=runtime_workspace,
1215
+ )
1209
1216
  copilot_hook_stage = _copilot_hook_stage(payload) if args.harness == "copilot" else None
1210
1217
  copilot_runtime_tool_call = (
1211
1218
  _copilot_runtime_tool_call(
@@ -1309,6 +1316,7 @@ def run_guard_command(
1309
1316
  "launch_target": json.dumps(runtime_arguments, sort_keys=True)
1310
1317
  if runtime_arguments is not None
1311
1318
  else runtime_artifact.command,
1319
+ "action_envelope_json": _action_envelope_json(action_envelope),
1312
1320
  }
1313
1321
  ]
1314
1322
  }
@@ -1667,6 +1675,7 @@ def run_guard_command(
1667
1675
  "source_scope": runtime_artifact.source_scope,
1668
1676
  "config_path": runtime_artifact.config_path,
1669
1677
  "launch_target": _runtime_request_summary(runtime_artifact),
1678
+ "action_envelope_json": _action_envelope_json(action_envelope),
1670
1679
  }
1671
1680
  ]
1672
1681
  }
@@ -3619,6 +3628,32 @@ def _load_hook_payload(event_file: str | None, *, input_text: str | None = None)
3619
3628
  return _normalize_hook_payload(payload) if isinstance(payload, dict) else {}
3620
3629
 
3621
3630
 
3631
+ _ACTION_ENVELOPE_HARNESSES = frozenset({"codex", "claude-code", "opencode", "copilot", "gemini"})
3632
+
3633
+
3634
+ def _hook_action_envelope(
3635
+ *,
3636
+ harness: str,
3637
+ payload: dict[str, object],
3638
+ home_dir: Path,
3639
+ workspace: Path | None,
3640
+ ) -> GuardActionEnvelope | None:
3641
+ canonical_harness = _canonical_harness_name(harness)
3642
+ if canonical_harness not in _ACTION_ENVELOPE_HARNESSES:
3643
+ return None
3644
+ return normalize_harness_payload(
3645
+ canonical_harness,
3646
+ _hook_event_name(payload) or "PreToolUse",
3647
+ payload,
3648
+ workspace=workspace,
3649
+ home_dir=home_dir,
3650
+ )
3651
+
3652
+
3653
+ def _action_envelope_json(envelope: GuardActionEnvelope | None) -> dict[str, object] | None:
3654
+ return envelope.to_dict() if envelope is not None else None
3655
+
3656
+
3622
3657
  def _normalize_hook_payload(payload: dict[str, object]) -> dict[str, object]:
3623
3658
  normalized = dict(payload)
3624
3659
  for source_key, target_key in (
@@ -141,6 +141,7 @@ class GuardReceipt:
141
141
  user_override: str | None = None
142
142
  artifact_name: str | None = None
143
143
  source_scope: str | None = None
144
+ action_envelope_json: dict[str, object] | None = None
144
145
 
145
146
  def to_dict(self) -> dict[str, object]:
146
147
  payload = asdict(self)
@@ -177,6 +178,7 @@ class GuardApprovalRequest:
177
178
  why_now: str | None = None
178
179
  launch_summary: str | None = None
179
180
  risk_headline: str | None = None
181
+ action_envelope_json: dict[str, object] | None = None
180
182
 
181
183
  def to_dict(self) -> dict[str, object]:
182
184
  payload = asdict(self)
@@ -12,6 +12,7 @@ import urllib.error
12
12
  import urllib.parse
13
13
  import urllib.request
14
14
  from collections.abc import Callable
15
+ from contextlib import suppress
15
16
  from datetime import datetime, timezone
16
17
  from pathlib import Path
17
18
  from typing import Any
@@ -24,6 +25,7 @@ from ..consumer import detect_harness, evaluate_detection
24
25
  from ..models import GuardArtifact, HarnessDetection, PolicyDecision
25
26
  from ..store import GuardStore
26
27
  from ..types import PromptRequest, RemediationAction
28
+ from .actions import GuardActionEnvelope, redacted_workspace_label
27
29
 
28
30
  _APPROVAL_METADATA_KEYS = (
29
31
  "approval_center_url",
@@ -233,12 +235,18 @@ def guard_run(
233
235
  if not evaluation["blocked"]:
234
236
  evaluation = evaluate_detection(detection, store, config, default_action=default_action, persist=True)
235
237
 
238
+ action_envelope = _guard_run_action_envelope(harness, context, passthrough_args)
239
+ if evaluation["blocked"]:
240
+ evaluation = _evaluation_with_action_envelope(evaluation, action_envelope)
241
+
236
242
  if not dry_run and interactive_resolver is not None and evaluation["blocked"]:
237
243
  evaluation = interactive_resolver(detection, evaluation)
238
244
  elif not dry_run and blocked_resolver is not None and evaluation["blocked"]:
239
245
  pending_evaluation = blocked_resolver(detection, evaluation)
240
246
  detection = _detection_with_prompt_artifacts(detect_harness(harness, context), context, passthrough_args)
241
247
  reevaluated = evaluate_detection(detection, store, config, default_action=default_action, persist=True)
248
+ if reevaluated["blocked"]:
249
+ reevaluated = _evaluation_with_action_envelope(reevaluated, action_envelope)
242
250
  for key in _APPROVAL_METADATA_KEYS:
243
251
  if key in pending_evaluation:
244
252
  reevaluated[key] = pending_evaluation[key]
@@ -274,6 +282,61 @@ def guard_run(
274
282
  return evaluation
275
283
 
276
284
 
285
+ def _guard_run_action_envelope(
286
+ harness: str,
287
+ context: HarnessContext,
288
+ passthrough_args: list[str],
289
+ ) -> GuardActionEnvelope:
290
+ workspace = context.workspace_dir
291
+ workspace_hash = None
292
+ if workspace is not None:
293
+ workspace_path = workspace.expanduser()
294
+ with suppress(OSError):
295
+ workspace_path = workspace_path.resolve()
296
+ workspace_hash = hashlib.sha256(str(workspace_path).encode("utf-8")).hexdigest()
297
+ return GuardActionEnvelope(
298
+ schema_version=1,
299
+ action_id="",
300
+ harness=harness,
301
+ event_name="HarnessStart",
302
+ action_type="harness_start",
303
+ workspace=redacted_workspace_label(workspace, home_dir=context.home_dir),
304
+ workspace_hash=workspace_hash,
305
+ tool_name=None,
306
+ command=None,
307
+ prompt_excerpt=None,
308
+ target_paths=(),
309
+ network_hosts=(),
310
+ mcp_server=None,
311
+ mcp_tool=None,
312
+ package_manager=None,
313
+ package_name=None,
314
+ script_name=None,
315
+ raw_payload_redacted={"passthrough_arg_count": len(passthrough_args)},
316
+ )
317
+
318
+
319
+ def _evaluation_with_action_envelope(
320
+ evaluation: dict[str, Any],
321
+ action_envelope: GuardActionEnvelope,
322
+ ) -> dict[str, Any]:
323
+ artifacts = evaluation.get("artifacts")
324
+ if not isinstance(artifacts, list):
325
+ return evaluation
326
+ action_payload = action_envelope.to_dict()
327
+ normalized_artifacts: list[object] = []
328
+ changed = False
329
+ for item in artifacts:
330
+ if isinstance(item, dict) and "action_envelope_json" not in item:
331
+ normalized_artifacts.append({**item, "action_envelope_json": action_payload})
332
+ changed = True
333
+ else:
334
+ normalized_artifacts.append(item)
335
+ if not changed:
336
+ return evaluation
337
+ return {**evaluation, "artifacts": normalized_artifacts}
338
+
339
+
277
340
  def _guard_run_config_paths(
278
341
  *,
279
342
  detection: HarnessDetection,
@@ -666,6 +666,7 @@ class GuardStore:
666
666
  self._ensure_approval_column(connection, "why_now", "text")
667
667
  self._ensure_approval_column(connection, "launch_summary", "text")
668
668
  self._ensure_approval_column(connection, "risk_headline", "text")
669
+ self._ensure_approval_column(connection, "action_envelope_json", "text")
669
670
  self._ensure_approval_column(connection, "workspace", "text")
670
671
  self._ensure_attachment_column(connection, "lease_id", "text not null default ''")
671
672
  self._ensure_attachment_column(connection, "lease_expires_at", "text")
@@ -30,12 +30,13 @@ def approval_schema_statement() -> str:
30
30
  risk_signals_json text not null default '[]',
31
31
  artifact_label text,
32
32
  source_label text,
33
- trigger_summary text,
34
- why_now text,
35
- launch_summary text,
36
- risk_headline text,
37
- review_command text not null,
38
- approval_url text not null,
33
+ trigger_summary text,
34
+ why_now text,
35
+ launch_summary text,
36
+ risk_headline text,
37
+ action_envelope_json text,
38
+ review_command text not null,
39
+ approval_url text not null,
39
40
  status text not null,
40
41
  resolution_action text,
41
42
  resolution_scope text,
@@ -68,7 +69,7 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
68
69
  recommended_scope = ?, changed_fields_json = ?, source_scope = ?, config_path = ?, workspace = ?,
69
70
  launch_target = ?, transport = ?, risk_summary = ?, risk_signals_json = ?,
70
71
  artifact_label = ?, source_label = ?, trigger_summary = ?, why_now = ?, launch_summary = ?,
71
- risk_headline = ?,
72
+ risk_headline = ?, action_envelope_json = ?,
72
73
  review_command = ?, approval_url = ?, created_at = ?
73
74
  where request_id = ?
74
75
  """,
@@ -93,6 +94,7 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
93
94
  request.why_now,
94
95
  request.launch_summary,
95
96
  request.risk_headline,
97
+ json.dumps(request.action_envelope_json) if request.action_envelope_json is not None else None,
96
98
  review_command,
97
99
  approval_url,
98
100
  now,
@@ -105,12 +107,12 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
105
107
  insert into approval_requests (
106
108
  request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher, policy_action,
107
109
  recommended_scope, changed_fields_json, source_scope, config_path, workspace,
108
- launch_target, transport, risk_summary,
109
- risk_signals_json, artifact_label, source_label, trigger_summary, why_now, launch_summary, risk_headline,
110
- review_command,
111
- approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
112
- )
113
- values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
110
+ launch_target, transport, risk_summary,
111
+ risk_signals_json, artifact_label, source_label, trigger_summary, why_now, launch_summary, risk_headline,
112
+ action_envelope_json, review_command,
113
+ approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
114
+ )
115
+ values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
114
116
  """,
115
117
  (
116
118
  request.request_id,
@@ -136,6 +138,7 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
136
138
  request.why_now,
137
139
  request.launch_summary,
138
140
  request.risk_headline,
141
+ json.dumps(request.action_envelope_json) if request.action_envelope_json is not None else None,
139
142
  request.review_command,
140
143
  request.approval_url,
141
144
  "pending",
@@ -182,9 +185,9 @@ def list_approval_requests(
182
185
  query = f"""
183
186
  select request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher, policy_action,
184
187
  recommended_scope, changed_fields_json, source_scope, config_path, workspace, launch_target, transport,
185
- risk_summary, risk_signals_json, artifact_label, source_label, trigger_summary, why_now,
186
- launch_summary, risk_headline, review_command,
187
- approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
188
+ risk_summary, risk_signals_json, artifact_label, source_label, trigger_summary, why_now,
189
+ launch_summary, risk_headline, action_envelope_json, review_command,
190
+ approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
188
191
  from approval_requests
189
192
  {where_clause}
190
193
  order by created_at desc
@@ -201,9 +204,9 @@ def get_approval_request(connection: sqlite3.Connection, request_id: str) -> dic
201
204
  """
202
205
  select request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher, policy_action,
203
206
  recommended_scope, changed_fields_json, source_scope, config_path, workspace, launch_target, transport,
204
- risk_summary, risk_signals_json, artifact_label, source_label, trigger_summary, why_now,
205
- launch_summary, risk_headline, review_command,
206
- approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
207
+ risk_summary, risk_signals_json, artifact_label, source_label, trigger_summary, why_now,
208
+ launch_summary, risk_headline, action_envelope_json, review_command,
209
+ approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
207
210
  from approval_requests
208
211
  where request_id = ?
209
212
  """,
@@ -273,6 +276,7 @@ def _row_to_payload(row: sqlite3.Row) -> dict[str, object]:
273
276
  "why_now": row["why_now"],
274
277
  "launch_summary": row["launch_summary"],
275
278
  "risk_headline": row["risk_headline"],
279
+ "action_envelope_json": _optional_json_object(row["action_envelope_json"]),
276
280
  "review_command": str(row["review_command"]),
277
281
  "approval_url": str(row["approval_url"]),
278
282
  "status": str(row["status"]),
@@ -282,3 +286,15 @@ def _row_to_payload(row: sqlite3.Row) -> dict[str, object]:
282
286
  "created_at": str(row["created_at"]),
283
287
  "resolved_at": row["resolved_at"],
284
288
  }
289
+
290
+
291
+ def _optional_json_object(value: object) -> dict[str, object] | None:
292
+ if value is None:
293
+ return None
294
+ try:
295
+ parsed = json.loads(str(value))
296
+ except (json.JSONDecodeError, TypeError, ValueError):
297
+ return None
298
+ if isinstance(parsed, dict):
299
+ return {str(key): item for key, item in parsed.items() if isinstance(key, str)}
300
+ return None
@@ -1,3 +1,3 @@
1
1
  """Single source of truth for tool version."""
2
2
 
3
- __version__ = "2.0.96"
3
+ __version__ = "2.0.97"
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import json
6
+ import sqlite3
6
7
  import urllib.error
7
8
  import urllib.parse
8
9
  import urllib.request
@@ -69,6 +70,26 @@ class TestGuardApprovals:
69
70
  def test_guard_store_persists_and_resolves_approval_requests(self, tmp_path):
70
71
  store = GuardStore(tmp_path / "guard-home")
71
72
  workspace_dir = tmp_path / "workspace"
73
+ action_envelope_json = {
74
+ "schema_version": 1,
75
+ "action_id": "action-123",
76
+ "harness": "codex",
77
+ "event_name": "PreToolUse",
78
+ "action_type": "shell_command",
79
+ "workspace": "~/workspace",
80
+ "workspace_hash": "workspace-hash",
81
+ "tool_name": "Bash",
82
+ "command": "cat ~/.npmrc",
83
+ "prompt_excerpt": None,
84
+ "target_paths": ["~/.npmrc"],
85
+ "network_hosts": [],
86
+ "mcp_server": None,
87
+ "mcp_tool": None,
88
+ "package_manager": None,
89
+ "package_name": None,
90
+ "script_name": None,
91
+ "raw_payload_redacted": {"tool_name": "Bash"},
92
+ }
72
93
  request = GuardApprovalRequest(
73
94
  request_id="req-123",
74
95
  harness="codex",
@@ -83,6 +104,7 @@ class TestGuardApprovals:
83
104
  workspace=str(workspace_dir),
84
105
  review_command="hol-guard approvals approve req-123",
85
106
  approval_url="http://127.0.0.1:4455/approvals/req-123",
107
+ action_envelope_json=action_envelope_json,
86
108
  )
87
109
 
88
110
  store.add_approval_request(request, "2026-04-11T00:00:00+00:00")
@@ -99,10 +121,169 @@ class TestGuardApprovals:
99
121
  assert pending[0]["status"] == "pending"
100
122
  assert pending[0]["approval_url"] == "http://127.0.0.1:4455/approvals/req-123"
101
123
  assert pending[0]["workspace"] == str(workspace_dir)
124
+ assert pending[0]["action_envelope_json"] == action_envelope_json
102
125
  assert resolved is not None
103
126
  assert resolved["status"] == "resolved"
104
127
  assert resolved["resolution_action"] == "allow"
105
128
  assert resolved["resolution_scope"] == "artifact"
129
+ assert resolved["action_envelope_json"] == action_envelope_json
130
+
131
+ def test_guard_store_loads_old_approval_rows_without_action_envelope(self, tmp_path):
132
+ guard_home = tmp_path / "guard-home"
133
+ guard_home.mkdir(parents=True, exist_ok=True)
134
+ connection = sqlite3.connect(guard_home / "guard.db")
135
+ try:
136
+ connection.execute(
137
+ """
138
+ create table approval_requests (
139
+ request_id text primary key,
140
+ harness text not null,
141
+ artifact_id text not null,
142
+ artifact_name text not null,
143
+ artifact_type text not null,
144
+ artifact_hash text not null,
145
+ publisher text,
146
+ policy_action text not null,
147
+ recommended_scope text not null,
148
+ changed_fields_json text not null,
149
+ source_scope text not null,
150
+ config_path text not null,
151
+ workspace text,
152
+ launch_target text,
153
+ transport text,
154
+ risk_summary text,
155
+ risk_signals_json text not null default '[]',
156
+ artifact_label text,
157
+ source_label text,
158
+ trigger_summary text,
159
+ why_now text,
160
+ launch_summary text,
161
+ risk_headline text,
162
+ review_command text not null,
163
+ approval_url text not null,
164
+ status text not null,
165
+ resolution_action text,
166
+ resolution_scope text,
167
+ reason text,
168
+ created_at text not null,
169
+ resolved_at text
170
+ )
171
+ """
172
+ )
173
+ connection.execute(
174
+ """
175
+ insert into approval_requests (
176
+ request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher,
177
+ policy_action, recommended_scope, changed_fields_json, source_scope, config_path, workspace,
178
+ launch_target, transport, risk_summary, risk_signals_json, artifact_label, source_label,
179
+ trigger_summary, why_now, launch_summary, risk_headline, review_command, approval_url, status,
180
+ resolution_action, resolution_scope, reason, created_at, resolved_at
181
+ )
182
+ values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
183
+ """,
184
+ (
185
+ "req-old",
186
+ "codex",
187
+ "codex:project:workspace_skill",
188
+ "workspace_skill",
189
+ "artifact",
190
+ "hash-old",
191
+ None,
192
+ "require-reapproval",
193
+ "artifact",
194
+ json.dumps(["args"]),
195
+ "project",
196
+ str(tmp_path / "workspace" / ".codex" / "config.toml"),
197
+ None,
198
+ None,
199
+ None,
200
+ None,
201
+ "[]",
202
+ None,
203
+ None,
204
+ None,
205
+ None,
206
+ None,
207
+ None,
208
+ "hol-guard approvals approve req-old",
209
+ "http://127.0.0.1/pending",
210
+ "pending",
211
+ None,
212
+ None,
213
+ None,
214
+ "2026-04-11T00:00:00+00:00",
215
+ None,
216
+ ),
217
+ )
218
+ connection.commit()
219
+ finally:
220
+ connection.close()
221
+
222
+ store = GuardStore(guard_home)
223
+ request = store.get_approval_request("req-old")
224
+
225
+ assert request is not None
226
+ assert request["request_id"] == "req-old"
227
+ assert request["action_envelope_json"] is None
228
+
229
+ def test_guard_store_ignores_malformed_action_envelope_json(self, tmp_path):
230
+ store = GuardStore(tmp_path / "guard-home")
231
+ connection = sqlite3.connect(store.path)
232
+ try:
233
+ connection.execute(
234
+ """
235
+ insert into approval_requests (
236
+ request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher,
237
+ policy_action, recommended_scope, changed_fields_json, source_scope, config_path, workspace,
238
+ launch_target, transport, risk_summary, risk_signals_json, artifact_label, source_label,
239
+ trigger_summary, why_now, launch_summary, risk_headline, action_envelope_json, review_command,
240
+ approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
241
+ )
242
+ values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
243
+ """,
244
+ (
245
+ "req-bad-envelope",
246
+ "codex",
247
+ "codex:project:workspace_skill",
248
+ "workspace_skill",
249
+ "artifact",
250
+ "hash-bad-envelope",
251
+ None,
252
+ "require-reapproval",
253
+ "artifact",
254
+ json.dumps(["args"]),
255
+ "project",
256
+ str(tmp_path / "workspace" / ".codex" / "config.toml"),
257
+ None,
258
+ None,
259
+ None,
260
+ None,
261
+ "[]",
262
+ None,
263
+ None,
264
+ None,
265
+ None,
266
+ None,
267
+ None,
268
+ "{not-json",
269
+ "hol-guard approvals approve req-bad-envelope",
270
+ "http://127.0.0.1/pending",
271
+ "pending",
272
+ None,
273
+ None,
274
+ None,
275
+ "2026-04-11T00:00:00+00:00",
276
+ None,
277
+ ),
278
+ )
279
+ connection.commit()
280
+ finally:
281
+ connection.close()
282
+
283
+ request = store.get_approval_request("req-bad-envelope")
284
+
285
+ assert request is not None
286
+ assert request["action_envelope_json"] is None
106
287
 
107
288
  def test_guard_surface_daemon_client_recovers_missing_auth_token(self, tmp_path, monkeypatch):
108
289
  guard_home = tmp_path / "guard-home"
@@ -492,6 +492,8 @@ clearer UX and an implementation plan with technical references.
492
492
  assert output["artifact_type"] == "prompt_request"
493
493
  assert "read .authrc" in output["launch_summary"]
494
494
  assert approval_requests[0]["launch_target"] == "Codex prompt for `.authrc`: read .authrc"
495
+ assert approval_requests[0]["action_envelope_json"]["action_type"] == "prompt"
496
+ assert approval_requests[0]["action_envelope_json"]["prompt_excerpt"] == "read .authrc"
495
497
 
496
498
  def test_codex_prompt_display_sanitizes_common_home_paths(self) -> None:
497
499
  display = guard_commands_module._codex_prompt_display_text(
@@ -9418,6 +9420,8 @@ def test_guard_headless_blocked_run_persists_receipts_and_diffs(tmp_path, monkey
9418
9420
  latest_receipt = store.get_latest_receipt("claude-code", baseline.artifact_id)
9419
9421
 
9420
9422
  assert result["blocked"] is True
9423
+ assert result["artifacts"][0]["action_envelope_json"]["action_type"] == "harness_start"
9424
+ assert result["artifacts"][0]["action_envelope_json"]["harness"] == "claude-code"
9421
9425
  assert latest_diff is not None
9422
9426
  assert latest_diff["current_hash"] == artifact_hash(changed)
9423
9427
  assert latest_receipt is not None
File without changes