plugin-scanner 2.0.131__tar.gz → 2.0.133__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 (422) hide show
  1. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/PKG-INFO +1 -1
  2. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/pyproject.toml +1 -1
  3. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/pyproject.toml.bak +1 -1
  4. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/approvals.py +10 -2
  5. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/cli/render.py +10 -1
  6. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/daemon/manager.py +110 -0
  7. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/daemon/server.py +76 -7
  8. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/models.py +1 -0
  9. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/store.py +1 -0
  10. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/store_approvals.py +15 -5
  11. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/version.py +1 -1
  12. plugin_scanner-2.0.133/tests/test_guard_approval_continuity.py +486 -0
  13. plugin_scanner-2.0.133/tests/test_guard_web_recovery.py +190 -0
  14. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.clusterfuzzlite/Dockerfile +0 -0
  15. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.clusterfuzzlite/build.sh +0 -0
  16. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.clusterfuzzlite/project.yaml +0 -0
  17. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.clusterfuzzlite/requirements-atheris.txt +0 -0
  18. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.dockerignore +0 -0
  19. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.github/CODEOWNERS +0 -0
  20. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  21. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  22. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  23. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.github/dependabot.yml +0 -0
  24. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.github/workflows/ci.yml +0 -0
  25. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.github/workflows/codeql.yml +0 -0
  26. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.github/workflows/dependabot-uv-lock.yml +0 -0
  27. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.github/workflows/fuzz.yml +0 -0
  28. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.github/workflows/harness-smoke.yml +0 -0
  29. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.github/workflows/publish.yml +0 -0
  30. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.github/workflows/scorecard.yml +0 -0
  31. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.gitignore +0 -0
  32. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/.pre-commit-hooks.yaml +0 -0
  33. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/CONTRIBUTING.md +0 -0
  34. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/Dockerfile +0 -0
  35. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/LICENSE +0 -0
  36. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/README.md +0 -0
  37. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/SECURITY.md +0 -0
  38. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/index.html +0 -0
  39. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/package.json +0 -0
  40. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/pnpm-lock.yaml +0 -0
  41. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/public/apple-touch-icon.png +0 -0
  42. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
  43. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/public/brand/Logo_Whole.png +0 -0
  44. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/public/favicon-16x16.png +0 -0
  45. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/public/favicon-32x32.png +0 -0
  46. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/public/favicon.ico +0 -0
  47. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/app.tsx +0 -0
  48. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/approval-center-layout.test.ts +0 -0
  49. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/approval-center-layout.tsx +0 -0
  50. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/approval-center-primitives.tsx +0 -0
  51. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/approval-center-review-cards.tsx +0 -0
  52. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/approval-center-utils.ts +0 -0
  53. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/data-flow-evidence-card.tsx +0 -0
  54. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/fleet-workspace.tsx +0 -0
  55. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/guard-api.test.ts +0 -0
  56. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/guard-api.ts +0 -0
  57. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/guard-demo.ts +0 -0
  58. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/guard-types.ts +0 -0
  59. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/main.tsx +0 -0
  60. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/receipts-workspace.test.ts +0 -0
  61. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/receipts-workspace.tsx +0 -0
  62. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/runtime-overview.test.ts +0 -0
  63. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/runtime-overview.tsx +0 -0
  64. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/settings-workspace.test.ts +0 -0
  65. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/settings-workspace.tsx +0 -0
  66. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/styles.css +0 -0
  67. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/src/vite-env.d.ts +0 -0
  68. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/tsconfig.json +0 -0
  69. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/dashboard/vite.config.ts +0 -0
  70. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/docker-requirements.txt +0 -0
  71. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/docs/guard/approval-audit.md +0 -0
  72. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/docs/guard/architecture.md +0 -0
  73. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/docs/guard/get-started.md +0 -0
  74. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/docs/guard/harness-support.md +0 -0
  75. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/docs/guard/local-vs-cloud.md +0 -0
  76. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/docs/guard/release-checklist.md +0 -0
  77. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/docs/guard/smoke-tests.md +0 -0
  78. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/docs/guard/testing-matrix.md +0 -0
  79. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/docs/trust/mcp-trust-draft.md +0 -0
  80. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/docs/trust/plugin-trust-draft.md +0 -0
  81. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/docs/trust/skill-trust-local.md +0 -0
  82. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/fuzzers/manifest_fuzzer.py +0 -0
  83. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/requirements.txt +0 -0
  84. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/schemas/plugin-quality.v1.json +0 -0
  85. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/schemas/scan-result.v1.json +0 -0
  86. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/schemas/verify-result.v1.json +0 -0
  87. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/__init__.py +0 -0
  88. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/action_runner.py +0 -0
  89. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/argparse_utils.py +0 -0
  90. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/checks/__init__.py +0 -0
  91. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
  92. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/checks/claude.py +0 -0
  93. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
  94. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
  95. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/checks/gemini.py +0 -0
  96. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/checks/manifest.py +0 -0
  97. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
  98. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
  99. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
  100. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/checks/opencode.py +0 -0
  101. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
  102. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/checks/security.py +0 -0
  103. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
  104. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/cli.py +0 -0
  105. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/cli_ui.py +0 -0
  106. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/config.py +0 -0
  107. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
  108. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
  109. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
  110. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
  111. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
  112. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
  113. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
  114. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
  115. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
  116. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/github_reporting.py +0 -0
  117. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/__init__.py +0 -0
  118. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/access_graph_events.py +0 -0
  119. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
  120. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
  121. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
  122. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
  123. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +0 -0
  124. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
  125. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/adapters/contracts.py +0 -0
  126. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
  127. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
  128. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
  129. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
  130. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
  131. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
  132. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
  133. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
  134. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
  135. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
  136. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
  137. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
  138. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
  139. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
  140. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
  141. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
  142. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/cli/commands.py +0 -0
  143. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
  144. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
  145. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
  146. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
  147. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
  148. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
  149. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/config.py +0 -0
  150. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
  151. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
  152. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
  153. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
  154. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
  155. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
  156. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
  157. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
  158. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
  159. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
  160. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
  161. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
  162. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
  163. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
  164. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/incident.py +0 -0
  165. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/launcher.py +0 -0
  166. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
  167. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
  168. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
  169. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/protect.py +0 -0
  170. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
  171. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
  172. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
  173. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
  174. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
  175. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
  176. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/redaction.py +0 -0
  177. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/risk.py +0 -0
  178. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
  179. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
  180. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/advisory_escalation.py +0 -0
  181. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/advisory_matchers.py +0 -0
  182. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/data_flow.py +0 -0
  183. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/data_flow_rules.py +0 -0
  184. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/data_flow_variables.py +0 -0
  185. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
  186. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/detectors.py +0 -0
  187. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/mcp_protection.py +0 -0
  188. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/prompt_injection.py +0 -0
  189. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
  190. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/safe_decode.py +0 -0
  191. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/sandbox.py +0 -0
  192. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
  193. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/secret_sensitivity.py +0 -0
  194. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/secret_sources.py +0 -0
  195. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/shell_commands.py +0 -0
  196. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
  197. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/skill_protection.py +0 -0
  198. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/supply_chain.py +0 -0
  199. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
  200. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/temp_files.py +0 -0
  201. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/runtime/threat_intel.py +0 -0
  202. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
  203. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
  204. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
  205. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
  206. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/shims.py +0 -0
  207. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
  208. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/store_evidence.py +0 -0
  209. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/store_threat_intel.py +0 -0
  210. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/guard/types.py +0 -0
  211. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
  212. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
  213. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
  214. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/lint_fixes.py +0 -0
  215. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/marketplace_support.py +0 -0
  216. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/models.py +0 -0
  217. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/path_support.py +0 -0
  218. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/policy.py +0 -0
  219. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/quality_artifact.py +0 -0
  220. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/repo_detect.py +0 -0
  221. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/reporting.py +0 -0
  222. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/rules/__init__.py +0 -0
  223. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/rules/registry.py +0 -0
  224. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/rules/specs.py +0 -0
  225. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/scanner.py +0 -0
  226. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/submission.py +0 -0
  227. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/suppressions.py +0 -0
  228. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
  229. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/trust_helpers.py +0 -0
  230. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
  231. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/trust_models.py +0 -0
  232. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
  233. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/trust_scoring.py +0 -0
  234. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
  235. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/trust_specs.py +0 -0
  236. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/src/codex_plugin_scanner/verification.py +0 -0
  237. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/__init__.py +0 -0
  238. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/conftest.py +0 -0
  239. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/__init__.py +0 -0
  240. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
  241. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/bad-plugin/.mcp.json +0 -0
  242. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/bad-plugin/secrets.js +0 -0
  243. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
  244. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
  245. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/claude-plugin-good/README.md +0 -0
  246. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
  247. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
  248. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
  249. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/code-quality-bad/evil.js +0 -0
  250. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/code-quality-bad/inject.js +0 -0
  251. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
  252. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
  253. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/gemini-extension-good/README.md +0 -0
  254. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
  255. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
  256. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
  257. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
  258. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/good-plugin/.codexignore +0 -0
  259. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/good-plugin/LICENSE +0 -0
  260. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/good-plugin/README.md +0 -0
  261. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/good-plugin/SECURITY.md +0 -0
  262. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
  263. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
  264. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
  265. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
  266. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
  267. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/README.md +0 -0
  268. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/benign-docs-fake-token.py +0 -0
  269. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/benign-health-endpoint.py +0 -0
  270. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/benign-nvmrc-fake-creds.py +0 -0
  271. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/benign-source-search.py +0 -0
  272. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/canary-exfil-encoded.py +0 -0
  273. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/canary-exfil.py +0 -0
  274. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/expected-decisions.json +0 -0
  275. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/malicious-dockerfile.txt +0 -0
  276. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/malicious-encoded-shell-exfil.py +0 -0
  277. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/malicious-github-action.yml +0 -0
  278. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/malicious-mcp-delete.md +0 -0
  279. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/malicious-mcp-secret-read.md +0 -0
  280. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/malicious-mcp-skill-exfil.md +0 -0
  281. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/malicious-npm-postinstall.js +0 -0
  282. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/malicious-prompt-env-read.md +0 -0
  283. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/malicious-prompt-guard-bypass.md +0 -0
  284. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/malicious-prompt-npmrc-read.md +0 -0
  285. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/malicious-python-setup.py +0 -0
  286. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/guard-red-team/smoke-evidence-template.json +0 -0
  287. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
  288. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
  289. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
  290. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
  291. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
  292. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
  293. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
  294. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
  295. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
  296. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
  297. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
  298. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
  299. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
  300. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
  301. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/mcp-canary-server.py +0 -0
  302. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
  303. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
  304. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/mit-license/LICENSE +0 -0
  305. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
  306. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
  307. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
  308. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
  309. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
  310. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
  311. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
  312. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
  313. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
  314. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
  315. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
  316. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
  317. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
  318. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
  319. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
  320. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
  321. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
  322. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
  323. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/opencode-good/LICENSE +0 -0
  324. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/opencode-good/README.md +0 -0
  325. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/opencode-good/SECURITY.md +0 -0
  326. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
  327. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
  328. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
  329. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
  330. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/supply-chain/benign-npm-package.json +0 -0
  331. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/supply-chain/benign-pnpm-package.json +0 -0
  332. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/supply-chain/benign-pyproject.toml +0 -0
  333. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/supply-chain/malicious-Dockerfile +0 -0
  334. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/supply-chain/malicious-action.yml +0 -0
  335. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/supply-chain/malicious-npm-package.json +0 -0
  336. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/supply-chain/malicious-setup.py +0 -0
  337. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
  338. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
  339. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/fixtures/with-marketplace/marketplace.json +0 -0
  340. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test-trust-scoring.py +0 -0
  341. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test-trust-specs.py +0 -0
  342. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_action_runner.py +0 -0
  343. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_best_practices.py +0 -0
  344. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_cisco_install_surfaces.py +0 -0
  345. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_cli.py +0 -0
  346. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_code_quality.py +0 -0
  347. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_config.py +0 -0
  348. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_coverage_remaining.py +0 -0
  349. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_ecosystems.py +0 -0
  350. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_edge_cases.py +0 -0
  351. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_final_coverage.py +0 -0
  352. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_access_graph.py +0 -0
  353. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_advisory_escalation.py +0 -0
  354. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_approval_store_scale.py +0 -0
  355. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_approvals.py +0 -0
  356. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_bootstrap.py +0 -0
  357. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_canary_fixtures.py +0 -0
  358. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_capabilities.py +0 -0
  359. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_claude_adapter.py +0 -0
  360. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_cli.py +0 -0
  361. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_cloud_local_sync.py +0 -0
  362. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_codex_e2e.py +0 -0
  363. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_codex_install.py +0 -0
  364. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_codex_proxy.py +0 -0
  365. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_config_paths.py +0 -0
  366. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_connect_flow.py +0 -0
  367. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_consumer_mode.py +0 -0
  368. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_copilot_adapter.py +0 -0
  369. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_copilot_proxy.py +0 -0
  370. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_daemon_manager.py +0 -0
  371. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_daemon_perf.py +0 -0
  372. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_data_flow.py +0 -0
  373. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_event_schema_v1.py +0 -0
  374. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_events.py +0 -0
  375. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_evidence_store.py +0 -0
  376. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_harness_contracts.py +0 -0
  377. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_launch_env.py +0 -0
  378. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_mcp_protection.py +0 -0
  379. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_opencode_proxy.py +0 -0
  380. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_product_flow.py +0 -0
  381. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_prompt_injection.py +0 -0
  382. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_protect.py +0 -0
  383. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_red_team.py +0 -0
  384. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_render.py +0 -0
  385. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_risk.py +0 -0
  386. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_runtime.py +0 -0
  387. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_runtime_action_harnesses.py +0 -0
  388. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_runtime_actions.py +0 -0
  389. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_runtime_decisions.py +0 -0
  390. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_runtime_detectors.py +0 -0
  391. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_runtime_signals.py +0 -0
  392. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_safe_decode.py +0 -0
  393. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_sandbox.py +0 -0
  394. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_skill_protection.py +0 -0
  395. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_store_migrations.py +0 -0
  396. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_supply_chain.py +0 -0
  397. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_surface_server.py +0 -0
  398. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_threat_intel.py +0 -0
  399. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_guard_verdicts.py +0 -0
  400. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_hermes_adapter.py +0 -0
  401. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_integration.py +0 -0
  402. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_lint_fixes.py +0 -0
  403. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_live_cisco_smoke.py +0 -0
  404. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_manifest.py +0 -0
  405. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_marketplace.py +0 -0
  406. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_mcp_security.py +0 -0
  407. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_openclaw_adapter.py +0 -0
  408. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_operational_security.py +0 -0
  409. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_policy.py +0 -0
  410. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_quality_artifact.py +0 -0
  411. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_rule_registry.py +0 -0
  412. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_scanner.py +0 -0
  413. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_schema_contracts.py +0 -0
  414. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_security.py +0 -0
  415. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_security_ops.py +0 -0
  416. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_skill_security.py +0 -0
  417. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_submission.py +0 -0
  418. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_trust_scoring.py +0 -0
  419. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_trust_specs.py +0 -0
  420. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_verification.py +0 -0
  421. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/tests/test_versioning.py +0 -0
  422. {plugin_scanner-2.0.131 → plugin_scanner-2.0.133}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 2.0.131
