plugin-scanner 2.0.106__tar.gz → 2.0.107__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 (351) hide show
  1. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/PKG-INFO +1 -1
  2. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/pyproject.toml +1 -1
  3. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/pyproject.toml.bak +1 -1
  4. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +85 -0
  5. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/capabilities.py +19 -0
  6. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/commands.py +17 -4
  7. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +93 -15
  8. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +11 -0
  9. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/version.py +1 -1
  10. plugin_scanner-2.0.107/tests/conftest.py +15 -0
  11. plugin_scanner-2.0.107/tests/test_guard_access_graph.py +395 -0
  12. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_cli.py +37 -0
  13. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_runtime.py +2 -0
  14. plugin_scanner-2.0.106/tests/conftest.py +0 -9
  15. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.clusterfuzzlite/Dockerfile +0 -0
  16. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.clusterfuzzlite/build.sh +0 -0
  17. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.clusterfuzzlite/project.yaml +0 -0
  18. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.clusterfuzzlite/requirements-atheris.txt +0 -0
  19. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.dockerignore +0 -0
  20. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/CODEOWNERS +0 -0
  21. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  22. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  23. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  24. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/dependabot.yml +0 -0
  25. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/workflows/ci.yml +0 -0
  26. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/workflows/codeql.yml +0 -0
  27. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/workflows/dependabot-uv-lock.yml +0 -0
  28. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/workflows/fuzz.yml +0 -0
  29. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/workflows/harness-smoke.yml +0 -0
  30. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/workflows/publish.yml +0 -0
  31. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/workflows/scorecard.yml +0 -0
  32. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.gitignore +0 -0
  33. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.pre-commit-hooks.yaml +0 -0
  34. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/CONTRIBUTING.md +0 -0
  35. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/Dockerfile +0 -0
  36. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/LICENSE +0 -0
  37. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/README.md +0 -0
  38. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/SECURITY.md +0 -0
  39. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/index.html +0 -0
  40. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/package.json +0 -0
  41. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/pnpm-lock.yaml +0 -0
  42. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/public/apple-touch-icon.png +0 -0
  43. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
  44. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/public/brand/Logo_Whole.png +0 -0
  45. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/public/favicon-16x16.png +0 -0
  46. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/public/favicon-32x32.png +0 -0
  47. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/public/favicon.ico +0 -0
  48. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/app.tsx +0 -0
  49. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/approval-center-layout.tsx +0 -0
  50. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/approval-center-primitives.tsx +0 -0
  51. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/approval-center-utils.ts +0 -0
  52. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/fleet-workspace.tsx +0 -0
  53. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/guard-api.test.ts +0 -0
  54. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/guard-api.ts +0 -0
  55. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/guard-demo.ts +0 -0
  56. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/guard-types.ts +0 -0
  57. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/main.tsx +0 -0
  58. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/receipts-workspace.tsx +0 -0
  59. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/runtime-overview.tsx +0 -0
  60. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/settings-workspace.tsx +0 -0
  61. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/styles.css +0 -0
  62. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/vite-env.d.ts +0 -0
  63. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/tsconfig.json +0 -0
  64. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/vite.config.ts +0 -0
  65. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docker-requirements.txt +0 -0
  66. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docs/guard/approval-audit.md +0 -0
  67. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docs/guard/architecture.md +0 -0
  68. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docs/guard/get-started.md +0 -0
  69. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docs/guard/harness-support.md +0 -0
  70. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docs/guard/local-vs-cloud.md +0 -0
  71. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docs/guard/testing-matrix.md +0 -0
  72. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docs/trust/mcp-trust-draft.md +0 -0
  73. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docs/trust/plugin-trust-draft.md +0 -0
  74. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docs/trust/skill-trust-local.md +0 -0
  75. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/fuzzers/manifest_fuzzer.py +0 -0
  76. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/requirements.txt +0 -0
  77. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/schemas/plugin-quality.v1.json +0 -0
  78. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/schemas/scan-result.v1.json +0 -0
  79. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/schemas/verify-result.v1.json +0 -0
  80. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/__init__.py +0 -0
  81. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/action_runner.py +0 -0
  82. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/argparse_utils.py +0 -0
  83. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/__init__.py +0 -0
  84. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
  85. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/claude.py +0 -0
  86. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
  87. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
  88. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/gemini.py +0 -0
  89. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/manifest.py +0 -0
  90. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
  91. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
  92. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
  93. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/opencode.py +0 -0
  94. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
  95. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/security.py +0 -0
  96. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
  97. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/cli.py +0 -0
  98. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/cli_ui.py +0 -0
  99. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/config.py +0 -0
  100. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
  101. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
  102. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
  103. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
  104. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
  105. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
  106. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
  107. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
  108. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
  109. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/github_reporting.py +0 -0
  110. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/__init__.py +0 -0
  111. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
  112. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
  113. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
  114. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
  115. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +0 -0
  116. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
  117. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
  118. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
  119. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
  120. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
  121. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
  122. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
  123. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
  124. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
  125. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
  126. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
  127. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/approvals.py +0 -0
  128. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
  129. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
  130. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
  131. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
  132. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
  133. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
  134. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
  135. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
  136. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
  137. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
  138. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
  139. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/config.py +0 -0
  140. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
  141. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
  142. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
  143. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
  144. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
  145. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
  146. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
  147. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
  148. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
  149. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
  150. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
  151. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
  152. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
  153. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
  154. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
  155. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
  156. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/incident.py +0 -0
  157. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/launcher.py +0 -0
  158. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/models.py +0 -0
  159. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
  160. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
  161. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/protect.py +0 -0
  162. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
  163. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
  164. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
  165. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
  166. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
  167. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/redaction.py +0 -0
  168. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/risk.py +0 -0
  169. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
  170. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
  171. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
  172. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/detectors.py +0 -0
  173. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
  174. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
  175. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/secret_sensitivity.py +0 -0
  176. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
  177. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
  178. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
  179. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
  180. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
  181. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
  182. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/shims.py +0 -0
  183. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/store.py +0 -0
  184. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
  185. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
  186. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/types.py +0 -0
  187. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
  188. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
  189. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
  190. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/lint_fixes.py +0 -0
  191. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/marketplace_support.py +0 -0
  192. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/models.py +0 -0
  193. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/path_support.py +0 -0
  194. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/policy.py +0 -0
  195. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/quality_artifact.py +0 -0
  196. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/repo_detect.py +0 -0
  197. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/reporting.py +0 -0
  198. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/rules/__init__.py +0 -0
  199. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/rules/registry.py +0 -0
  200. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/rules/specs.py +0 -0
  201. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/scanner.py +0 -0
  202. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/submission.py +0 -0
  203. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/suppressions.py +0 -0
  204. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
  205. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_helpers.py +0 -0
  206. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
  207. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_models.py +0 -0
  208. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
  209. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_scoring.py +0 -0
  210. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
  211. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_specs.py +0 -0
  212. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/verification.py +0 -0
  213. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/__init__.py +0 -0
  214. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/__init__.py +0 -0
  215. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
  216. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/bad-plugin/.mcp.json +0 -0
  217. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/bad-plugin/secrets.js +0 -0
  218. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
  219. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
  220. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/claude-plugin-good/README.md +0 -0
  221. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
  222. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
  223. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
  224. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/code-quality-bad/evil.js +0 -0
  225. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/code-quality-bad/inject.js +0 -0
  226. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
  227. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
  228. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/gemini-extension-good/README.md +0 -0
  229. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
  230. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
  231. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
  232. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
  233. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/.codexignore +0 -0
  234. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/LICENSE +0 -0
  235. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/README.md +0 -0
  236. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/SECURITY.md +0 -0
  237. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
  238. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
  239. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
  240. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
  241. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
  242. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
  243. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
  244. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
  245. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
  246. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
  247. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
  248. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
  249. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
  250. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
  251. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
  252. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
  253. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
  254. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
  255. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
  256. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/mcp-canary-server.py +0 -0
  257. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
  258. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
  259. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/mit-license/LICENSE +0 -0
  260. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
  261. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
  262. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
  263. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
  264. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
  265. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
  266. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
  267. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
  268. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
  269. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
  270. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
  271. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
  272. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
  273. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
  274. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
  275. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
  276. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
  277. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
  278. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/opencode-good/LICENSE +0 -0
  279. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/opencode-good/README.md +0 -0
  280. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/opencode-good/SECURITY.md +0 -0
  281. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
  282. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
  283. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
  284. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
  285. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
  286. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
  287. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/with-marketplace/marketplace.json +0 -0
  288. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test-trust-scoring.py +0 -0
  289. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test-trust-specs.py +0 -0
  290. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_action_runner.py +0 -0
  291. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_best_practices.py +0 -0
  292. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_cisco_install_surfaces.py +0 -0
  293. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_cli.py +0 -0
  294. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_code_quality.py +0 -0
  295. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_config.py +0 -0
  296. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_coverage_remaining.py +0 -0
  297. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_ecosystems.py +0 -0
  298. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_edge_cases.py +0 -0
  299. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_final_coverage.py +0 -0
  300. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_approvals.py +0 -0
  301. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_bootstrap.py +0 -0
  302. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_capabilities.py +0 -0
  303. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_claude_adapter.py +0 -0
  304. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_codex_e2e.py +0 -0
  305. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_codex_install.py +0 -0
  306. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_codex_proxy.py +0 -0
  307. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_config_paths.py +0 -0
  308. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_connect_flow.py +0 -0
  309. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_consumer_mode.py +0 -0
  310. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_copilot_adapter.py +0 -0
  311. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_copilot_proxy.py +0 -0
  312. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_daemon_manager.py +0 -0
  313. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_event_schema_v1.py +0 -0
  314. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_events.py +0 -0
  315. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_launch_env.py +0 -0
  316. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_opencode_proxy.py +0 -0
  317. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_product_flow.py +0 -0
  318. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_protect.py +0 -0
  319. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_render.py +0 -0
  320. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_risk.py +0 -0
  321. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_runtime_action_harnesses.py +0 -0
  322. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_runtime_actions.py +0 -0
  323. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_runtime_decisions.py +0 -0
  324. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_runtime_detectors.py +0 -0
  325. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_runtime_signals.py +0 -0
  326. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_store_migrations.py +0 -0
  327. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_surface_server.py +0 -0
  328. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_verdicts.py +0 -0
  329. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_hermes_adapter.py +0 -0
  330. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_integration.py +0 -0
  331. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_lint_fixes.py +0 -0
  332. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_live_cisco_smoke.py +0 -0
  333. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_manifest.py +0 -0
  334. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_marketplace.py +0 -0
  335. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_mcp_security.py +0 -0
  336. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_openclaw_adapter.py +0 -0
  337. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_operational_security.py +0 -0
  338. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_policy.py +0 -0
  339. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_quality_artifact.py +0 -0
  340. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_rule_registry.py +0 -0
  341. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_scanner.py +0 -0
  342. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_schema_contracts.py +0 -0
  343. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_security.py +0 -0
  344. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_security_ops.py +0 -0
  345. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_skill_security.py +0 -0
  346. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_submission.py +0 -0
  347. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_trust_scoring.py +0 -0
  348. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_trust_specs.py +0 -0
  349. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_verification.py +0 -0
  350. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_versioning.py +0 -0
  351. {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 2.0.106
3
+ Version: 2.0.107
4
4
  Summary: Lint, verify, and gate plugin ecosystems for maintainers, CI, and publish workflows.
5
5
  Project-URL: Homepage, https://github.com/hashgraph-online/ai-plugin-scanner
6
6
  Project-URL: Repository, https://github.com/hashgraph-online/ai-plugin-scanner
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "plugin-scanner"
7
- version = "2.0.106"
7
+ version = "2.0.107"
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.106"
7
+ version = "2.0.107"
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"
@@ -2,7 +2,10 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import json
5
6
  from dataclasses import dataclass
7
+ from hashlib import sha256
8
+ from pathlib import PurePath
6
9
 
7
10
  from ..models import GuardArtifact, HarnessDetection
8
11
 
@@ -31,6 +34,23 @@ _GUARD_PROXY_COMMANDS = frozenset(
31
34
  }
32
35
  )
