plugin-scanner 2.0.92__tar.gz → 2.0.94__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 (340) hide show
  1. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/PKG-INFO +1 -1
  2. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/package.json +3 -1
  3. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/pnpm-lock.yaml +36 -8
  4. plugin_scanner-2.0.94/dashboard/src/guard-api.test.ts +18 -0
  5. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/src/guard-api.ts +130 -43
  6. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/src/guard-types.ts +12 -0
  7. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/pyproject.toml +1 -1
  8. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/pyproject.toml.bak +1 -1
  9. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/approvals.py +10 -0
  10. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/cli/connect_flow.py +1 -0
  11. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/cli/render.py +2 -1
  12. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/daemon/server.py +70 -14
  13. plugin_scanner-2.0.94/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +9 -0
  14. plugin_scanner-2.0.94/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +1 -0
  15. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/runtime/runner.py +14 -8
  16. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/schemas/surface_server.py +72 -0
  17. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/version.py +1 -1
  18. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_approvals.py +104 -0
  19. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_connect_flow.py +60 -0
  20. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_runtime.py +61 -0
  21. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_surface_server.py +24 -0
  22. plugin_scanner-2.0.92/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -9
  23. plugin_scanner-2.0.92/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -1
  24. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.clusterfuzzlite/Dockerfile +0 -0
  25. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.clusterfuzzlite/build.sh +0 -0
  26. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.clusterfuzzlite/project.yaml +0 -0
  27. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.clusterfuzzlite/requirements-atheris.txt +0 -0
  28. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.dockerignore +0 -0
  29. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.github/CODEOWNERS +0 -0
  30. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  31. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  32. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  33. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.github/dependabot.yml +0 -0
  34. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.github/workflows/ci.yml +0 -0
  35. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.github/workflows/codeql.yml +0 -0
  36. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.github/workflows/dependabot-uv-lock.yml +0 -0
  37. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.github/workflows/fuzz.yml +0 -0
  38. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.github/workflows/harness-smoke.yml +0 -0
  39. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.github/workflows/publish.yml +0 -0
  40. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.github/workflows/scorecard.yml +0 -0
  41. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.gitignore +0 -0
  42. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/.pre-commit-hooks.yaml +0 -0
  43. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/CONTRIBUTING.md +0 -0
  44. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/Dockerfile +0 -0
  45. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/LICENSE +0 -0
  46. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/README.md +0 -0
  47. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/SECURITY.md +0 -0
  48. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/index.html +0 -0
  49. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/public/apple-touch-icon.png +0 -0
  50. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
  51. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/public/brand/Logo_Whole.png +0 -0
  52. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/public/favicon-16x16.png +0 -0
  53. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/public/favicon-32x32.png +0 -0
  54. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/public/favicon.ico +0 -0
  55. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/src/app.tsx +0 -0
  56. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/src/approval-center-layout.tsx +0 -0
  57. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/src/approval-center-primitives.tsx +0 -0
  58. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/src/approval-center-utils.ts +0 -0
  59. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/src/fleet-workspace.tsx +0 -0
  60. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/src/guard-demo.ts +0 -0
  61. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/src/main.tsx +0 -0
  62. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/src/receipts-workspace.tsx +0 -0
  63. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/src/runtime-overview.tsx +0 -0
  64. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/src/settings-workspace.tsx +0 -0
  65. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/src/styles.css +0 -0
  66. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/src/vite-env.d.ts +0 -0
  67. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/tsconfig.json +0 -0
  68. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/dashboard/vite.config.ts +0 -0
  69. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/docker-requirements.txt +0 -0
  70. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/docs/guard/approval-audit.md +0 -0
  71. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/docs/guard/architecture.md +0 -0
  72. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/docs/guard/get-started.md +0 -0
  73. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/docs/guard/harness-support.md +0 -0
  74. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/docs/guard/local-vs-cloud.md +0 -0
  75. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/docs/guard/testing-matrix.md +0 -0
  76. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/docs/trust/mcp-trust-draft.md +0 -0
  77. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/docs/trust/plugin-trust-draft.md +0 -0
  78. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/docs/trust/skill-trust-local.md +0 -0
  79. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/fuzzers/manifest_fuzzer.py +0 -0
  80. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/requirements.txt +0 -0
  81. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/schemas/plugin-quality.v1.json +0 -0
  82. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/schemas/scan-result.v1.json +0 -0
  83. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/schemas/verify-result.v1.json +0 -0
  84. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/__init__.py +0 -0
  85. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/action_runner.py +0 -0
  86. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/argparse_utils.py +0 -0
  87. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/checks/__init__.py +0 -0
  88. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
  89. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/checks/claude.py +0 -0
  90. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
  91. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
  92. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/checks/gemini.py +0 -0
  93. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/checks/manifest.py +0 -0
  94. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
  95. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
  96. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
  97. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/checks/opencode.py +0 -0
  98. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
  99. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/checks/security.py +0 -0
  100. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
  101. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/cli.py +0 -0
  102. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/cli_ui.py +0 -0
  103. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/config.py +0 -0
  104. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
  105. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
  106. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
  107. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
  108. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
  109. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
  110. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
  111. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
  112. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
  113. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/github_reporting.py +0 -0
  114. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/__init__.py +0 -0
  115. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
  116. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
  117. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
  118. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
  119. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
  120. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
  121. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
  122. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
  123. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
  124. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
  125. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
  126. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
  127. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
  128. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
  129. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
  130. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
  131. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
  132. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
  133. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
  134. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
  135. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
  136. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/cli/commands.py +0 -0
  137. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
  138. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
  139. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
  140. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
  141. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
  142. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/config.py +0 -0
  143. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
  144. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
  145. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
  146. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
  147. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
  148. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
  149. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
  150. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
  151. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
  152. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
  153. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
  154. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
  155. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
  156. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/incident.py +0 -0
  157. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/launcher.py +0 -0
  158. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
  159. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/models.py +0 -0
  160. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
  161. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
  162. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/protect.py +0 -0
  163. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
  164. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
  165. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
  166. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
  167. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
  168. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
  169. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/redaction.py +0 -0
  170. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/risk.py +0 -0
  171. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
  172. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
  173. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
  174. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
  175. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
  176. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
  177. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/shims.py +0 -0
  178. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/store.py +0 -0
  179. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
  180. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
  181. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/guard/types.py +0 -0
  182. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
  183. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
  184. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
  185. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/lint_fixes.py +0 -0
  186. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/marketplace_support.py +0 -0
  187. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/models.py +0 -0
  188. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/path_support.py +0 -0
  189. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/policy.py +0 -0
  190. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/quality_artifact.py +0 -0
  191. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/repo_detect.py +0 -0
  192. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/reporting.py +0 -0
  193. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/rules/__init__.py +0 -0
  194. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/rules/registry.py +0 -0
  195. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/rules/specs.py +0 -0
  196. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/scanner.py +0 -0
  197. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/submission.py +0 -0
  198. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/suppressions.py +0 -0
  199. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
  200. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/trust_helpers.py +0 -0
  201. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
  202. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/trust_models.py +0 -0
  203. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
  204. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/trust_scoring.py +0 -0
  205. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
  206. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/trust_specs.py +0 -0
  207. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/src/codex_plugin_scanner/verification.py +0 -0
  208. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/__init__.py +0 -0
  209. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/conftest.py +0 -0
  210. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/__init__.py +0 -0
  211. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
  212. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/bad-plugin/.mcp.json +0 -0
  213. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/bad-plugin/secrets.js +0 -0
  214. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
  215. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
  216. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/claude-plugin-good/README.md +0 -0
  217. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
  218. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
  219. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
  220. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/code-quality-bad/evil.js +0 -0
  221. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/code-quality-bad/inject.js +0 -0
  222. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
  223. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
  224. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/gemini-extension-good/README.md +0 -0
  225. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
  226. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
  227. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
  228. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
  229. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/good-plugin/.codexignore +0 -0
  230. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/good-plugin/LICENSE +0 -0
  231. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/good-plugin/README.md +0 -0
  232. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/good-plugin/SECURITY.md +0 -0
  233. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
  234. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
  235. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
  236. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
  237. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
  238. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
  239. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
  240. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
  241. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
  242. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
  243. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
  244. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
  245. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
  246. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
  247. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
  248. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
  249. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
  250. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
  251. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
  252. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/mcp-canary-server.py +0 -0
  253. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
  254. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
  255. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/mit-license/LICENSE +0 -0
  256. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
  257. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
  258. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
  259. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
  260. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
  261. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
  262. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
  263. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
  264. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
  265. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
  266. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
  267. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
  268. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
  269. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
  270. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
  271. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
  272. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
  273. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
  274. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/opencode-good/LICENSE +0 -0
  275. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/opencode-good/README.md +0 -0
  276. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/opencode-good/SECURITY.md +0 -0
  277. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
  278. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
  279. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
  280. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
  281. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
  282. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
  283. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/fixtures/with-marketplace/marketplace.json +0 -0
  284. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test-trust-scoring.py +0 -0
  285. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test-trust-specs.py +0 -0
  286. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_action_runner.py +0 -0
  287. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_best_practices.py +0 -0
  288. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_cisco_install_surfaces.py +0 -0
  289. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_cli.py +0 -0
  290. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_code_quality.py +0 -0
  291. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_config.py +0 -0
  292. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_coverage_remaining.py +0 -0
  293. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_ecosystems.py +0 -0
  294. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_edge_cases.py +0 -0
  295. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_final_coverage.py +0 -0
  296. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_bootstrap.py +0 -0
  297. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_capabilities.py +0 -0
  298. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_claude_adapter.py +0 -0
  299. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_cli.py +0 -0
  300. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_codex_e2e.py +0 -0
  301. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_codex_install.py +0 -0
  302. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_codex_proxy.py +0 -0
  303. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_config_paths.py +0 -0
  304. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_consumer_mode.py +0 -0
  305. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_copilot_adapter.py +0 -0
  306. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_copilot_proxy.py +0 -0
  307. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_daemon_manager.py +0 -0
  308. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_event_schema_v1.py +0 -0
  309. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_events.py +0 -0
  310. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_launch_env.py +0 -0
  311. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_opencode_proxy.py +0 -0
  312. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_product_flow.py +0 -0
  313. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_protect.py +0 -0
  314. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_render.py +0 -0
  315. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_risk.py +0 -0
  316. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_store_migrations.py +0 -0
  317. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_guard_verdicts.py +0 -0
  318. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_hermes_adapter.py +0 -0
  319. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_integration.py +0 -0
  320. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_lint_fixes.py +0 -0
  321. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_live_cisco_smoke.py +0 -0
  322. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_manifest.py +0 -0
  323. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_marketplace.py +0 -0
  324. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_mcp_security.py +0 -0
  325. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_openclaw_adapter.py +0 -0
  326. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_operational_security.py +0 -0
  327. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_policy.py +0 -0
  328. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_quality_artifact.py +0 -0
  329. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_rule_registry.py +0 -0
  330. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_scanner.py +0 -0
  331. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_schema_contracts.py +0 -0
  332. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_security.py +0 -0
  333. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_security_ops.py +0 -0
  334. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_skill_security.py +0 -0
  335. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_submission.py +0 -0
  336. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_trust_scoring.py +0 -0
  337. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_trust_specs.py +0 -0
  338. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_verification.py +0 -0
  339. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/tests/test_versioning.py +0 -0
  340. {plugin_scanner-2.0.92 → plugin_scanner-2.0.94}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 2.0.92