3
+ Version: 2.0.133
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.131"
7
+ version = "2.0.133"
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.131"
7
+ version = "2.0.133"
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"
@@ -24,6 +24,14 @@ GUARD_FLEET_URL = f"{GUARD_DASHBOARD_URL}/fleet"
24
24
  GUARD_CONNECT_URL = f"{GUARD_DASHBOARD_URL}/connect"
25
25
 
26
26
 
27
+ class ApprovalRequestNotFoundError(ValueError):
28
+ """Raised when an approval request ID does not exist."""
29
+
30
+
31
+ class ApprovalRequestAlreadyResolvedError(ValueError):
32
+ """Raised when an approval request was already resolved."""
33
+
34
+
27
35
  def queue_blocked_approvals(
28
36
  *,
29
37
  detection: HarnessDetection,
@@ -114,9 +122,9 @@ def apply_approval_resolution(
114
122
  ) -> dict[str, object]:
115
123
  request = store.get_approval_request(request_id)
116
124
  if request is None:
117
- raise ValueError(f"Unknown approval request: {request_id}")
125
+ raise ApprovalRequestNotFoundError(f"Unknown approval request: {request_id}")
118
126
  if request["status"] != "pending":
119
- raise ValueError(f"Approval request already resolved: {request_id}")
127
+ raise ApprovalRequestAlreadyResolvedError(f"Approval request already resolved: {request_id}")
120
128
  if scope == "workspace" and not workspace:
121
129
  raise ValueError(f"Approval request {request_id} requires --workspace for workspace scope.")
122
130
  if scope == "publisher" and not isinstance(request.get("publisher"), str):
@@ -1768,6 +1768,15 @@ def _build_approval_table(items: list[dict[str, object]], *, title: str | None)
1768
1768
  table.add_row("—", "—", "No pending approvals", "—", "—", "—", "—")
1769
1769
  return table
1770
1770
  for item in items:
1771
+ approval_url = item.get("approval_url")
1772
+ fallback_cli = item.get("fallback_cli_command")
1773
+ review_cmd = str(item.get("review_command") or "hol-guard approvals")
1774
+ if approval_url and fallback_cli:
1775
+ resolve_text = f"{approval_url}\n or: {fallback_cli}"
1776
+ elif approval_url:
1777
+ resolve_text = str(approval_url)
1778
+ else:
1779
+ resolve_text = review_cmd
1771
1780
  table.add_row(
1772
1781
  str(item.get("request_id") or "unknown"),
1773
1782
  str(item.get("harness") or "unknown"),
@@ -1775,7 +1784,7 @@ def _build_approval_table(items: list[dict[str, object]], *, title: str | None)
1775
1784
  ", ".join(_coerce_string_list(item.get("changed_fields"))) or "none",
1776
1785
  str(item.get("risk_summary") or "no obvious secret/network signal"),
1777
1786
  _action_text(str(item.get("policy_action") or "warn")),
1778
- str(item.get("review_command") or "hol-guard approvals"),
1787
+ resolve_text,
1779
1788
  )
1780
1789
  return table
1781
1790
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import dataclasses
5
6
  import hashlib
6
7
  import json
7
8
  import os
@@ -33,6 +34,7 @@ _EPHEMERAL_GUARD_DAEMON_STALE_SECONDS = 30.0
33
34
  _EPHEMERAL_GUARD_DAEMON_MAX_STATES = 512
34
35
  _GUARD_DAEMON_PRIVATE_FILE_MODE = 0o600
35
36
  _GUARD_DAEMON_PRIVATE_DIR_MODE = 0o700
37
+ _APPROVAL_CENTER_LOCATOR_FILE = "approval-center-locator.json"
36
38
 
37
39
  _START_LOCKS: dict[str, threading.Lock] = {}
38
40
  _START_LOCKS_GUARD = threading.Lock()
@@ -40,6 +42,18 @@ _LAST_EPHEMERAL_REAP_AT = 0.0
40
42
  _RUNTIME_FINGERPRINT_CACHE: str | None = None
41
43
 
42
44
 
45
+ @dataclasses.dataclass(frozen=True, slots=True)
46
+ class ApprovalCenterLocator:
47
+ """Structured snapshot of where the Guard approval-center daemon is running."""
48
+
49
+ guard_home: Path
50
+ daemon_url: str
51
+ approval_url_base: str
52
+ pid: int
53
+ started_at: str
54
+ state_path: Path
55
+
56
+
43
57
  def _daemon_launcher_env() -> dict[str, str]:
44
58
  env = dict(os.environ)
45
59
  pythonpath_entries: list[str] = []
@@ -173,6 +187,102 @@ def clear_guard_daemon_state(guard_home: Path) -> None:
173
187
  _write_private_text(state_path, "{}")
174
188
 
175
189
 
190
+ def _locator_path(guard_home: Path) -> Path:
191
+ return guard_home / _APPROVAL_CENTER_LOCATOR_FILE
192
+
193
+
194
+ def write_approval_center_locator(guard_home: Path, locator: ApprovalCenterLocator) -> None:
195
+ locator_path = _locator_path(guard_home)
196
+ _ensure_private_directory(locator_path.parent)
197
+ payload = {
198
+ "guard_home": str(locator.guard_home),
199
+ "daemon_url": locator.daemon_url,
200
+ "approval_url_base": locator.approval_url_base,
201
+ "pid": locator.pid,
202
+ "started_at": locator.started_at,
203
+ "state_path": str(locator.state_path),
204
+ }
205
+ _write_private_text(locator_path, json.dumps(payload, indent=2))
206
+
207
+
208
+ def read_approval_center_locator(guard_home: Path) -> ApprovalCenterLocator | None:
209
+ locator_path = _locator_path(guard_home)
210
+ if not locator_path.is_file():
211
+ return None
212
+ try:
213
+ payload = json.loads(locator_path.read_text(encoding="utf-8"))
214
+ except (OSError, json.JSONDecodeError):
215
+ return None
216
+ if not isinstance(payload, dict):
217
+ return None
218
+ pid = payload.get("pid")
219
+ if not isinstance(pid, int) or pid <= 0:
220
+ return None
221
+ if not _guard_daemon_pid_is_running(pid):
222
+ return None
223
+ if not _guard_daemon_pid_matches_command(pid, expected_guard_home=guard_home):
224
+ return None
225
+ daemon_url = payload.get("daemon_url")
226
+ approval_url_base = payload.get("approval_url_base")
227
+ started_at = payload.get("started_at")
228
+ state_path_str = payload.get("state_path")
229
+ guard_home_str = payload.get("guard_home")
230
+ if not all(isinstance(v, str) for v in (daemon_url, approval_url_base, started_at, state_path_str, guard_home_str)):
231
+ return None
232
+ return ApprovalCenterLocator(
233
+ guard_home=Path(guard_home_str),
234
+ daemon_url=daemon_url,
235
+ approval_url_base=approval_url_base,
236
+ pid=pid,
237
+ started_at=started_at,
238
+ state_path=Path(state_path_str),
239
+ )
240
+
241
+
242
+ def _approval_center_daemon_is_healthy(daemon_url: str) -> bool:
243
+ try:
244
+ with urllib.request.urlopen(f"{daemon_url}/healthz", timeout=1) as response:
245
+ if response.status != 200:
246
+ return False
247
+ return _healthz_payload_is_current(response.read().decode("utf-8"))
248
+ except (OSError, ValueError, urllib.error.URLError):
249
+ return False
250
+
251
+
252
+ def _daemon_state_pid_matches_locator(guard_home: Path, locator_pid: int) -> bool:
253
+ state = _load_state(guard_home)
254
+ if not isinstance(state, dict):
255
+ return False
256
+ state_pid = state.get("pid")
257
+ return isinstance(state_pid, int) and state_pid == locator_pid
258
+
259
+
260
+ def ensure_approval_center(guard_home: Path) -> ApprovalCenterLocator:
261
+ existing = read_approval_center_locator(guard_home)
262
+ if (
263
+ existing is not None
264
+ and _approval_center_daemon_is_healthy(existing.daemon_url)
265
+ and _daemon_state_pid_matches_locator(guard_home, existing.pid)
266
+ ):
267
+ return existing
268
+ daemon_url = ensure_guard_daemon(guard_home)
269
+ now = datetime.now(tz=timezone.utc).isoformat()
270
+ state = _load_state(guard_home)
271
+ pid = state.get("pid") if isinstance(state, dict) else None
272
+ if not isinstance(pid, int) or pid <= 0:
273
+ pid = os.getpid()
274
+ locator = ApprovalCenterLocator(
275
+ guard_home=guard_home,
276
+ daemon_url=daemon_url,
277
+ approval_url_base=daemon_url,
278
+ pid=pid,
279
+ started_at=now,
280
+ state_path=_state_path(guard_home),
281
+ )
282
+ write_approval_center_locator(guard_home, locator)
283
+ return locator
284
+
285
+
176
286
  def _load_state(guard_home: Path) -> dict[str, object] | None:
177
287
  state_path = _state_path(guard_home)
178
288
  if not state_path.is_file():
@@ -18,7 +18,12 @@ from typing import Any
18
18
  from urllib.parse import parse_qs, parse_qsl, unquote, urlencode, urlparse, urlunparse
19
19
 
20
20
  from ...version import __version__
21
- from ..approvals import apply_approval_resolution, build_runtime_snapshot
21
+ from ..approvals import (
22
+ ApprovalRequestAlreadyResolvedError,
23
+ ApprovalRequestNotFoundError,
24
+ apply_approval_resolution,
25
+ build_runtime_snapshot,
26
+ )
22
27
  from ..config import editable_guard_settings, load_guard_config, update_guard_settings
23
28
  from ..models import DECISION_SCOPE_VALUES, GUARD_ACTION_VALUES
24
29
  from ..runtime.surface_server import GuardSurfaceRuntime
@@ -183,7 +188,17 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
183
188
  if len(path_parts) == 3 and path_parts[:2] == ["v1", "requests"]:
184
189
  approval = store.get_approval_request(path_parts[2])
185
190
  if approval is None:
186
- self._write_json({"error": "not_found"}, status=404)
191
+ self._write_json(
192
+ {
193
+ "error": "not_found",
194
+ "recovery": {
195
+ "code": "request_unknown",
196
+ "title": "This request is no longer waiting.",
197
+ "body": "The request was either already resolved or expired. You can close this tab.",
198
+ },
199
+ },
200
+ status=404,
201
+ )
187
202
  return
188
203
  self._write_json(approval)
189
204
  return
@@ -313,11 +328,29 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
313
328
  self._write_json({"error": "forbidden_origin"}, status=403)
314
329
  return
315
330
  if self._requires_header_token(parsed.path, path_parts) and not self._header_token_is_valid():
316
- self._write_json(
317
- {"error": "unauthorized"},
318
- status=401,
319
- extra_headers=self._cors_headers_for_request(),
320
- )
331
+ if len(path_parts) == 4 and path_parts[:2] == ["v1", "requests"] and path_parts[3] in {"approve", "block"}:
332
+ host = self.server.server_address[0] # type: ignore[attr-defined]
333
+ port = self.server.server_address[1] # type: ignore[attr-defined]
334
+ reconnect_url = _build_local_url(host, port, "/#/reconnect")
335
+ self._write_json(
336
+ {
337
+ "error": "unauthorized",
338
+ "recovery": {
339
+ "code": "session_stale",
340
+ "title": "Your session with the local Guard daemon has expired.",
341
+ "body": "Click the link below to reconnect, then retry your approval.",
342
+ "reconnect_url": reconnect_url,
343
+ },
344
+ },
345
+ status=401,
346
+ extra_headers=self._cors_headers_for_request(),
347
+ )
348
+ else:
349
+ self._write_json(
350
+ {"error": "unauthorized"},
351
+ status=401,
352
+ extra_headers=self._cors_headers_for_request(),
353
+ )
321
354
  return
322
355
  payload, body_error = self._load_request_body()
323
356
  if body_error is not None:
@@ -389,6 +422,37 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
389
422
  workspace=self._optional_string(payload.get("workspace")),
390
423
  reason=self._optional_string(payload.get("reason")),
391
424
  )