33
36
 
37
+ _STABLE_SLASH_FLAG_TOKENS = frozenset(
38
+ {
39
+ "/?",
40
+ "/debug",
41
+ "/dry-run",
42
+ "/h",
43
+ "/help",
44
+ "/quiet",
45
+ "/read-only",
46
+ "/readonly",
47
+ "/ro",
48
+ "/safe",
49
+ "/trace",
50
+ "/verbose",
51
+ }
52
+ )
53
+
34
54
 
35
55
  def managed_stdio_servers(detection: HarnessDetection) -> tuple[ManagedMcpServer, ...]:
36
56
  """Extract local stdio MCP servers from a harness detection payload."""
@@ -76,6 +96,8 @@ def proxy_cli_args(
76
96
  guard_home,
77
97
  "--server-name",
78
98
  server.name,
99
+ "--server-id",
100
+ stable_mcp_server_identifier(server),
79
101
  "--source-scope",
80
102
  server.source_scope,
81
103
  "--config-path",
@@ -94,6 +116,24 @@ def proxy_cli_args(
94
116
  return args
95
117
 
96
118
 
119
+ def stable_mcp_server_identifier(server: ManagedMcpServer) -> str:
120
+ """Build a Cloud-stable MCP server ID without local config path material."""
121
+
122
+ harness = server.harness.strip().lower()
123
+ source_scope = server.source_scope.strip().lower()
124
+ server_name = _stable_server_name(server.name)
125
+ payload = {
126
+ "harness": harness,
127
+ "source_scope": source_scope,
128
+ "name": server_name,
129
+ "command": _stable_command_name(server.command),
130
+ "args": [_stable_arg_token(value) for value in server.args],
131
+ "transport": server.transport,
132
+ }
133
+ digest = sha256(json.dumps(payload, sort_keys=True).encode("utf-8")).hexdigest()[:20]
134
+ return f"mcp_server:{harness}:{source_scope}:{server_name}:{digest}"
135
+
136
+
97
137
  def _managed_stdio_server(artifact: GuardArtifact) -> ManagedMcpServer | None:
98
138
  if artifact.artifact_type != "mcp_server":
99
139
  return None
@@ -119,6 +159,50 @@ def _managed_stdio_server(artifact: GuardArtifact) -> ManagedMcpServer | None:
119
159
  )
120
160
 
121
161
 
162
+ def _stable_arg_token(value: str) -> str:
163
+ key, separator, item = value.partition("=")
164
+ if separator and (_looks_like_path_assignment(key, item) or _looks_like_path_token(item)):
165
+ return f"{key}=<path>"
166
+ if _looks_like_path_token(value):
167
+ return "<path>"
168
+ return value
169
+
170
+
171
+ def _stable_server_name(value: str) -> str:
172
+ return value.strip().lower() or "unnamed"
173
+
174
+
175
+ def _stable_command_name(value: str) -> str:
176
+ return PurePath(value.replace("\\", "/")).name.lower()
177
+
178
+
179
+ def _looks_like_path_assignment(key: str, value: str) -> bool:
180
+ normalized_key = key.strip().lstrip("-/").lower().replace("_", "-")
181
+ path_keys = {
182
+ "cache",
183
+ "config",
184
+ "cwd",
185
+ "dir",
186
+ "directory",
187
+ "file",
188
+ "folder",
189
+ "path",
190
+ "root",
191
+ "workspace",
192
+ "workdir",
193
+ }
194
+ return normalized_key in path_keys and value.strip().replace("\\", "/").startswith("/")
195
+
196
+
197
+ def _looks_like_path_token(value: str) -> bool:
198
+ normalized = value.strip().replace("\\", "/")
199
+ if normalized.startswith(("~/", "./", "../")):
200
+ return True
201
+ if normalized.startswith("/"):
202
+ return "/" in normalized[1:] or normalized.lower() not in _STABLE_SLASH_FLAG_TOKENS
203
+ return len(normalized) >= 3 and normalized[0].isalpha() and normalized[1:3] == ":/"
204
+
205
+
122
206
  def _string_env(value: object) -> dict[str, str]:
123
207
  if not isinstance(value, dict):
124
208
  return {}
@@ -149,4 +233,5 @@ __all__ = [
149
233
  "managed_stdio_servers",
150
234
  "proxy_cli_args",
151
235
  "skipped_stdio_server_names",
236
+ "stable_mcp_server_identifier",
152
237
  ]
@@ -196,6 +196,25 @@ def severity_from_deltas(deltas: tuple[CapabilityDelta, ...]) -> int:
196
196
  return max(delta.severity for delta in deltas)
197
197
 
198
198
 
199
+ def normalized_capability_categories(capabilities: CapabilitySet) -> tuple[str, ...]:
200
+ """Return broad Cloud access graph categories for skills and MCP tools."""
201
+
202
+ categories: set[str] = set()
203
+ if capabilities.network_hosts or capabilities.network_schemes:
204
+ categories.add("network")
205
+ if capabilities.filesystem_paths:
206
+ categories.add("filesystem")
207
+ if capabilities.secret_classes:
208
+ categories.add("secret")
209
+ if capabilities.subprocess_invocation or capabilities.interpreters or capabilities.shell_wrappers:
210
+ categories.add("execution")
211
+ if capabilities.publisher:
212
+ categories.add("publisher")
213
+ if capabilities.transport != "local":
214
+ categories.add("transport")
215
+ return tuple(sorted(categories))
216
+
217
+
199
218
  def _first_seen_deltas(after: CapabilitySet) -> list[CapabilityDelta]:
200
219
  deltas: list[CapabilityDelta] = []
201
220
  if after.network_hosts:
@@ -539,6 +539,7 @@ def _configure_guard_parser(guard_parser: argparse.ArgumentParser) -> None:
539
539
  codex_proxy_parser = guard_subparsers.add_parser("codex-mcp-proxy", help=argparse.SUPPRESS)
540
540
  _add_guard_common_args(codex_proxy_parser)
541
541
  codex_proxy_parser.add_argument("--server-name", required=True)
542
+ codex_proxy_parser.add_argument("--server-id")
542
543
  codex_proxy_parser.add_argument("--source-scope", default="project")
543
544
  codex_proxy_parser.add_argument("--config-path", required=True)
544
545
  codex_proxy_parser.add_argument("--transport", default="stdio")
@@ -548,6 +549,7 @@ def _configure_guard_parser(guard_parser: argparse.ArgumentParser) -> None:
548
549
  opencode_proxy_parser = guard_subparsers.add_parser("opencode-mcp-proxy", help=argparse.SUPPRESS)
549
550
  _add_guard_common_args(opencode_proxy_parser)
550
551
  opencode_proxy_parser.add_argument("--server-name", required=True)
552
+ opencode_proxy_parser.add_argument("--server-id")
551
553
  opencode_proxy_parser.add_argument("--source-scope", default="project")
552
554
  opencode_proxy_parser.add_argument("--config-path", required=True)
553
555
  opencode_proxy_parser.add_argument("--transport", default="local")
@@ -557,6 +559,7 @@ def _configure_guard_parser(guard_parser: argparse.ArgumentParser) -> None:
557
559
  copilot_proxy_parser = guard_subparsers.add_parser("copilot-mcp-proxy", help=argparse.SUPPRESS)
558
560
  _add_guard_common_args(copilot_proxy_parser)
559
561
  copilot_proxy_parser.add_argument("--server-name", required=True)
562
+ copilot_proxy_parser.add_argument("--server-id")
560
563
  copilot_proxy_parser.add_argument("--source-scope", default="project")
561
564
  copilot_proxy_parser.add_argument("--config-path", required=True)
562
565
  copilot_proxy_parser.add_argument("--transport", default="stdio")
@@ -807,6 +810,7 @@ def run_guard_command(
807
810
  source_scope=args.source_scope,
808
811
  config_path=args.config_path,
809
812
  transport=args.transport,
813
+ server_id=args.server_id,
810
814
  )
811
815
  return proxy.serve()
812
816
 
@@ -820,6 +824,7 @@ def run_guard_command(
820
824
  source_scope=args.source_scope,
821
825
  config_path=args.config_path,
822
826
  transport=args.transport,
827
+ server_id=args.server_id,
823
828
  )
824
829
  return proxy.serve()
825
830
 
@@ -833,6 +838,7 @@ def run_guard_command(
833
838
  source_scope=args.source_scope,
834
839
  config_path=args.config_path,
835
840
  transport=args.transport,
841
+ server_id=args.server_id,
836
842
  )
837
843
  return proxy.serve()
838
844
 
@@ -1253,6 +1259,7 @@ def run_guard_command(
1253
1259
  decision_source="pre-tool-hook",
1254
1260
  now=now,
1255
1261
  signals=decision.signals,
1262
+ risk_categories=decision.risk_categories,
1256
1263
  remember=False,
1257
1264
  )
1258
1265
  if _should_emit_copilot_hook_response(args):
@@ -1267,6 +1274,7 @@ def run_guard_command(
1267
1274
  decision_source="pre-tool-hook",
1268
1275
  now=now,
1269
1276
  signals=decision.signals,
1277
+ risk_categories=decision.risk_categories,
1270
1278
  )
1271
1279
  if _should_emit_copilot_hook_response(args):
1272
1280
  _emit_copilot_hook_response(
@@ -1345,6 +1353,7 @@ def run_guard_command(
1345
1353
  decision_source=decision.source,
1346
1354
  now=now,
1347
1355
  signals=decision.signals,
1356
+ risk_categories=decision.risk_categories,
1348
1357
  remember=False,
1349
1358
  )
1350
1359
  if _should_emit_copilot_hook_response(args):
@@ -1359,6 +1368,7 @@ def run_guard_command(
1359
1368
  decision_source="permission-request-hook",
1360
1369
  now=now,
1361
1370
  signals=decision.signals,
1371
+ risk_categories=decision.risk_categories,
1362
1372
  )
1363
1373
  approval_center_url = ensure_guard_daemon(guard_home)
1364
1374
  approval_flow = get_adapter(args.harness).approval_flow(managed_install=managed_install)
@@ -2010,18 +2020,19 @@ def _should_emit_native_hook_json_response(
2010
2020
 
2011
2021
 
2012
2022
  def _should_emit_native_hook_exit_block(args: argparse.Namespace, *, event_name: str, policy_action: str) -> bool:
2013
- codex_runtime_marker = (
2014
- os.environ.get("CODEX_HOME", "").strip() or os.environ.get("CODEX_MANAGED_BY_BUN", "").strip()
2015
- )
2016
2023
  return (
2017
2024
  args.harness == "codex"
2018
2025
  and event_name == "PreToolUse"
2019
2026
  and policy_action in {"block", "sandbox-required", "require-reapproval"}
2020
2027
  and not getattr(args, "json", False)
2021
- and bool(codex_runtime_marker)
2028
+ and _is_codex_native_runtime()
2022
2029
  )
2023
2030
 
2024
2031
 
2032
+ def _is_codex_native_runtime() -> bool:
2033
+ return bool(os.environ.get("CODEX_HOME", "").strip() or os.environ.get("CODEX_MANAGED_BY_BUN", "").strip())
2034
+
2035
+
2025
2036
  def _codex_browser_approval_decision(
2026
2037
  *,
2027
2038
  args: argparse.Namespace,
@@ -2040,6 +2051,8 @@ def _codex_browser_approval_decision(
2040
2051
  return None
2041
2052
  if policy_action not in {"block", "sandbox-required", "require-reapproval"}:
2042
2053
  return None
2054
+ if event_name == "PreToolUse" and not _is_codex_native_runtime():
2055
+ return None
2043
2056
  approval_requests = response_payload.get("approval_requests")
2044
2057
  if not isinstance(approval_requests, list):
2045
2058
  return None
@@ -22,6 +22,7 @@ class ToolCallDecision:
22
22
  source: str
23
23
  signals: tuple[str, ...]
24
24
  summary: str
25
+ risk_categories: tuple[str, ...] = ()
25
26
 
26
27
 
27
28
  def build_tool_call_artifact(
@@ -32,9 +33,12 @@ def build_tool_call_artifact(
32
33
  source_scope: str,
33
34
  config_path: str,
34
35
  transport: str,
36
+ server_id: str | None = None,
35
37
  server_fingerprint: object | None = None,
36
38
  ) -> GuardArtifact:
37
39
  metadata = {"server_name": server_name}
40
+ if server_id is not None:
41
+ metadata["server_id"] = server_id
38
42
  if server_fingerprint is not None:
39
43
  metadata["server_fingerprint"] = server_fingerprint
40
44
  return GuardArtifact(
@@ -82,20 +86,24 @@ def evaluate_tool_call(
82
86
  override = config.resolve_action_override(artifact.harness, artifact.artifact_id, artifact.publisher)
83
87
  action = _coerce_guard_action(override) if isinstance(override, str) else None
84
88
  if action is not None:
89
+ risk_categories = tool_call_risk_categories(artifact, arguments)
85
90
  return ToolCallDecision(
86
91
  action=action,
87
92
  source="policy",
88
93
  signals=tool_call_risk_signals(artifact, arguments),
89
94
  summary="Local Guard policy matched this exact tool call.",
95
+ risk_categories=risk_categories,
90
96
  )
91
97
 
92
98
  signals = tool_call_risk_signals(artifact, arguments)
99
+ risk_categories = tool_call_risk_categories(artifact, arguments)
93
100
  if len(signals) == 0:
94
101
  return ToolCallDecision(
95
102
  action="allow",
96
103
  source="heuristic",
97
104
  signals=(),
98
105
  summary="Guard did not detect a high-risk signal in this tool call.",
106
+ risk_categories=(),
99
107
  )
100
108
  if config.mode == "prompt":
101
109
  return ToolCallDecision(
@@ -103,37 +111,95 @@ def evaluate_tool_call(
103
111
  source="heuristic",
104
112
  signals=signals,
105
113
  summary=tool_call_risk_summary(artifact, arguments),
114
+ risk_categories=risk_categories,
106
115
  )
107
116
  return ToolCallDecision(
108
117
  action="block",
109
118
  source="heuristic",
110
119
  signals=signals,
111
120
  summary=tool_call_risk_summary(artifact, arguments),
121
+ risk_categories=risk_categories,
112
122
  )
113
123
 
114
124
 
115
125
  def tool_call_risk_signals(artifact: GuardArtifact, arguments: object) -> tuple[str, ...]:
126
+ signals_by_category = {
127
+ "destructive_mutation": "tool name implies destructive file or system changes",
128
+ "command_execution": "tool name implies shell or command execution",
129
+ "outbound_network": "call arguments imply outbound network activity",
130
+ "secret_access": "call arguments mention sensitive local files or secrets",
131
+ "privileged_system_mutation": "call arguments imply privileged system mutation",
132
+ }
133
+ return tuple(signals_by_category[category] for category in tool_call_risk_categories(artifact, arguments))
134
+
135
+
136
+ def tool_call_risk_categories(artifact: GuardArtifact, arguments: object) -> tuple[str, ...]:
137
+ """Return normalized Cloud risk categories for one MCP tool call."""
138
+
139
+ categories = _tool_call_risk_category_set(artifact, arguments)
140
+ order = (
141
+ "command_execution",
142
+ "destructive_mutation",
143
+ "outbound_network",
144
+ "privileged_system_mutation",
145
+ "secret_access",
146
+ )
147
+ return tuple(category for category in order if category in categories)
148
+
149
+
150
+ def _tool_call_risk_category_set(artifact: GuardArtifact, arguments: object) -> set[str]:
116
151
  tool_name = PurePath(artifact.command or artifact.name).name
117
- serialized_arguments = json.dumps(arguments, sort_keys=True).lower() if arguments is not None else ""
118
- combined = f"{artifact.name.lower()} {serialized_arguments}"
152
+ serialized_arguments = _serialized_tool_arguments(arguments)
153
+ combined = _risk_match_text(f"{artifact.name} {serialized_arguments}")
119
154
  tool_name_tokens = set(_tool_name_tokens(tool_name))
120
- signals: list[str] = []
155
+ categories: set[str] = set()
121
156
 
122
157
  if len(tool_name_tokens.intersection({"delete", "remove", "rm", "destroy", "erase"})) > 0:
123
- signals.append("tool name implies destructive file or system changes")
158
+ categories.add("destructive_mutation")
124
159
  if len(tool_name_tokens.intersection({"shell", "bash", "exec", "execute", "command", "powershell"})) > 0:
125
- signals.append("tool name implies shell or command execution")
126
- if any(token in combined for token in ("http://", "https://", "curl", "wget", "fetch", "axios", "requests")):
127
- signals.append("call arguments imply outbound network activity")
128
- if any(
129
- token in combined
130
- for token in (".env", ".ssh", "id_rsa", "credentials", ".npmrc", ".pypirc", "token", "secret", "passwd")
160
+ categories.add("command_execution")
161
+ if _matches_any(
162
+ combined,
163
+ (
164
+ r"https?://",
165
+ _token_pattern("curl", "wget", "fetch", "axios", "requests"),
166
+ ),
167
+ ):
168
+ categories.add("outbound_network")
169
+ if _matches_any(
170
+ combined,
171
+ (
172
+ r"(?<![a-z0-9_-])\.env(?![a-z0-9_-])",
173
+ r"(?<![a-z0-9_-])\.ssh(?![a-z0-9_-])",
174
+ r"(?<![a-z0-9])(id[_-]?rsa|credentials|token|secret|passwd)(?![a-z0-9])",
175
+ r"(?<![a-z0-9_-])\.(npmrc|pypirc)(?![a-z0-9_-])",
176
+ ),
131
177
  ):
132
- signals.append("call arguments mention sensitive local files or secrets")
133
- if any(token in combined for token in ("sudo", "chmod", "chown", "launchctl", "systemctl")):
134
- signals.append("call arguments imply privileged system mutation")
178
+ categories.add("secret_access")
179
+ if _matches_any(
180
+ combined,
181
+ (_token_pattern("sudo", "chmod", "chown", "launchctl", "systemctl"),),
182
+ ):
183
+ categories.add("privileged_system_mutation")
184
+ return categories
185
+
135
186
 
136
- return tuple(_dedupe(signals))
187
+ def _serialized_tool_arguments(arguments: object) -> str:
188
+ if arguments is None:
189
+ return ""
190
+ try:
191
+ return json.dumps(arguments, sort_keys=True, default=str)
192
+ except (TypeError, ValueError):
193
+ return str(arguments)
194
+
195
+
196
+ def _matches_any(value: str, patterns: tuple[str, ...]) -> bool:
197
+ return any(re.search(pattern, value) is not None for pattern in patterns)
198
+
199
+
200
+ def _token_pattern(*tokens: str) -> str:
201
+ alternatives = "|".join(re.escape(token) for token in tokens)
202
+ return rf"(?<![a-z0-9])({alternatives})(?![a-z0-9])"
137
203
 
138
204
 
139
205
  def tool_call_risk_summary(artifact: GuardArtifact, arguments: object) -> str:
@@ -154,6 +220,7 @@ def allow_tool_call(
154
220
  now: str,
155
221
  signals: tuple[str, ...],
156
222
  remember: bool,
223
+ risk_categories: tuple[str, ...] = (),
157
224
  ) -> GuardReceipt:
158
225
  if remember:
159
226
  store.upsert_policy(
@@ -196,6 +263,7 @@ def allow_tool_call(
196
263
  "artifact_id": artifact.artifact_id,
197
264
  "artifact_hash": artifact_hash,
198
265
  "decision_source": decision_source,
266
+ "risk_categories": list(risk_categories),
199
267
  "signals": list(signals),
200
268
  },
201
269
  now,
@@ -211,6 +279,7 @@ def block_tool_call(
211
279
  decision_source: str,
212
280
  now: str,
213
281
  signals: tuple[str, ...],
282
+ risk_categories: tuple[str, ...] = (),
214
283
  ) -> GuardReceipt:
215
284
  store.record_inventory_artifact(
216
285
  artifact=artifact,
@@ -239,6 +308,7 @@ def block_tool_call(
239
308
  "artifact_id": artifact.artifact_id,
240
309
  "artifact_hash": artifact_hash,
241
310
  "decision_source": decision_source,
311
+ "risk_categories": list(risk_categories),
242
312
  "signals": list(signals),
243
313
  },
244
314
  now,
@@ -258,10 +328,18 @@ def _dedupe(values: list[str]) -> list[str]:
258
328
 
259
329
 
260
330
  def _tool_name_tokens(tool_name: str) -> tuple[str, ...]:
261
- camel_normalized = re.sub(r"([a-z0-9])([A-Z])", r"\1 \2", tool_name)
331
+ camel_normalized = _camel_token_normalized(tool_name)
262
332
  return tuple(token for token in re.findall(r"[a-z0-9]+", camel_normalized.lower()) if token)
263
333
 
264
334
 
335
+ def _risk_match_text(value: str) -> str:
336
+ return _camel_token_normalized(value).lower()
337
+
338
+
339
+ def _camel_token_normalized(value: str) -> str:
340
+ return re.sub(r"([a-z0-9])([A-Z])", r"\1 \2", value)
341
+
342
+
265
343
  def _coerce_guard_action(value: str) -> GuardAction | None:
266
344
  for action in GUARD_ACTION_VALUES:
267
345
  if value == action:
@@ -18,6 +18,7 @@ from ..mcp_tool_calls import (
18
18
  build_tool_call_artifact,
19
19
  build_tool_call_hash,
20
20
  evaluate_tool_call,
21
+ tool_call_risk_categories,
21
22
  tool_call_risk_summary,
22
23
  )
23
24
  from ..models import HarnessDetection
@@ -40,6 +41,7 @@ class RuntimeMcpGuardProxy:
40
41
  source_scope: str,
41
42
  config_path: str,
42
43
  transport: str = "stdio",
44
+ server_id: str | None = None,
43
45
  ) -> None:
44
46
  self.harness = harness
45
47
  self.server_name = server_name
@@ -50,6 +52,7 @@ class RuntimeMcpGuardProxy:
50
52
  self.source_scope = source_scope
51
53
  self.config_path = config_path
52
54
  self.transport = transport
55
+ self.server_id = server_id
53
56
  self._inline_prompt_available = False
54
57
  self._inline_prompt_counter = 0
55
58
  self._buffered_child_responses: dict[str, list[dict[str, Any]]] = {}
@@ -185,6 +188,7 @@ class RuntimeMcpGuardProxy:
185
188
  source_scope=self.source_scope,
186
189
  config_path=self.config_path,
187
190
  transport=self.transport,
191
+ server_id=self.server_id,
188
192
  server_fingerprint={
189
193
  "command": self.command,
190
194
  "transport": self.transport,
@@ -209,6 +213,7 @@ class RuntimeMcpGuardProxy:
209
213
  artifact_hash=artifact_hash,
210
214
  decision_source=_decision_source(decision.action, decision.source),
211
215
  signals=decision.signals,
216
+ risk_categories=decision.risk_categories,
212
217
  params=params,
213
218
  )
214
219
  if self._allow_after_native_prompt(decision):
@@ -222,6 +227,7 @@ class RuntimeMcpGuardProxy:
222
227
  artifact_hash=artifact_hash,
223
228
  decision_source="native-approved",
224
229
  signals=decision.signals,
230
+ risk_categories=decision.risk_categories,
225
231
  params=params,
226
232
  )
227
233
  if self._inline_prompt_available and approval_callback is not None:
@@ -237,6 +243,7 @@ class RuntimeMcpGuardProxy:
237
243
  artifact_hash=artifact_hash,
238
244
  decision_source="inline-approved",
239
245
  signals=decision.signals,
246
+ risk_categories=decision.risk_categories,
240
247
  params=params,
241
248
  remember=True,
242
249
  )
@@ -248,6 +255,7 @@ class RuntimeMcpGuardProxy:
248
255
  decision_source="inline-denied",
249
256
  now=_now(),
250
257
  signals=decision.signals,
258
+ risk_categories=decision.risk_categories,
251
259
  )
252
260
  return _blocked_tool_response(
253
261
  message.get("id"),
@@ -289,6 +297,7 @@ class RuntimeMcpGuardProxy:
289
297
  artifact_hash: str,
290
298
  decision_source: str,
291
299
  signals: tuple[str, ...],
300
+ risk_categories: tuple[str, ...],
292
301
  params: dict[str, Any],
293
302
  remember: bool = False,
294
303
  ) -> tuple[dict[str, Any], dict[str, Any]]:
@@ -299,6 +308,7 @@ class RuntimeMcpGuardProxy:
299
308
  decision_source=decision_source,
300
309
  now=_now(),
301
310
  signals=signals,
311
+ risk_categories=risk_categories,
302
312
  remember=remember,
303
313
  )
304
314
  response = self._forward_message(
@@ -537,6 +547,7 @@ class RuntimeMcpGuardProxy:
537
547
  decision_source="approval-center-pending",
538
548
  now=_now(),
539
549
  signals=signals,
550
+ risk_categories=tool_call_risk_categories(artifact, params.get("arguments")),
540
551
  )
541
552
  request_id = str(queued[0]["request_id"]) if queued else "unknown"
542
553
  return _blocked_tool_response(
@@ -1,3 +1,3 @@
1
1
  """Single source of truth for tool version."""
2
2
 
3
- __version__ = "2.0.106"
3
+ __version__ = "2.0.107"
@@ -0,0 +1,15 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import sys
5
+ from pathlib import Path
6
+
7
+ SRC_PATH = Path(__file__).resolve().parents[1] / "src"
8
+
9
+ if str(SRC_PATH) not in sys.path:
10
+ sys.path.insert(0, str(SRC_PATH))
11
+
12
+ existing_pythonpath = os.environ.get("PYTHONPATH", "")
13
+ pythonpath_entries = [entry for entry in existing_pythonpath.split(os.pathsep) if entry]
14
+ if str(SRC_PATH) not in pythonpath_entries:
15
+ os.environ["PYTHONPATH"] = os.pathsep.join([str(SRC_PATH), *pythonpath_entries])