3
+ Version: 2.0.94
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,8 @@
4
4
  "version": "0.0.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
- "build": "vite build"
7
+ "build": "vite build",
8
+ "test": "tsx src/guard-api.test.ts"
8
9
  },
9
10
  "dependencies": {
10
11
  "react": "^19.2.0",
@@ -17,6 +18,7 @@
17
18
  "@types/react-dom": "^19.2.2",
18
19
  "@vitejs/plugin-react": "^5.0.4",
19
20
  "tailwindcss": "^4.1.4",
21
+ "tsx": "^4.8.1",
20
22
  "typescript": "^5.9.3",
21
23
  "vite": "^7.1.10"
22
24
  }
@@ -20,7 +20,7 @@ importers:
20
20
  devDependencies:
21
21
  '@tailwindcss/vite':
22
22
  specifier: ^4.1.4
23
- version: 4.2.2(vite@7.3.2(jiti@2.6.1)(lightningcss@1.32.0))
23
+ version: 4.2.2(vite@7.3.2(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))
24
24
  '@types/react':
25
25
  specifier: ^19.2.2
26
26
  version: 19.2.14
@@ -29,16 +29,19 @@ importers:
29
29
  version: 19.2.3(@types/react@19.2.14)
30
30
  '@vitejs/plugin-react':