425
+ except ApprovalRequestNotFoundError:
426
+ self._write_json(
427
+ {
428
+ "resolved": False,
429
+ "error": "not_found",
430
+ "recovery": {
431
+ "code": "request_unknown",
432
+ "title": "This request is no longer waiting.",
433
+ "body": "The request was either already resolved or expired. You can close this tab.",
434
+ },
435
+ },
436
+ status=404,
437
+ )
438
+ return
439
+ except ApprovalRequestAlreadyResolvedError:
440
+ self._write_json(
441
+ {
442
+ "resolved": False,
443
+ "error": "already_resolved",
444
+ "recovery": {
445
+ "code": "request_resolved",
446
+ "title": "This request has already been resolved.",
447
+ "body": (
448
+ "If the action is blocked and you believe it should be allowed, "
449
+ "you can re-submit from your AI assistant."
450
+ ),
451
+ },
452
+ },
453
+ status=409,
454
+ )
455
+ return
392
456
  except ValueError as error:
393
457
  self._write_json({"resolved": False, "error": str(error)}, status=400)
394
458
  return
@@ -1319,6 +1383,11 @@ def _approval_center_browser_url(approval_center_url: str, auth_token: str) -> s
1319
1383
  return urlunparse(parsed._replace(fragment=urlencode(fragment_pairs)))
