plugin-scanner 2.0.117__tar.gz → 2.0.119__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 (364) hide show
  1. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/PKG-INFO +1 -1
  2. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/src/guard-api.test.ts +24 -0
  3. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/src/guard-api.ts +8 -0
  4. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/src/guard-types.ts +10 -0
  5. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/src/runtime-overview.tsx +32 -1
  6. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/pyproject.toml +1 -1
  7. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/pyproject.toml.bak +1 -1
  8. plugin_scanner-2.0.119/src/codex_plugin_scanner/guard/access_graph_events.py +223 -0
  9. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +12 -0
  10. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/approvals.py +99 -1
  11. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/cli/commands.py +16 -1
  12. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/consumer/service.py +8 -0
  13. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +6 -6
  14. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/edge_events.py +93 -0
  15. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +25 -0
  16. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +83 -0
  17. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/redaction.py +15 -1
  18. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/runtime/detectors.py +79 -2
  19. plugin_scanner-2.0.119/src/codex_plugin_scanner/guard/runtime/mcp_protection.py +426 -0
  20. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/runtime/runner.py +115 -4
  21. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +32 -0
  22. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +25 -3
  23. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/store.py +131 -24
  24. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/version.py +1 -1
  25. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_access_graph.py +2 -1
  26. plugin_scanner-2.0.119/tests/test_guard_cloud_local_sync.py +451 -0
  27. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_codex_proxy.py +294 -0
  28. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_connect_flow.py +4 -0
  29. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_event_schema_v1.py +66 -2
  30. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_launch_env.py +81 -0
  31. plugin_scanner-2.0.119/tests/test_guard_mcp_protection.py +761 -0
  32. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_risk.py +37 -0
  33. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_runtime.py +33 -0
  34. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_runtime_detectors.py +90 -0
  35. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_surface_server.py +64 -0
  36. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.clusterfuzzlite/Dockerfile +0 -0
  37. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.clusterfuzzlite/build.sh +0 -0
  38. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.clusterfuzzlite/project.yaml +0 -0
  39. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.clusterfuzzlite/requirements-atheris.txt +0 -0
  40. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.dockerignore +0 -0
  41. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.github/CODEOWNERS +0 -0
  42. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  43. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  44. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  45. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.github/dependabot.yml +0 -0
  46. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.github/workflows/ci.yml +0 -0
  47. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.github/workflows/codeql.yml +0 -0
  48. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.github/workflows/dependabot-uv-lock.yml +0 -0
  49. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.github/workflows/fuzz.yml +0 -0
  50. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.github/workflows/harness-smoke.yml +0 -0
  51. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.github/workflows/publish.yml +0 -0
  52. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.github/workflows/scorecard.yml +0 -0
  53. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.gitignore +0 -0
  54. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/.pre-commit-hooks.yaml +0 -0
  55. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/CONTRIBUTING.md +0 -0
  56. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/Dockerfile +0 -0
  57. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/LICENSE +0 -0
  58. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/README.md +0 -0
  59. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/SECURITY.md +0 -0
  60. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/index.html +0 -0
  61. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/package.json +0 -0
  62. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/pnpm-lock.yaml +0 -0
  63. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/public/apple-touch-icon.png +0 -0
  64. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
  65. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/public/brand/Logo_Whole.png +0 -0
  66. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/public/favicon-16x16.png +0 -0
  67. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/public/favicon-32x32.png +0 -0
  68. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/public/favicon.ico +0 -0
  69. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/src/app.tsx +0 -0
  70. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/src/approval-center-layout.tsx +0 -0
  71. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/src/approval-center-primitives.tsx +0 -0
  72. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/src/approval-center-utils.ts +0 -0
  73. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/src/data-flow-evidence-card.tsx +0 -0
  74. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/src/fleet-workspace.tsx +0 -0
  75. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/src/guard-demo.ts +0 -0
  76. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/src/main.tsx +0 -0
  77. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/src/receipts-workspace.tsx +0 -0
  78. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/src/settings-workspace.tsx +0 -0
  79. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/src/styles.css +0 -0
  80. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/src/vite-env.d.ts +0 -0
  81. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/tsconfig.json +0 -0
  82. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/dashboard/vite.config.ts +0 -0
  83. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/docker-requirements.txt +0 -0
  84. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/docs/guard/approval-audit.md +0 -0
  85. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/docs/guard/architecture.md +0 -0
  86. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/docs/guard/get-started.md +0 -0
  87. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/docs/guard/harness-support.md +0 -0
  88. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/docs/guard/local-vs-cloud.md +0 -0
  89. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/docs/guard/testing-matrix.md +0 -0
  90. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/docs/trust/mcp-trust-draft.md +0 -0
  91. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/docs/trust/plugin-trust-draft.md +0 -0
  92. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/docs/trust/skill-trust-local.md +0 -0
  93. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/fuzzers/manifest_fuzzer.py +0 -0
  94. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/requirements.txt +0 -0
  95. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/schemas/plugin-quality.v1.json +0 -0
  96. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/schemas/scan-result.v1.json +0 -0
  97. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/schemas/verify-result.v1.json +0 -0
  98. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/__init__.py +0 -0
  99. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/action_runner.py +0 -0
  100. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/argparse_utils.py +0 -0
  101. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/checks/__init__.py +0 -0
  102. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
  103. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/checks/claude.py +0 -0
  104. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
  105. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
  106. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/checks/gemini.py +0 -0
  107. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/checks/manifest.py +0 -0
  108. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
  109. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
  110. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
  111. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/checks/opencode.py +0 -0
  112. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
  113. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/checks/security.py +0 -0
  114. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
  115. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/cli.py +0 -0
  116. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/cli_ui.py +0 -0
  117. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/config.py +0 -0
  118. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
  119. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
  120. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
  121. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
  122. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
  123. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
  124. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
  125. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
  126. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
  127. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/github_reporting.py +0 -0
  128. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/__init__.py +0 -0
  129. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
  130. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
  131. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
  132. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
  133. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +0 -0
  134. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
  135. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
  136. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
  137. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
  138. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
  139. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
  140. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
  141. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
  142. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
  143. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
  144. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
  145. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
  146. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
  147. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
  148. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
  149. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
  150. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
  151. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
  152. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
  153. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
  154. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
  155. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
  156. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
  157. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/config.py +0 -0
  158. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
  159. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
  160. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
  161. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
  162. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
  163. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
  164. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
  165. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
  166. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
  167. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
  168. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
  169. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
  170. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
  171. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/incident.py +0 -0
  172. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/launcher.py +0 -0
  173. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/models.py +0 -0
  174. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
  175. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
  176. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/protect.py +0 -0
  177. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
  178. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
  179. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
  180. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
  181. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
  182. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/risk.py +0 -0
  183. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
  184. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
  185. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/runtime/data_flow.py +0 -0
  186. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/runtime/data_flow_rules.py +0 -0
  187. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/runtime/data_flow_variables.py +0 -0
  188. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
  189. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/runtime/prompt_injection.py +0 -0
  190. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/runtime/secret_sensitivity.py +0 -0
  191. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/runtime/secret_sources.py +0 -0
  192. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/runtime/shell_commands.py +0 -0
  193. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
  194. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
  195. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/runtime/temp_files.py +0 -0
  196. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
  197. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
  198. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
  199. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/shims.py +0 -0
  200. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
  201. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
  202. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/guard/types.py +0 -0
  203. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
  204. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
  205. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
  206. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/lint_fixes.py +0 -0
  207. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/marketplace_support.py +0 -0
  208. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/models.py +0 -0
  209. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/path_support.py +0 -0
  210. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/policy.py +0 -0
  211. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/quality_artifact.py +0 -0
  212. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/repo_detect.py +0 -0
  213. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/reporting.py +0 -0
  214. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/rules/__init__.py +0 -0
  215. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/rules/registry.py +0 -0
  216. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/rules/specs.py +0 -0
  217. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/scanner.py +0 -0
  218. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/submission.py +0 -0
  219. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/suppressions.py +0 -0
  220. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
  221. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/trust_helpers.py +0 -0
  222. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
  223. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/trust_models.py +0 -0
  224. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
  225. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/trust_scoring.py +0 -0
  226. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
  227. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/trust_specs.py +0 -0
  228. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/src/codex_plugin_scanner/verification.py +0 -0
  229. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/__init__.py +0 -0
  230. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/conftest.py +0 -0
  231. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/__init__.py +0 -0
  232. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
  233. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/bad-plugin/.mcp.json +0 -0
  234. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/bad-plugin/secrets.js +0 -0
  235. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
  236. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
  237. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/claude-plugin-good/README.md +0 -0
  238. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
  239. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
  240. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
  241. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/code-quality-bad/evil.js +0 -0
  242. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/code-quality-bad/inject.js +0 -0
  243. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
  244. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
  245. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/gemini-extension-good/README.md +0 -0
  246. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
  247. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
  248. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
  249. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
  250. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/good-plugin/.codexignore +0 -0
  251. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/good-plugin/LICENSE +0 -0
  252. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/good-plugin/README.md +0 -0
  253. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/good-plugin/SECURITY.md +0 -0
  254. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
  255. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
  256. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
  257. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
  258. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
  259. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
  260. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
  261. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
  262. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
  263. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
  264. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
  265. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
  266. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
  267. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
  268. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
  269. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
  270. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
  271. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
  272. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
  273. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/mcp-canary-server.py +0 -0
  274. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
  275. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
  276. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/mit-license/LICENSE +0 -0
  277. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
  278. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
  279. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
  280. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
  281. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
  282. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
  283. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
  284. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
  285. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
  286. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
  287. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
  288. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
  289. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
  290. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
  291. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
  292. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
  293. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
  294. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
  295. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/opencode-good/LICENSE +0 -0
  296. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/opencode-good/README.md +0 -0
  297. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/opencode-good/SECURITY.md +0 -0
  298. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
  299. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
  300. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
  301. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
  302. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
  303. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
  304. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/fixtures/with-marketplace/marketplace.json +0 -0
  305. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test-trust-scoring.py +0 -0
  306. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test-trust-specs.py +0 -0
  307. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_action_runner.py +0 -0
  308. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_best_practices.py +0 -0
  309. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_cisco_install_surfaces.py +0 -0
  310. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_cli.py +0 -0
  311. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_code_quality.py +0 -0
  312. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_config.py +0 -0
  313. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_coverage_remaining.py +0 -0
  314. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_ecosystems.py +0 -0
  315. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_edge_cases.py +0 -0
  316. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_final_coverage.py +0 -0
  317. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_approvals.py +0 -0
  318. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_bootstrap.py +0 -0
  319. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_capabilities.py +0 -0
  320. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_claude_adapter.py +0 -0
  321. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_cli.py +0 -0
  322. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_codex_e2e.py +0 -0
  323. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_codex_install.py +0 -0
  324. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_config_paths.py +0 -0
  325. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_consumer_mode.py +0 -0
  326. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_copilot_adapter.py +0 -0
  327. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_copilot_proxy.py +0 -0
  328. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_daemon_manager.py +0 -0
  329. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_data_flow.py +0 -0
  330. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_events.py +0 -0
  331. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_opencode_proxy.py +0 -0
  332. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_product_flow.py +0 -0
  333. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_prompt_injection.py +0 -0
  334. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_protect.py +0 -0
  335. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_render.py +0 -0
  336. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_runtime_action_harnesses.py +0 -0
  337. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_runtime_actions.py +0 -0
  338. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_runtime_decisions.py +0 -0
  339. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_runtime_signals.py +0 -0
  340. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_store_migrations.py +0 -0
  341. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_guard_verdicts.py +0 -0
  342. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_hermes_adapter.py +0 -0
  343. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_integration.py +0 -0
  344. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_lint_fixes.py +0 -0
  345. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_live_cisco_smoke.py +0 -0
  346. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_manifest.py +0 -0
  347. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_marketplace.py +0 -0
  348. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_mcp_security.py +0 -0
  349. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_openclaw_adapter.py +0 -0
  350. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_operational_security.py +0 -0
  351. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_policy.py +0 -0
  352. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_quality_artifact.py +0 -0
  353. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_rule_registry.py +0 -0
  354. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_scanner.py +0 -0
  355. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_schema_contracts.py +0 -0
  356. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_security.py +0 -0
  357. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_security_ops.py +0 -0
  358. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_skill_security.py +0 -0
  359. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_submission.py +0 -0
  360. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_trust_scoring.py +0 -0
  361. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_trust_specs.py +0 -0
  362. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_verification.py +0 -0
  363. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/tests/test_versioning.py +0 -0
  364. {plugin_scanner-2.0.117 → plugin_scanner-2.0.119}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 2.0.117