31
31
  specifier: ^5.0.4
32
- version: 5.2.0(vite@7.3.2(jiti@2.6.1)(lightningcss@1.32.0))
32
+ version: 5.2.0(vite@7.3.2(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))
33
33
  tailwindcss:
34
34
  specifier: ^4.1.4
35
35
  version: 4.2.2
36
+ tsx:
37
+ specifier: ^4.8.1
38
+ version: 4.21.0
36
39
  typescript:
37
40
  specifier: ^5.9.3
38
41
  version: 5.9.3
39
42
  vite:
40
43
  specifier: ^7.1.10
41
- version: 7.3.2(jiti@2.6.1)(lightningcss@1.32.0)
44
+ version: 7.3.2(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
42
45
 
43
46
  packages:
44
47
 
@@ -610,6 +613,9 @@ packages:
610
613
  resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
611
614
  engines: {node: '>=6.9.0'}
612
615
 
616
+ get-tsconfig@4.14.0:
617
+ resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==}
618
+
613
619
  graceful-fs@4.2.11:
614
620
  resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
615
621
 
@@ -746,6 +752,9 @@ packages:
746
752
  resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==}
747
753
  engines: {node: '>=0.10.0'}
748
754
 
755
+ resolve-pkg-maps@1.0.0:
756
+ resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
757
+
749
758
  rollup@4.60.1:
750
759
  resolution: {integrity: sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==}
751
760
  engines: {node: '>=18.0.0', npm: '>=8.0.0'}
@@ -773,6 +782,11 @@ packages:
773
782
  resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==}
774
783
  engines: {node: '>=12.0.0'}
775
784
 
785
+ tsx@4.21.0:
786
+ resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==}
787
+ engines: {node: '>=18.0.0'}
788
+ hasBin: true
789
+
776
790
  typescript@5.9.3:
777
791
  resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
778
792
  engines: {node: '>=14.17'}
@@ -1176,12 +1190,12 @@ snapshots:
1176
1190
  '@tailwindcss/oxide-win32-arm64-msvc': 4.2.2
1177
1191
  '@tailwindcss/oxide-win32-x64-msvc': 4.2.2
1178
1192
 
1179
- '@tailwindcss/vite@4.2.2(vite@7.3.2(jiti@2.6.1)(lightningcss@1.32.0))':
1193
+ '@tailwindcss/vite@4.2.2(vite@7.3.2(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))':
1180
1194
  dependencies:
1181
1195
  '@tailwindcss/node': 4.2.2
1182
1196
  '@tailwindcss/oxide': 4.2.2
1183
1197
  tailwindcss: 4.2.2