1320
1384
 
1321
1385
 
1386
+ def _build_local_url(host: str, port: int, path: str) -> str:
1387
+ host_part = f"[{host}]" if ":" in host else host
1388
+ return f"http://{host_part}:{port}{path}"
1389
+
1390
+
1322
1391
  def _now() -> str:
1323
1392
  from datetime import datetime, timezone
1324
1393
 
@@ -180,6 +180,7 @@ class GuardApprovalRequest:
180
180
  risk_headline: str | None = None
181
181
  action_envelope_json: dict[str, object] | None = None
182
182
  decision_v2_json: dict[str, object] | None = None
183
+ fallback_cli_command: str | None = None
183
184
 
184
185
  def to_dict(self) -> dict[str, object]:
185
186
  payload = asdict(self)
@@ -686,6 +686,7 @@ class GuardStore:
686
686
  self._ensure_approval_column(connection, "action_envelope_json", "text")
687
687
  self._ensure_approval_column(connection, "decision_v2_json", "text")
688
688
  self._ensure_approval_column(connection, "workspace", "text")
689
+ self._ensure_approval_column(connection, "fallback_cli_command", "text")
689
690
  self._ensure_attachment_column(connection, "lease_id", "text not null default ''")
690
691
  self._ensure_attachment_column(connection, "lease_expires_at", "text")