3
+ Version: 2.0.119
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,6 +4,7 @@ import {
4
4
  parseActionEnvelope,
5
5
  parseDecisionV2
6
6
  } from "./guard-api";
7
+ import { resolveCloudSyncHealthCopy } from "./runtime-overview";
7
8
  import {
8
9
  resolveDecisionV2Detail,
9
10
  resolveDecisionV2Title,
@@ -29,6 +30,29 @@ assert(snapshot.cloud_pairing_state.dashboard_url === snapshot.dashboard_url, "d
29
30
  assert(snapshot.cloud_pairing_state.inbox_url === snapshot.inbox_url, "demo inbox URL is preserved");
30
31
  assert(snapshot.cloud_pairing_state.fleet_url === snapshot.fleet_url, "demo fleet URL is preserved");
31
32
  assert(snapshot.cloud_pairing_state.connect_url === snapshot.connect_url, "demo connect URL is preserved");
33
+ assert(snapshot.cloud_sync_health.state === "pending", "demo snapshot exposes pending Cloud sync health");
34
+
35
+ const expectedSyncHealthLabels = {
36
+ healthy: "Cloud sync healthy",
37
+ pending: "Cloud sync pending",
38
+ failed: "Cloud sync needs attention",
39
+ degraded: "Cloud sync degraded",
40
+ disabled: "Cloud sync disabled",
41
+ stale: "Cloud sync stale"
42
+ };
43
+
44
+ for (const [state, label] of Object.entries(expectedSyncHealthLabels)) {
45
+ const copy = resolveCloudSyncHealthCopy({
46
+ state: state as keyof typeof expectedSyncHealthLabels,
47
+ label,
48
+ detail: `${label} detail`,
49
+ pending_events: state === "pending" ? 2 : 0,
50
+ last_synced_at: state === "disabled" ? null : "2026-04-24T00:00:00+00:00",
51
+ next_retry_after: state === "failed" ? "2026-04-24T00:02:00+00:00" : null
52
+ });
53
+ assert(copy.label === label, `T370: ${state} sync health label is preserved`);
54
+ assert(copy.detail.includes("detail"), `T370: ${state} sync health detail is preserved`);
55
+ }
32
56
 
33
57
  const BASE_ENVELOPE: GuardActionEnvelope = {
34
58
  schema_version: 1,
@@ -411,6 +411,14 @@ export function buildDemoRuntimeSnapshot(): GuardRuntimeSnapshot {
411
411
  fleet_url: fleetUrl,
412
412
  connect_url: connectUrl
413
413
  },
414
+ cloud_sync_health: {
415
+ state: "pending",
416
+ label: "Cloud sync pending",
417
+ detail: "Waiting for the first shared Cloud proof from this machine.",
418
+ pending_events: 1,
419
+ last_synced_at: null,
420
+ next_retry_after: null
421
+ },
414
422
  dashboard_url: dashboardUrl,
415
423
  inbox_url: inboxUrl,
416
424
  fleet_url: fleetUrl,
@@ -153,6 +153,15 @@ export type GuardCloudPairingState = {
153
153
  connect_url: string;
154
154
  };
155
155
 
156
+ export type GuardCloudSyncHealth = {
157
+ state: "healthy" | "pending" | "failed" | "degraded" | "disabled" | "stale";
158
+ label: string;
159
+ detail: string;
160
+ pending_events: number;
161
+ last_synced_at: string | null;
162
+ next_retry_after: string | null;
163
+ };
164
+
156
165
  export type GuardRuntimeSnapshot = {
157
166
  generated_at: string;
158
167
  approval_center_url: string | null;
@@ -167,6 +176,7 @@ export type GuardRuntimeSnapshot = {
167
176
  cloud_state_label: string;
168
177
  cloud_state_detail: string;
169
178
  cloud_pairing_state: GuardCloudPairingState;
179
+ cloud_sync_health: GuardCloudSyncHealth;
170
180
  dashboard_url: string;
171
181
  inbox_url: string;
172
182
  fleet_url: string;
@@ -1,5 +1,5 @@
1
1
  import { ActionButton, Badge, KeyValueGrid, SectionLabel, Surface, Tag } from "./approval-center-primitives";
2
- import type { GuardRuntimeSnapshot } from "./guard-types";
2
+ import type { GuardCloudSyncHealth, GuardRuntimeSnapshot } from "./guard-types";
3
3
 
4
4
  type RuntimeOverviewProps = {
5
5
  snapshot: GuardRuntimeSnapshot;
@@ -34,6 +34,35 @@ function remediationLine(snapshot: GuardRuntimeSnapshot): string {
34
34
  return "Open Guard Cloud for shared proof, Watched Apps for local coverage, or the review queue when something needs your choice.";
35
35
  }
36
36
 
37
+ export function resolveCloudSyncHealthCopy(health: GuardCloudSyncHealth): { label: string; detail: string } {
38
+ return {
39
+ label: health.label,
40
+ detail: health.detail
41
+ };
42
+ }
43
+
44
+ function cloudSyncHealthTone(state: GuardCloudSyncHealth["state"]): "blue" | "slate" {
45
+ if (state === "disabled" || state === "failed" || state === "stale") {
46
+ return "slate";
47
+ }
48
+ return "blue";
49
+ }
50
+
51
+ function CloudSyncHealthCard(props: { health: GuardCloudSyncHealth }) {
52
+ const copy = resolveCloudSyncHealthCopy(props.health);
53
+ return (
54
+ <div className="rounded-xl border border-border bg-white px-5 py-4">
55
+ <div className="flex flex-wrap items-center justify-between gap-2">
56
+ <p className="text-xs font-semibold uppercase tracking-[0.18em] text-brand-blue">
57
+ Cloud sync health
58
+ </p>
59
+ <Tag tone={cloudSyncHealthTone(props.health.state)}>{copy.label}</Tag>
60
+ </div>
61
+ <p className="mt-2 text-sm leading-relaxed text-brand-dark/80">{copy.detail}</p>
62
+ </div>
63
+ );
64
+ }
65
+
37
66
  export function RuntimeOverview(props: RuntimeOverviewProps) {
38
67
  const { snapshot } = props;
39
68
 
@@ -72,6 +101,8 @@ export function RuntimeOverview(props: RuntimeOverviewProps) {
72
101
  />
73
102
  </div>
74
103
 
104
+ <CloudSyncHealthCard health={snapshot.cloud_sync_health} />
105
+
75
106
  <div className="rounded-xl border border-border bg-white px-5 py-4">
76
107
  <p className="text-xs font-semibold uppercase tracking-[0.18em] text-brand-blue">
77
108
  Recommended next step
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "plugin-scanner"
7
- version = "2.0.117"
7
+ version = "2.0.119"
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.117"
7
+ version = "2.0.119"
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"
@@ -0,0 +1,223 @@
1
+ """Local access graph snapshot event queueing for Guard Cloud."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import json
7
+
8
+ from .edge_events import build_access_graph_snapshot_event
9
+ from .models import HarnessDetection
10
+ from .redaction import redact_sensitive_text
11
+ from .store import GuardStore
12
+
13
+
14
+ def queue_access_graph_snapshot(
15
+ *,
16
+ store: GuardStore,
17
+ detection: HarnessDetection,
18
+ artifacts: list[dict[str, object]],
19
+ now: str,
20
+ ) -> None:
21
+ workspace_id = store.get_cloud_workspace_id()
22
+ device_id = store.get_or_create_installation_id()
23
+ device_fingerprint = f"device:{device_id}"
24
+ harness_fingerprint = f"harness:{detection.harness}"
25
+ agent_id = f"{detection.harness}:local-agent"
26
+ agent_fingerprint = f"agent:{agent_id}"
27
+ entities: list[dict[str, object]] = []
28
+ edges: list[dict[str, object]] = []
29
+ seen_fingerprints: set[str] = set()
30
+
31
+ def add_entity(entity: dict[str, object]) -> None:
32
+ fingerprint = entity.get("fingerprint")
33
+ if not isinstance(fingerprint, str) or fingerprint in seen_fingerprints:
34
+ return
35
+ seen_fingerprints.add(fingerprint)
36
+ entities.append(entity)
37
+
38
+ _add_device_harness_and_agent(
39
+ add_entity=add_entity,
40
+ edges=edges,
41
+ device_id=device_id,
42
+ device_fingerprint=device_fingerprint,
43
+ detection=detection,
44
+ harness_fingerprint=harness_fingerprint,
45
+ agent_id=agent_id,
46
+ agent_fingerprint=agent_fingerprint,
47
+ now=now,
48
+ )
49
+ _add_artifact_entities(
50
+ add_entity=add_entity,
51
+ edges=edges,
52
+ artifacts=artifacts,
53
+ agent_fingerprint=agent_fingerprint,
54
+ now=now,
55
+ )
56
+ snapshot_seed = {
57
+ "workspace": workspace_id,
58
+ "device": device_id,
59
+ "harness": detection.harness,
60
+ "generatedAt": now,
61
+ }
62
+ snapshot_hash = hashlib.sha256(json.dumps(snapshot_seed, sort_keys=True).encode("utf-8")).hexdigest()[:24]
63
+ snapshot_id = f"access-graph-{snapshot_hash}"
64
+ payload = {
65
+ "snapshotId": snapshot_id,
66
+ "generatedAt": now,
67
+ "entities": entities,
68
+ "edges": edges,
69
+ }
70
+ try:
71
+ store.add_guard_event_v1(
72
+ build_access_graph_snapshot_event(
73
+ snapshot_id=snapshot_id,
74
+ occurred_at=now,
75
+ payload=payload,
76
+ workspace_id=workspace_id,
77
+ device_id=device_id,
78
+ )
79
+ )
80
+ except Exception as error:
81
+ store.add_event(
82
+ "access_graph_snapshot_queue_failed",
83
+ {
84
+ "error_type": type(error).__name__,
85
+ "message": redact_sensitive_text(str(error)),
86
+ },
87
+ now,
88
+ )
89
+
90
+
91
+ def _add_device_harness_and_agent(
92
+ *,
93
+ add_entity,
94
+ edges: list[dict[str, object]],
95
+ device_id: str,
96
+ device_fingerprint: str,
97
+ detection: HarnessDetection,
98
+ harness_fingerprint: str,
99
+ agent_id: str,
100
+ agent_fingerprint: str,
101
+ now: str,
102
+ ) -> None:
103
+ add_entity(
104
+ {
105
+ "entityType": "device",
106
+ "entityId": device_id,
107
+ "displayName": "Local machine",
108
+ "fingerprint": device_fingerprint,
109
+ "metadata": {},
110
+ "firstSeenAt": now,
111
+ "lastSeenAt": now,
112
+ }
113
+ )
114
+ add_entity(
115
+ {
116
+ "entityType": "harness",
117
+ "entityId": detection.harness,
118
+ "displayName": detection.harness,
119
+ "fingerprint": harness_fingerprint,
120
+ "metadata": {"installed": detection.installed, "commandAvailable": detection.command_available},
121
+ "firstSeenAt": now,
122
+ "lastSeenAt": now,
123
+ }
124
+ )
125
+ edges.append(
126
+ {
127
+ "sourceFingerprint": device_fingerprint,
128
+ "targetFingerprint": harness_fingerprint,
129
+ "edgeType": "device_runs_harness",
130
+ "confidence": 100,
131
+ "metadata": {},
132
+ "firstSeenAt": now,
133
+ "lastSeenAt": now,
134
+ }
135
+ )
136
+ add_entity(
137
+ {
138
+ "entityType": "agent",
139
+ "entityId": agent_id,
140
+ "displayName": f"{detection.harness} local agent",
141
+ "fingerprint": agent_fingerprint,
142
+ "metadata": {"harness": detection.harness},
143
+ "firstSeenAt": now,
144
+ "lastSeenAt": now,
145
+ }
146
+ )
147
+ edges.append(
148
+ {
149
+ "sourceFingerprint": harness_fingerprint,
150
+ "targetFingerprint": agent_fingerprint,
151
+ "edgeType": "harness_runs_agent",
152
+ "confidence": 90,
153
+ "metadata": {},
154
+ "firstSeenAt": now,
155
+ "lastSeenAt": now,
156
+ }
157
+ )
158
+
159
+
160
+ def _add_artifact_entities(
161
+ *,
162
+ add_entity,
163
+ edges: list[dict[str, object]],
164
+ artifacts: list[dict[str, object]],
165
+ agent_fingerprint: str,
166
+ now: str,
167
+ ) -> None:
168
+ for artifact in artifacts:
169
+ artifact_id = _non_empty_string(artifact.get("artifact_id"))
170
+ if artifact_id is None:
171
+ continue
172
+ artifact_type = _non_empty_string(artifact.get("artifact_type")) or "tool"
173
+ entity_type = _access_graph_entity_type(artifact_type)
174
+ fingerprint = f"{entity_type}:{artifact_id}"
175
+ add_entity(
176
+ {
177
+ "entityType": entity_type,
178
+ "entityId": artifact_id,
179
+ "displayName": _non_empty_string(artifact.get("artifact_name")) or artifact_id,
180
+ "fingerprint": fingerprint,
181
+ "metadata": {
182
+ "artifactType": artifact_type,
183
+ "sourceScope": _non_empty_string(artifact.get("source_scope")),
184
+ "policyAction": _non_empty_string(artifact.get("policy_action")),
185
+ "present": artifact.get("removed") is not True,
186
+ },
187
+ "firstSeenAt": now,
188
+ "lastSeenAt": now,
189
+ }
190
+ )
191
+ edge_type = _access_graph_artifact_edge_type(entity_type)
192
+ if edge_type is not None:
193
+ edges.append(
194
+ {
195
+ "sourceFingerprint": agent_fingerprint,
196
+ "targetFingerprint": fingerprint,
197
+ "edgeType": edge_type,
198
+ "confidence": 80,
199
+ "metadata": {},
200
+ "firstSeenAt": now,
201
+ "lastSeenAt": now,
202
+ }
203
+ )
204
+
205
+
206
+ def _access_graph_entity_type(artifact_type: str) -> str:
207
+ if artifact_type in {"skill", "mcp_server", "tool", "repository", "agent", "policy", "integration"}:
208
+ return artifact_type
209
+ return "tool"
210
+
211
+
212
+ def _access_graph_artifact_edge_type(entity_type: str) -> str | None:
213
+ if entity_type == "skill":
214
+ return "agent_uses_skill"
215
+ if entity_type == "mcp_server":
216
+ return "agent_uses_mcp_server"
217
+ return None
218
+
219
+
220
+ def _non_empty_string(value: object) -> str | None:
221
+ if isinstance(value, str) and value.strip():
222
+ return value
223
+ return None
@@ -8,6 +8,7 @@ from hashlib import sha256
8
8
  from pathlib import PurePath
9
9
 
10
10
  from ..models import GuardArtifact, HarnessDetection
11
+ from ..runtime.mcp_protection import McpServerIdentity, build_mcp_server_identity
11
12
 
12
13
 
13
14
  @dataclass(frozen=True, slots=True)
@@ -23,6 +24,7 @@ class ManagedMcpServer:
23
24
  transport: str
24
25
  env: dict[str, str]
25
26
  enabled: bool
27
+ identity: McpServerIdentity | None = None
26
28
 
27
29
 
28
30
  _GUARD_PROXY_COMMANDS = frozenset(
@@ -113,6 +115,9 @@ def proxy_cli_args(
113
115
  args.extend(["--workspace", workspace])
114
116
  for value in server.args:
115
117
  args.append(f"--arg={value}")
118
+ for key in sorted(server.env):
119
+ if key.strip():
120
+ args.append(f"--server-env-key={key.strip()}")
116
121
  return args
117
122
 
118
123
 
@@ -156,6 +161,13 @@ def _managed_stdio_server(artifact: GuardArtifact) -> ManagedMcpServer | None:
156
161
  transport=transport,
157
162
  env=env,
158
163
  enabled=enabled,
164
+ identity=build_mcp_server_identity(
165
+ config_path=artifact.config_path,
166
+ command=artifact.command,
167
+ args=artifact.args,
168
+ transport=transport,
169
+ env=env,
170
+ ),
159
171
  )
160
172
 
161
173
 
@@ -6,7 +6,7 @@ import time
6
6
  import uuid
7
7
  from collections.abc import Mapping
8
8
  from dataclasses import replace
9
- from datetime import datetime, timezone
9
+ from datetime import datetime, timedelta, timezone
10
10
  from pathlib import Path
11
11
  from urllib.parse import urlparse
12
12
 
@@ -374,11 +374,13 @@ def _build_runtime_cloud_context(store: GuardStore) -> dict[str, object]:
374
374
  remote_payload_active=remote_payload_active,
375
375
  )
376
376
  dashboard_url, inbox_url, fleet_url, connect_url = _resolve_guard_urls(sync_url)
377
+ sync_health = _build_cloud_sync_health(store, credentials is not None, cloud_state)
377
378
  return {
378
379
  "sync_configured": credentials is not None,
379
380
  "cloud_state": cloud_state,
380
381
  "cloud_state_label": _runtime_cloud_state_label(cloud_state),
381
382
  "cloud_state_detail": _runtime_cloud_state_detail(cloud_state),
383
+ "cloud_sync_health": sync_health,
382
384
  "cloud_pairing_state": {
383
385
  "state": cloud_state,
384
386
  "label": _runtime_cloud_state_label(cloud_state),
@@ -396,6 +398,102 @@ def _build_runtime_cloud_context(store: GuardStore) -> dict[str, object]:
396
398
  }
397
399
 
398
400
 
401
+ def _build_cloud_sync_health(store: GuardStore, sync_configured: bool, cloud_state: str) -> dict[str, object]:
402
+ pending_events = store.count_guard_events_v1(uploaded=False)
403
+ event_summary = store.get_sync_payload("guard_events_v1_summary") or {}
404
+ sync_summary = store.get_sync_payload("sync_summary") or {}
405
+ runtime_summary = store.get_sync_payload("runtime_session_summary") or {}
406
+ last_synced_at = _latest_sync_timestamp(
407
+ event_summary.get("synced_at"),
408
+ sync_summary.get("synced_at"),
409
+ runtime_summary.get("synced_at"),
410
+ )
411
+ if not sync_configured:
412
+ state = "disabled"
413
+ elif isinstance(event_summary, dict) and event_summary.get("status") == "failed":
414
+ state = "failed"
415
+ elif (
416
+ isinstance(event_summary, dict)
417
+ and event_summary.get("sync_skipped") is True
418
+ and event_summary.get("sync_reason") == "guard_events_endpoint_unavailable"
419
+ ):
420
+ state = "degraded"
421
+ elif last_synced_at is not None and _timestamp_is_stale(last_synced_at):
422
+ state = "stale"
423
+ elif pending_events > 0 or cloud_state == "paired_waiting":
424
+ state = "pending"
425
+ else:
426
+ state = "healthy"
427
+ return {
428
+ "state": state,
429
+ "label": _cloud_sync_health_label(state),
430
+ "detail": _cloud_sync_health_detail(state, pending_events=pending_events),
431
+ "pending_events": pending_events,
432
+ "last_synced_at": last_synced_at,
433
+ "next_retry_after": event_summary.get("next_retry_after") if isinstance(event_summary, dict) else None,
434
+ }
435
+
436
+
437
+ def _latest_sync_timestamp(*values: object) -> str | None:
438
+ parsed_values: list[tuple[datetime, str]] = []
439
+ for value in values:
440
+ if not isinstance(value, str) or not value.strip():
441
+ continue
442
+ parsed = _parse_timestamp(value)
443
+ if parsed is not None:
444
+ parsed_values.append((parsed, value))
445
+ if not parsed_values:
446
+ return None
447
+ return max(parsed_values, key=lambda item: item[0])[1]
448
+
449
+
450
+ def _parse_timestamp(value: str) -> datetime | None:
451
+ try:
452
+ parsed = datetime.fromisoformat(value.replace("Z", "+00:00"))
453
+ except ValueError:
454
+ return None
455
+ if parsed.tzinfo is None:
456
+ return parsed.replace(tzinfo=timezone.utc)
457
+ return parsed
458
+
459
+
460
+ def _timestamp_is_stale(value: str) -> bool:
461
+ parsed = _parse_timestamp(value)
462
+ if parsed is None:
463
+ return False
464
+ return datetime.now(timezone.utc) - parsed > timedelta(hours=24)
465
+
466
+
467
+ def _cloud_sync_health_label(state: str) -> str:
468
+ labels = {
469
+ "healthy": "Cloud sync healthy",
470
+ "pending": "Cloud sync pending",
471
+ "failed": "Cloud sync needs attention",
472
+ "degraded": "Cloud sync degraded",
473
+ "disabled": "Cloud sync disabled",
474
+ "stale": "Cloud sync stale",
475
+ }
476
+ return labels.get(state, "Cloud sync pending")
477
+
478
+
479
+ def _cloud_sync_health_detail(state: str, *, pending_events: int) -> str:
480
+ if state == "healthy":
481
+ return "Guard Cloud has the latest local proof from this machine."
482
+ if state == "failed":
483
+ return "The latest Cloud upload failed. HOL Guard kept local protection active and will retry."
484
+ if state == "degraded":
485
+ return "Cloud accepted legacy sync, but v1 Guard event ingest is unavailable. Local protection stayed active."
486
+ if state == "disabled":
487
+ return "Local protection is active. Connect Cloud when you want shared team proof."
488
+ if state == "stale":
489
+ return "Cloud has not seen fresh local proof recently. Keep this runtime open or run sync again."
490
+ if pending_events == 1:
491
+ return "One local proof event is queued for the next Cloud sync."
492
+ if pending_events > 1:
493
+ return f"{pending_events} local proof events are queued for the next Cloud sync."
494
+ return "Waiting for the first shared Cloud proof from this machine."
495
+
496
+
399
497
  def _resolve_runtime_cloud_state(*, sync_configured: bool, sync_completed: bool, remote_payload_active: bool) -> str:
400
498
  if not sync_configured:
401
499
  return "local_only"
@@ -95,6 +95,7 @@ from ..runtime.secret_file_requests import (
95
95
  build_file_read_request_artifact,
96
96
  build_tool_action_request_artifact,
97
97
  extract_sensitive_file_read_request,
98
+ extract_sensitive_file_read_request_from_action,
98
99
  extract_sensitive_tool_action_request,
99
100
  is_explicitly_benign_tool_action_request,
100
101
  )
@@ -561,6 +562,7 @@ def _configure_guard_parser(guard_parser: argparse.ArgumentParser) -> None:
561
562
  codex_proxy_parser.add_argument("--transport", default="stdio")
562
563
  codex_proxy_parser.add_argument("--command", dest="server_command", required=True)
563
564
  codex_proxy_parser.add_argument("--arg", dest="server_args", action="append", default=[])
565
+ codex_proxy_parser.add_argument("--server-env-key", dest="server_env_keys", action="append", default=[])
564
566
 
565
567
  opencode_proxy_parser = guard_subparsers.add_parser("opencode-mcp-proxy", help=argparse.SUPPRESS)
566
568
  _add_guard_common_args(opencode_proxy_parser)
@@ -571,6 +573,7 @@ def _configure_guard_parser(guard_parser: argparse.ArgumentParser) -> None:
571
573
  opencode_proxy_parser.add_argument("--transport", default="local")
572
574
  opencode_proxy_parser.add_argument("--command", dest="server_command", required=True)
573
575
  opencode_proxy_parser.add_argument("--arg", dest="server_args", action="append", default=[])
576
+ opencode_proxy_parser.add_argument("--server-env-key", dest="server_env_keys", action="append", default=[])
574
577
 
575
578
  copilot_proxy_parser = guard_subparsers.add_parser("copilot-mcp-proxy", help=argparse.SUPPRESS)
576
579
  _add_guard_common_args(copilot_proxy_parser)
@@ -581,6 +584,7 @@ def _configure_guard_parser(guard_parser: argparse.ArgumentParser) -> None:
581
584
  copilot_proxy_parser.add_argument("--transport", default="stdio")
582
585
  copilot_proxy_parser.add_argument("--command", dest="server_command", required=True)
583
586
  copilot_proxy_parser.add_argument("--arg", dest="server_args", action="append", default=[])
587
+ copilot_proxy_parser.add_argument("--server-env-key", dest="server_env_keys", action="append", default=[])
584
588
 
585
589
  hermes_mcp_proxy_parser = guard_subparsers.add_parser("hermes-mcp-proxy", help=argparse.SUPPRESS)
586
590
  _add_guard_common_args(hermes_mcp_proxy_parser)
@@ -827,6 +831,7 @@ def run_guard_command(
827
831
  config_path=args.config_path,
828
832
  transport=args.transport,
829
833
  server_id=args.server_id,
834
+ server_env_keys=tuple(args.server_env_keys),
830
835
  )
831
836
  return proxy.serve()
832
837
 
@@ -841,6 +846,7 @@ def run_guard_command(
841
846
  config_path=args.config_path,
842
847
  transport=args.transport,
843
848
  server_id=args.server_id,
849
+ server_env_keys=tuple(args.server_env_keys),
844
850
  )
845
851
  return proxy.serve()
846
852
 
@@ -855,6 +861,7 @@ def run_guard_command(
855
861
  config_path=args.config_path,
856
862
  transport=args.transport,
857
863
  server_id=args.server_id,
864
+ server_env_keys=tuple(args.server_env_keys),
858
865
  )
859
866
  return proxy.serve()
860
867
 
@@ -1455,6 +1462,7 @@ def run_guard_command(
1455
1462
  runtime_artifact = _hook_runtime_artifact(
1456
1463
  harness=args.harness,
1457
1464
  payload=payload,
1465
+ action_envelope=action_envelope,
1458
1466
  home_dir=context.home_dir,
1459
1467
  guard_home=context.guard_home,
1460
1468
  workspace=runtime_workspace,
@@ -4019,6 +4027,7 @@ def _hook_runtime_artifact(
4019
4027
  *,
4020
4028
  harness: str,
4021
4029
  payload: dict[str, object],
4030
+ action_envelope: GuardActionEnvelope | None,
4022
4031
  home_dir: Path,
4023
4032
  guard_home: Path,
4024
4033
  workspace: Path | None,
@@ -4079,6 +4088,12 @@ def _hook_runtime_artifact(
4079
4088
  cwd=workspace,
4080
4089
  home_dir=home_dir,
4081
4090
  )
4091
+ if request is None:
4092
+ request = (
4093
+ extract_sensitive_file_read_request_from_action(action_envelope, cwd=workspace, home_dir=home_dir)
4094
+ if action_envelope is not None
4095
+ else None
4096
+ )
4082
4097
  source_scope = _coalesce_string(payload.get("source_scope"), "project")
4083
4098
  config_path = str(_runtime_policy_path(harness, home_dir, workspace))
4084
4099
  if request is not None:
@@ -5916,7 +5931,7 @@ def _guard_service_login_payload(
5916
5931
  "client_title": label,
5917
5932
  "client_version": _GUARD_CLIENT_VERSION,
5918
5933
  }
5919
- store.set_sync_credentials(sync_url, token, now)
5934
+ store.set_sync_credentials(sync_url, token, now, workspace_id=workspace or None)
5920
5935
  store.set_sync_payload(_SERVICE_RUNTIME_PROFILE_STATE_KEY, service_profile, now)
5921
5936
  device = store.set_device_label(label, now)
5922
5937
  store.add_event(
@@ -9,6 +9,7 @@ from pathlib import Path
9
9
  from typing import Any
10
10
 
11
11
  from ...models import ScanOptions
12
+ from ..access_graph_events import queue_access_graph_snapshot
12
13
  from ..adapters import get_adapter, list_adapters
13
14
  from ..adapters.base import HarnessContext
14
15
  from ..capabilities import compute_capability_delta, normalize_artifact_capabilities, severity_from_deltas
@@ -658,6 +659,13 @@ def evaluate_detection(
658
659
  },
659
660
  now,
660
661
  )
662
+ if persist:
663
+ queue_access_graph_snapshot(
664
+ store=store,
665
+ detection=detection,
666
+ artifacts=results,
667
+ now=now,
668
+ )
661
669
  return {
662
670
  "harness": detection.harness,
663
671
  "artifacts": results,