1184
- vite: 7.3.2(jiti@2.6.1)(lightningcss@1.32.0)
1198
+ vite: 7.3.2(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
1185
1199
 
1186
1200
  '@types/babel__core@7.20.5':
1187
1201
  dependencies:
@@ -1214,7 +1228,7 @@ snapshots:
1214
1228
  dependencies:
1215
1229
  csstype: 3.2.3
1216
1230
 
1217
- '@vitejs/plugin-react@5.2.0(vite@7.3.2(jiti@2.6.1)(lightningcss@1.32.0))':
1231
+ '@vitejs/plugin-react@5.2.0(vite@7.3.2(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))':
1218
1232
  dependencies:
1219
1233
  '@babel/core': 7.29.0
1220
1234
  '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0)
@@ -1222,7 +1236,7 @@ snapshots:
1222
1236
  '@rolldown/pluginutils': 1.0.0-rc.3
1223
1237
  '@types/babel__core': 7.20.5
1224
1238
  react-refresh: 0.18.0
1225
- vite: 7.3.2(jiti@2.6.1)(lightningcss@1.32.0)
1239
+ vite: 7.3.2(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
1226
1240
  transitivePeerDependencies:
1227
1241
  - supports-color
1228
1242
 
@@ -1295,6 +1309,10 @@ snapshots:
1295
1309
 
1296
1310
  gensync@1.0.0-beta.2: {}
1297
1311
 
1312
+ get-tsconfig@4.14.0:
1313
+ dependencies:
1314
+ resolve-pkg-maps: 1.0.0
1315
+
1298
1316
  graceful-fs@4.2.11: {}
1299
1317
 
1300
1318
  jiti@2.6.1: {}
@@ -1391,6 +1409,8 @@ snapshots:
1391
1409
 
1392
1410
  react@19.2.5: {}
1393
1411
 
1412
+ resolve-pkg-maps@1.0.0: {}
1413
+
1394
1414
  rollup@4.60.1:
1395
1415
  dependencies:
1396
1416
  '@types/estree': 1.0.8
@@ -1437,6 +1457,13 @@ snapshots:
1437
1457
  fdir: 6.5.0(picomatch@4.0.4)
1438
1458
  picomatch: 4.0.4
1439
1459
 
1460
+ tsx@4.21.0:
1461
+ dependencies:
1462
+ esbuild: 0.27.7
1463
+ get-tsconfig: 4.14.0
1464
+ optionalDependencies:
1465
+ fsevents: 2.3.3
1466
+
1440
1467
  typescript@5.9.3: {}
1441
1468
 
1442
1469
  update-browserslist-db@1.2.3(browserslist@4.28.2):
@@ -1445,7 +1472,7 @@ snapshots:
1445
1472
  escalade: 3.2.0
1446
1473
  picocolors: 1.1.1
1447
1474
 
1448
- vite@7.3.2(jiti@2.6.1)(lightningcss@1.32.0):
1475
+ vite@7.3.2(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0):
1449
1476
  dependencies:
1450
1477
  esbuild: 0.27.7
1451
1478
  fdir: 6.5.0(picomatch@4.0.4)
@@ -1457,5 +1484,6 @@ snapshots:
1457
1484
  fsevents: 2.3.3
1458
1485
  jiti: 2.6.1
1459
1486
  lightningcss: 1.32.0
1487
+ tsx: 4.21.0
1460
1488
 
1461
1489
  yallist@3.1.1: {}
@@ -0,0 +1,18 @@
1
+ import { buildDemoRuntimeSnapshot } from "./guard-api";
2
+
3
+ function assert(condition: boolean, message: string): void {
4
+ if (!condition) {
5
+ throw new Error(message);
6
+ }
7
+ }
8
+
9
+ const snapshot = buildDemoRuntimeSnapshot();
10
+
11
+ assert(snapshot.cloud_pairing_state.state === "paired_waiting", "demo snapshot exposes paired waiting state");
12
+ assert(snapshot.cloud_pairing_state.label === snapshot.cloud_state_label, "demo pairing label matches legacy label");
13
+ assert(snapshot.cloud_pairing_state.detail === snapshot.cloud_state_detail, "demo pairing detail matches legacy detail");
14
+ assert(snapshot.cloud_pairing_state.sync_configured === true, "demo pairing state marks sync configured");
15
+ assert(snapshot.cloud_pairing_state.dashboard_url === snapshot.dashboard_url, "demo dashboard URL is preserved");
16
+ assert(snapshot.cloud_pairing_state.inbox_url === snapshot.inbox_url, "demo inbox URL is preserved");
17
+ assert(snapshot.cloud_pairing_state.fleet_url === snapshot.fleet_url, "demo fleet URL is preserved");
18
+ assert(snapshot.cloud_pairing_state.connect_url === snapshot.connect_url, "demo connect URL is preserved");
@@ -18,24 +18,31 @@ import {
18
18
  } from "./guard-demo";
19
19
 
20
20
  const GUARD_TOKEN_PARAM = "guard-token";
21
+ const GUARD_DAEMON_PARAM = "guardDaemon";
21
22
 
22
23
  async function readJson<T>(input: RequestInfo, init?: RequestInit): Promise<T> {
23
- const response = await fetch(input, init);
24
+ const response = await fetch(guardApiInput(input), withGuardAuth(init));
24
25
  if (!response.ok) {
25
26
  throw new Error(`Request failed with ${response.status}`);
26
27
  }
27
28
  return (await response.json()) as T;
28
29
  }
29
30
 
30
- function guardTokenFromHash(): string | null {
31
- const fragment = window.location.hash.startsWith("#")
32
- ? window.location.hash.slice(1)
33
- : window.location.hash;
34
- return new URLSearchParams(fragment).get(GUARD_TOKEN_PARAM);
31
+ function guardParams(): URLSearchParams {
32
+ const params = new URLSearchParams(window.location.search);
33
+ const fragment = window.location.hash.startsWith("#") ? window.location.hash.slice(1) : window.location.hash;
34
+ for (const [key, value] of new URLSearchParams(fragment)) {
35
+ params.set(key, value);
36
+ }
37
+ return params;
38
+ }
39
+
40
+ function guardParam(name: string): string | null {
41
+ return guardParams().get(name);
35
42
  }
36
43
 
37
44
  function readGuardToken(): string | null {
38
- const guardToken = guardTokenFromHash();
45
+ const guardToken = guardParam(GUARD_TOKEN_PARAM);
39
46
  if (guardToken) {
40
47
  window.sessionStorage.setItem(GUARD_TOKEN_PARAM, guardToken);
41
48
  return guardToken;
@@ -43,6 +50,55 @@ function readGuardToken(): string | null {
43
50
  return window.sessionStorage.getItem(GUARD_TOKEN_PARAM);
44
51
  }
45
52
 
53
+ function readGuardDaemonOrigin(): string | null {
54
+ const rawDaemonUrl = guardParam(GUARD_DAEMON_PARAM);
55
+ if (rawDaemonUrl) {
56
+ const daemonOrigin = localGuardDaemonOrigin(rawDaemonUrl);
57
+ if (daemonOrigin) {
58
+ window.sessionStorage.setItem(GUARD_DAEMON_PARAM, daemonOrigin);
59
+ return daemonOrigin;
60
+ }
61
+ }
62
+ const storedDaemonUrl = window.sessionStorage.getItem(GUARD_DAEMON_PARAM);
63
+ return storedDaemonUrl ? localGuardDaemonOrigin(storedDaemonUrl) : null;
64
+ }
65
+
66
+ function localGuardDaemonOrigin(rawUrl: string): string | null {
67
+ try {
68
+ const url = new URL(rawUrl);
69
+ if (url.protocol !== "http:" || !["127.0.0.1", "localhost", "[::1]", "::1"].includes(url.hostname)) {
70
+ return null;
71
+ }
72
+ if (url.username || url.password || (url.pathname && url.pathname !== "/") || url.search || url.hash) {
73
+ return null;
74
+ }
75
+ return url.origin;
76
+ } catch {
77
+ return null;
78
+ }
79
+ }
80
+
81
+ function guardApiInput(input: RequestInfo): RequestInfo {
82
+ const daemonOrigin = readGuardDaemonOrigin();
83
+ if (!daemonOrigin || typeof input !== "string" || !input.startsWith("/")) {
84
+ return input;
85
+ }
86
+ return `${daemonOrigin}${input}`;
87
+ }
88
+
89
+ function withGuardAuth(init?: RequestInit): RequestInit | undefined {
90
+ const guardToken = readGuardToken();
91
+ if (!guardToken) {
92
+ return init;
93
+ }
94
+ const headers = new Headers(init?.headers);
95
+ headers.set("X-Guard-Token", guardToken);
96
+ return {
97
+ ...init,
98
+ headers
99
+ };
100
+ }
101
+
46
102
  function guardAuthHeaders(): HeadersInit {
47
103
  const guardToken = readGuardToken();
48
104
  return guardToken ? { "X-Guard-Token": guardToken } : {};
@@ -59,7 +115,12 @@ export function guardAwareHref(href: string): string {
59
115
  return href;
60
116
  }
61
117
 
62
- url.hash = new URLSearchParams([[GUARD_TOKEN_PARAM, guardToken]]).toString();
118
+ const fragmentPairs = [[GUARD_TOKEN_PARAM, guardToken]];
119
+ const daemonOrigin = readGuardDaemonOrigin();
120
+ if (daemonOrigin) {
121
+ fragmentPairs.push([GUARD_DAEMON_PARAM, daemonOrigin]);
122
+ }
123
+ url.hash = new URLSearchParams(fragmentPairs).toString();
63
124
  if (href.startsWith("http://") || href.startsWith("https://")) {
64
125
  return url.toString();
65
126
  }
@@ -76,43 +137,65 @@ export async function fetchRequests(): Promise<GuardApprovalRequest[]> {
76
137
 
77
138
  export async function fetchRuntimeSnapshot(): Promise<GuardRuntimeSnapshot> {
78
139
  if (isGuardDemoMode()) {
79
- const demoRequests = getDemoRequests();
80
- const demoReceipts = getDemoReceipts();
81
- return {
82
- generated_at: new Date().toISOString(),
83
- approval_center_url: "http://127.0.0.1:4455",
84
- runtime_state: {
85
- session_id: "demo-runtime",
86
- daemon_host: "127.0.0.1",
87
- daemon_port: 4455,
88
- started_at: new Date().toISOString(),
89
- last_heartbeat_at: new Date().toISOString(),
90
- approval_center_url: "http://127.0.0.1:4455"
91
- },
92
- pending_count: demoRequests.length,
93
- receipt_count: demoReceipts.length,
94
- headline_state: demoRequests.length > 0 ? "blocked" : "connected",
95
- headline_label: demoRequests.length > 0 ? "Blocked" : "Connected",
96
- headline_detail:
97
- demoRequests.length > 0
98
- ? "A blocked action is waiting for review."
99
- : "This machine is connected to Guard Cloud and waiting for the first shared proof to appear.",
100
- sync_configured: true,
101
- cloud_state: "paired_waiting",
102
- cloud_state_label: "Connected",
103
- cloud_state_detail:
104
- "This machine is connected to Guard Cloud, but the first shared proof has not landed yet. Open Watched Apps while the first sync settles.",
105
- dashboard_url: "https://hol.org/guard",
106
- inbox_url: "https://hol.org/guard/inbox",
107
- fleet_url: "https://hol.org/guard/fleet",
108
- connect_url: "https://hol.org/guard/connect",
109
- items: demoRequests,
110
- latest_receipts: demoReceipts.slice(0, 10)
111
- };
140
+ return buildDemoRuntimeSnapshot();
112
141
  }
113
142
  return readJson<GuardRuntimeSnapshot>("/v1/runtime");
114
143
  }
115
144
 
145
+ export function buildDemoRuntimeSnapshot(): GuardRuntimeSnapshot {
146
+ const demoRequests = getDemoRequests();
147
+ const demoReceipts = getDemoReceipts();
148
+ const now = new Date().toISOString();
149
+ const cloudState = "paired_waiting";
150
+ const cloudLabel = "Connected";
151
+ const cloudDetail =
152
+ "This machine is connected to Guard Cloud, but the first shared proof has not landed yet. Open Watched Apps while the first sync settles.";
153
+ const dashboardUrl = "https://hol.org/guard";
154
+ const inboxUrl = "https://hol.org/guard/inbox";
155
+ const fleetUrl = "https://hol.org/guard/fleet";
156
+ const connectUrl = "https://hol.org/guard/connect";
157
+ return {
158
+ generated_at: now,
159
+ approval_center_url: "http://127.0.0.1:4455",
160
+ runtime_state: {
161
+ session_id: "demo-runtime",
162
+ daemon_host: "127.0.0.1",
163
+ daemon_port: 4455,
164
+ started_at: now,
165
+ last_heartbeat_at: now,
166
+ approval_center_url: "http://127.0.0.1:4455"
167
+ },
168
+ pending_count: demoRequests.length,
169
+ receipt_count: demoReceipts.length,
170
+ headline_state: demoRequests.length > 0 ? "blocked" : "connected",
171
+ headline_label: demoRequests.length > 0 ? "Blocked" : "Connected",
172
+ headline_detail:
173
+ demoRequests.length > 0
174
+ ? "A blocked action is waiting for review."
175
+ : "This machine is connected to Guard Cloud and waiting for the first shared proof to appear.",
176
+ sync_configured: true,
177
+ cloud_state: cloudState,
178
+ cloud_state_label: cloudLabel,
179
+ cloud_state_detail: cloudDetail,
180
+ cloud_pairing_state: {
181
+ state: cloudState,
182
+ label: cloudLabel,
183
+ detail: cloudDetail,
184
+ sync_configured: true,
185
+ dashboard_url: dashboardUrl,
186
+ inbox_url: inboxUrl,
187
+ fleet_url: fleetUrl,
188
+ connect_url: connectUrl
189
+ },
190
+ dashboard_url: dashboardUrl,
191
+ inbox_url: inboxUrl,
192
+ fleet_url: fleetUrl,
193
+ connect_url: connectUrl,
194
+ items: demoRequests,
195
+ latest_receipts: demoReceipts.slice(0, 10)
196
+ };
197
+ }
198
+
116
199
  export async function fetchInventory(): Promise<GuardInventoryItem[]> {
117
200
  if (isGuardDemoMode()) {
118
201
  return [];
@@ -193,7 +276,7 @@ export async function fetchLatestReceipt(
193
276
  if (isGuardDemoMode()) {
194
277
  return getDemoReceipts().find((entry) => entry.artifact_id === artifactId) ?? null;
195
278
  }
196
- const response = await fetch(
279
+ const response = await fetchGuardApi(
197
280
  `/v1/receipts/latest?harness=${encodeURIComponent(harness)}&artifact_id=${encodeURIComponent(artifactId)}`
198
281
  );
199
282
  if (response.status === 404) {
@@ -252,7 +335,7 @@ export async function fetchDiff(
252
335
  if (isGuardDemoMode()) {
253
336
  return getDemoDiff(artifactId, harness);
254
337
  }
255
- const response = await fetch(
338
+ const response = await fetchGuardApi(
256
339
  `/v1/artifacts/${encodeURIComponent(artifactId)}/diff?harness=${encodeURIComponent(harness)}`
257
340
  );
258
341
  if (response.status === 404) {
@@ -264,6 +347,10 @@ export async function fetchDiff(
264
347
  return (await response.json()) as GuardArtifactDiff;
265
348
  }
266
349
 
350
+ function fetchGuardApi(input: RequestInfo, init?: RequestInit): Promise<Response> {
351
+ return fetch(guardApiInput(input), withGuardAuth(init));
352
+ }
353
+
267
354
  export async function resolveRequest(input: {
268
355
  requestId: string;
269
356
  action: "allow" | "block";
@@ -47,6 +47,17 @@ export type GuardRuntimeState = {
47
47
  approval_center_url: string;
48
48
  };
49
49
 
50
+ export type GuardCloudPairingState = {
51
+ state: "local_only" | "paired_waiting" | "paired_active";
52
+ label: string;
53
+ detail: string;
54
+ sync_configured: boolean;
55
+ dashboard_url: string;
56
+ inbox_url: string;
57
+ fleet_url: string;
58
+ connect_url: string;
59
+ };
60
+
50
61
  export type GuardRuntimeSnapshot = {
51
62
  generated_at: string;
52
63
  approval_center_url: string | null;
@@ -60,6 +71,7 @@ export type GuardRuntimeSnapshot = {
60
71
  cloud_state: "local_only" | "paired_waiting" | "paired_active";
61
72
  cloud_state_label: string;
62
73
  cloud_state_detail: string;
74
+ cloud_pairing_state: GuardCloudPairingState;
63
75
  dashboard_url: string;
64
76
  inbox_url: string;
65
77
  fleet_url: string;
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "plugin-scanner"
7
- version = "2.0.92"
7
+ version = "2.0.94"
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.92"
7
+ version = "2.0.94"
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"
@@ -362,6 +362,16 @@ def _build_runtime_cloud_context(store: GuardStore) -> dict[str, object]:
362
362
  "cloud_state": cloud_state,
363
363
  "cloud_state_label": _runtime_cloud_state_label(cloud_state),
364
364
  "cloud_state_detail": _runtime_cloud_state_detail(cloud_state),
365
+ "cloud_pairing_state": {
366
+ "state": cloud_state,
367
+ "label": _runtime_cloud_state_label(cloud_state),
368
+ "detail": _runtime_cloud_state_detail(cloud_state),
369
+ "sync_configured": credentials is not None,
370
+ "dashboard_url": dashboard_url,
371
+ "inbox_url": inbox_url,
372
+ "fleet_url": fleet_url,
373
+ "connect_url": connect_url,
374
+ },
365
375
  "dashboard_url": dashboard_url,
366
376
  "inbox_url": inbox_url,
367
377
  "fleet_url": fleet_url,
@@ -299,6 +299,7 @@ def build_connect_payload(
299
299
  "sync_available": sync_available if sync_available is not None else connected,
300
300
  "browser_opened": browser_opened,
301
301
  "connect_url": connect_url,
302
+ "cloud_pairing_url": connect_url,
302
303
  "sync_url": sync_url,
303
304
  "status": str(state.get("status") or "waiting"),
304
305
  "milestone": str(state.get("milestone") or "waiting_for_browser"),
@@ -698,7 +698,8 @@ def _render_connect(console: Console, payload: dict[str, object]) -> None:
698
698
  body.add_row("Connection", _connect_status_text(payload))
699
699
  if milestone:
700
700
  body.add_row("Next step", _connect_milestone_text(payload))
701
- body.add_row("Connect URL", str(payload.get("connect_url") or "unknown"))
701
+ cloud_pairing_url = payload.get("cloud_pairing_url") or payload.get("connect_url") or "unknown"
702
+ body.add_row("Cloud URL", str(cloud_pairing_url))
702
703
  body.add_row("Sync endpoint", str(payload.get("sync_url") or "unknown"))
703
704
  sync_payload = payload.get("sync")
704
705
  should_render_sync_counts = False
@@ -54,6 +54,7 @@ _CLAUDE_HOOK_EXECUTION_LOCK = threading.Lock()
54
54
  _DEFAULT_GUARD_DAEMON_IDLE_TIMEOUT_SECONDS = 30 * 60
55
55
  _EPHEMERAL_GUARD_DAEMON_IDLE_TIMEOUT_SECONDS = 5
56
56
  _GUARD_DAEMON_IDLE_POLL_INTERVAL_SECONDS = 0.5
57
+ _HOSTED_GUARD_DASHBOARD_ORIGINS = frozenset({"https://hol.org", "https://www.hol.org"})
57
58
 
58
59
 
59
60
  class _GuardDaemonHandler(BaseHTTPRequestHandler):
@@ -64,21 +65,31 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
64
65
  if origin is None:
65
66
  self._write_empty(status=400)
66
67
  return
67
- if not self._origin_is_allowed():
68
+ headers = self._cors_headers_for_request(
69
+ allow_methods="GET, POST, OPTIONS",
70
+ allow_headers="Content-Type, X-Guard-Token",
71
+ )
72
+ if headers is None:
68
73
  self._write_empty(status=403)
69
74
  return
70
- self._write_empty(
71
- status=200,
72
- extra_headers=self._cors_headers(
73
- origin, allow_methods="GET, POST, OPTIONS", allow_headers="Content-Type, X-Guard-Token"
74
- ),
75
- )
75
+ self._write_empty(status=200, extra_headers=headers)
76
76
 
77
77
  def do_GET(self) -> None:
78
78
  store = self.server.store # type: ignore[attr-defined]
79
79
  parsed = urlparse(self.path)
80
80
  self._touch_runtime_heartbeat(parsed.path)
81
81
  path_parts = [part for part in parsed.path.split("/") if part]
82
+ if not self._origin_is_allowed_for_request(parsed.path, path_parts):
83
+ self._write_json({"error": "forbidden_origin"}, status=403)
84
+ return
85
+ if (
86
+ self._is_hosted_dashboard_origin()
87
+ and self._is_hosted_dashboard_api_path(parsed.path, path_parts)
88
+ and parsed.path != "/v1/connect/state"
89
+ and not self._header_token_is_valid()
90
+ ):
91
+ self._write_json({"error": "unauthorized"}, status=401)
92
+ return
82
93
  if parsed.path == "/healthz":
83
94
  self._write_json(
84
95
  {
@@ -204,16 +215,15 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
204
215
  def do_POST(self) -> None:
205
216
  parsed = urlparse(self.path)
206
217
  self._touch_runtime_heartbeat(parsed.path)
207
- if parsed.path != "/v1/connect/complete" and not self._origin_is_allowed():
218
+ path_parts = [part for part in parsed.path.split("/") if part]
219
+ if parsed.path != "/v1/connect/complete" and not self._origin_is_allowed_for_request(parsed.path, path_parts):
208
220
  self._write_json({"error": "forbidden_origin"}, status=403)
209
221
  return
210
- path_parts = [part for part in parsed.path.split("/") if part]
211
222
  if self._requires_header_token(parsed.path, path_parts) and not self._header_token_is_valid():
212
- origin = self._normalize_origin(self.headers.get("Origin"))
213
223
  self._write_json(
214
224
  {"error": "unauthorized"},
215
225
  status=401,
216
- extra_headers=self._cors_headers(origin) if origin is not None else None,
226
+ extra_headers=self._cors_headers_for_request(),
217
227
  )
218
228
  return
219
229
  payload, body_error = self._load_request_body()
@@ -801,7 +811,7 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
801
811
  finally:
802
812
  self._decrement_active_stream_clients()
803
813
 
804
- def _origin_is_allowed(self) -> bool:
814
+ def _origin_is_allowed_for_request(self, path: str, path_parts: list[str]) -> bool:
805
815
  origin = self.headers.get("Origin")
806
816
  if origin is None:
807
817
  return True
@@ -809,7 +819,36 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
809
819
  if normalized_origin is None:
810
820
  return False
811
821
  parsed = urlparse(normalized_origin)
812
- return parsed.hostname in {"127.0.0.1", "localhost", "::1"}
822
+ local_origin = parsed.hostname in {"127.0.0.1", "localhost", "::1"}
823
+ if local_origin:
824
+ return True
825
+ return normalized_origin in _HOSTED_GUARD_DASHBOARD_ORIGINS and self._is_hosted_dashboard_api_path(
826
+ path, path_parts
827
+ )
828
+
829
+ @staticmethod
830
+ def _is_hosted_dashboard_api_path(path: str, path_parts: list[str]) -> bool:
831
+ if path in {
832
+ "/v1/inventory",
833
+ "/v1/connect/state",
834
+ "/v1/policy",
835
+ "/v1/policy/clear",
836
+ "/v1/receipts",
837
+ "/v1/receipts/latest",
838
+ "/v1/requests",
839
+ "/v1/runtime",
840
+ "/v1/settings",
841
+ }:
842
+ return True
843
+ if len(path_parts) == 3 and path_parts[:2] in (["v1", "requests"], ["v1", "receipts"]):
844
+ return True
845
+ if len(path_parts) == 4 and path_parts[:2] == ["v1", "requests"] and path_parts[3] in {"approve", "block"}:
846
+ return True
847
+ return len(path_parts) == 4 and path_parts[:2] == ["v1", "artifacts"] and path_parts[3] == "diff"
848
+
849
+ def _is_hosted_dashboard_origin(self) -> bool:
850
+ origin = self._normalize_origin(self.headers.get("Origin"))
851
+ return origin in _HOSTED_GUARD_DASHBOARD_ORIGINS
813
852
 
814
853
  @staticmethod
815
854
  def _normalize_origin(origin: str | None) -> str | None:
@@ -852,6 +891,19 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
852
891
  "Vary": "Origin",
853
892
  }
854
893
 
894
+ def _cors_headers_for_request(
895
+ self,
896
+ *,
897
+ allow_methods: str = "POST, OPTIONS",
898
+ allow_headers: str = "Content-Type, X-Guard-Token",
899
+ ) -> dict[str, str] | None:
900
+ parsed = urlparse(self.path)
901
+ path_parts = [part for part in parsed.path.split("/") if part]
902
+ origin = self._normalize_origin(self.headers.get("Origin"))
903
+ if origin is None or not self._origin_is_allowed_for_request(parsed.path, path_parts):
904
+ return None
905
+ return self._cors_headers(origin, allow_methods=allow_methods, allow_headers=allow_headers)
906
+
855
907
  def _handle_policy_upsert(self, payload: dict[str, object]) -> None:
856
908
  harness = payload.get("harness")
857
909
  scope = payload.get("scope")
@@ -964,10 +1016,14 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
964
1016
  extra_headers: dict[str, str] | None = None,
965
1017
  ) -> None:
966
1018
  body = json.dumps(payload).encode("utf-8")
1019
+ headers = dict(extra_headers or {})
1020
+ cors_headers = self._cors_headers_for_request(allow_methods="GET, POST, OPTIONS")
1021
+ if cors_headers is not None:
1022
+ headers = {**cors_headers, **headers}
967
1023
  self.send_response(status)
968
1024
  self.send_header("Content-Type", "application/json")
969
1025
  self.send_header("Content-Length", str(len(body)))
970
- for key, value in self._validated_headers(extra_headers).items():
1026
+ for key, value in self._validated_headers(headers).items():
971
1027
  self.send_header(key, value)
972
1028
  self.end_headers()
973
1029
  self.wfile.write(body)