691
692
  self._ensure_local_device(connection)
@@ -36,6 +36,7 @@ def approval_schema_statement() -> str:
36
36
  risk_headline text,
37
37
  action_envelope_json text,
38
38
  decision_v2_json text,
39
+ fallback_cli_command text,
39
40
  review_command text not null,
40
41
  approval_url text not null,
41
42
  status text not null,
@@ -70,7 +71,7 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
70
71
  recommended_scope = ?, changed_fields_json = ?, source_scope = ?, config_path = ?, workspace = ?,
71
72
  launch_target = ?, transport = ?, risk_summary = ?, risk_signals_json = ?,
72
73
  artifact_label = ?, source_label = ?, trigger_summary = ?, why_now = ?, launch_summary = ?,
73
- risk_headline = ?, action_envelope_json = ?, decision_v2_json = ?,
74
+ risk_headline = ?, action_envelope_json = ?, decision_v2_json = ?, fallback_cli_command = ?,
74
75
  review_command = ?, approval_url = ?, created_at = ?
75
76
  where request_id = ?
76
77
  """,
@@ -97,6 +98,11 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
97
98
  request.risk_headline,
98
99
  json.dumps(request.action_envelope_json) if request.action_envelope_json is not None else None,
99
100
  json.dumps(request.decision_v2_json) if request.decision_v2_json is not None else None,
101
+ (
102
+ _rewrite_review_command(request.fallback_cli_command, request_id)
103
+ if request.fallback_cli_command
104
+ else None
105
+ ),
100
106
  review_command,
101
107
  approval_url,
102
108
  now,
@@ -111,10 +117,10 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
111
117
  recommended_scope, changed_fields_json, source_scope, config_path, workspace,
112
118
  launch_target, transport, risk_summary,
113
119
  risk_signals_json, artifact_label, source_label, trigger_summary, why_now, launch_summary, risk_headline,
114
- action_envelope_json, decision_v2_json, review_command,
120
+ action_envelope_json, decision_v2_json, fallback_cli_command, review_command,
115
121
  approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
116
122
  )
117
- values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
123
+ values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
118
124
  """,
119
125
  (
120
126
  request.request_id,
@@ -142,6 +148,7 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
142
148
  request.risk_headline,
143
149
  json.dumps(request.action_envelope_json) if request.action_envelope_json is not None else None,
144
150
  json.dumps(request.decision_v2_json) if request.decision_v2_json is not None else None,
151
+ request.fallback_cli_command,
145
152
  request.review_command,
146
153
  request.approval_url,
147
154
  "pending",
@@ -211,7 +218,8 @@ def list_approval_requests(
211
218
  select request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher, policy_action,
212
219
  recommended_scope, changed_fields_json, source_scope, config_path, workspace, launch_target, transport,
213
220
  risk_summary, risk_signals_json, artifact_label, source_label, trigger_summary, why_now,
214
- launch_summary, risk_headline, action_envelope_json, decision_v2_json, review_command,
221
+ launch_summary, risk_headline, action_envelope_json, decision_v2_json,
222
+ fallback_cli_command, review_command,
215
223
  approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
216
224
  from approval_requests
217
225
  {where_clause}
@@ -230,7 +238,8 @@ def get_approval_request(connection: sqlite3.Connection, request_id: str) -> dic
230
238
  select request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher, policy_action,
231
239
  recommended_scope, changed_fields_json, source_scope, config_path, workspace, launch_target, transport,
232
240
  risk_summary, risk_signals_json, artifact_label, source_label, trigger_summary, why_now,
233
- launch_summary, risk_headline, action_envelope_json, decision_v2_json, review_command,
241
+ launch_summary, risk_headline, action_envelope_json, decision_v2_json,
242
+ fallback_cli_command, review_command,
234
243
  approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
235
244
  from approval_requests
236
245
  where request_id = ?
@@ -311,6 +320,7 @@ def _row_to_payload(row: sqlite3.Row) -> dict[str, object]:
311
320
  "risk_headline": row["risk_headline"],
312
321
  "action_envelope_json": _optional_json_object(row["action_envelope_json"]),
313
322
  "decision_v2_json": _optional_json_object(row["decision_v2_json"]),
323
+ "fallback_cli_command": row["fallback_cli_command"],
314
324
  "review_command": str(row["review_command"]),
315
325
  "approval_url": str(row["approval_url"]),
316
326
  "status": str(row["status"]),
@@ -1,3 +1,3 @@
1
1
  """Single source of truth for tool version."""
2
2
 
3
- __version__ = "2.0.131"
3
+ __version__ = "2.0.133"