plugin-scanner 2.0.129__tar.gz → 2.0.131__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 (421) hide show
  1. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/PKG-INFO +47 -1
  2. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/README.md +46 -0
  3. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/docs/guard/testing-matrix.md +26 -0
  4. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/pyproject.toml +1 -1
  5. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/pyproject.toml.bak +1 -1
  6. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/cli/commands.py +54 -0
  7. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/cli/render.py +16 -0
  8. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/daemon/client.py +13 -3
  9. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/detectors.py +5 -0
  10. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/runner.py +7 -1
  11. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/version.py +1 -1
  12. plugin_scanner-2.0.131/tests/fixtures/guard-red-team/README.md +74 -0
  13. plugin_scanner-2.0.131/tests/fixtures/guard-red-team/benign-docs-fake-token.py +28 -0
  14. plugin_scanner-2.0.131/tests/fixtures/guard-red-team/benign-health-endpoint.py +26 -0
  15. plugin_scanner-2.0.131/tests/fixtures/guard-red-team/benign-nvmrc-fake-creds.py +29 -0
  16. plugin_scanner-2.0.131/tests/fixtures/guard-red-team/benign-source-search.py +34 -0
  17. plugin_scanner-2.0.131/tests/fixtures/guard-red-team/expected-decisions.json +119 -0
  18. plugin_scanner-2.0.131/tests/fixtures/guard-red-team/malicious-dockerfile.txt +37 -0
  19. plugin_scanner-2.0.131/tests/fixtures/guard-red-team/malicious-encoded-shell-exfil.py +36 -0
  20. plugin_scanner-2.0.131/tests/fixtures/guard-red-team/malicious-github-action.yml +46 -0
  21. plugin_scanner-2.0.131/tests/fixtures/guard-red-team/malicious-mcp-delete.md +33 -0
  22. plugin_scanner-2.0.131/tests/fixtures/guard-red-team/malicious-mcp-secret-read.md +33 -0
  23. plugin_scanner-2.0.131/tests/fixtures/guard-red-team/malicious-mcp-skill-exfil.md +39 -0
  24. plugin_scanner-2.0.131/tests/fixtures/guard-red-team/malicious-npm-postinstall.js +36 -0
  25. plugin_scanner-2.0.131/tests/fixtures/guard-red-team/malicious-prompt-env-read.md +28 -0
  26. plugin_scanner-2.0.131/tests/fixtures/guard-red-team/malicious-prompt-guard-bypass.md +30 -0
  27. plugin_scanner-2.0.131/tests/fixtures/guard-red-team/malicious-prompt-npmrc-read.md +25 -0
  28. plugin_scanner-2.0.131/tests/fixtures/guard-red-team/malicious-python-setup.py +46 -0
  29. plugin_scanner-2.0.131/tests/test_guard_daemon_perf.py +178 -0
  30. plugin_scanner-2.0.131/tests/test_guard_red_team.py +184 -0
  31. plugin_scanner-2.0.129/tests/fixtures/guard-red-team/README.md +0 -27
  32. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.clusterfuzzlite/Dockerfile +0 -0
  33. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.clusterfuzzlite/build.sh +0 -0
  34. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.clusterfuzzlite/project.yaml +0 -0
  35. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.clusterfuzzlite/requirements-atheris.txt +0 -0
  36. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.dockerignore +0 -0
  37. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.github/CODEOWNERS +0 -0
  38. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  39. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  40. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  41. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.github/dependabot.yml +0 -0
  42. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.github/workflows/ci.yml +0 -0
  43. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.github/workflows/codeql.yml +0 -0
  44. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.github/workflows/dependabot-uv-lock.yml +0 -0
  45. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.github/workflows/fuzz.yml +0 -0
  46. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.github/workflows/harness-smoke.yml +0 -0
  47. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.github/workflows/publish.yml +0 -0
  48. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.github/workflows/scorecard.yml +0 -0
  49. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.gitignore +0 -0
  50. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/.pre-commit-hooks.yaml +0 -0
  51. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/CONTRIBUTING.md +0 -0
  52. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/Dockerfile +0 -0
  53. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/LICENSE +0 -0
  54. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/SECURITY.md +0 -0
  55. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/index.html +0 -0
  56. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/package.json +0 -0
  57. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/pnpm-lock.yaml +0 -0
  58. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/public/apple-touch-icon.png +0 -0
  59. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
  60. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/public/brand/Logo_Whole.png +0 -0
  61. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/public/favicon-16x16.png +0 -0
  62. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/public/favicon-32x32.png +0 -0
  63. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/public/favicon.ico +0 -0
  64. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/app.tsx +0 -0
  65. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/approval-center-layout.test.ts +0 -0
  66. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/approval-center-layout.tsx +0 -0
  67. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/approval-center-primitives.tsx +0 -0
  68. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/approval-center-review-cards.tsx +0 -0
  69. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/approval-center-utils.ts +0 -0
  70. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/data-flow-evidence-card.tsx +0 -0
  71. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/fleet-workspace.tsx +0 -0
  72. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/guard-api.test.ts +0 -0
  73. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/guard-api.ts +0 -0
  74. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/guard-demo.ts +0 -0
  75. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/guard-types.ts +0 -0
  76. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/main.tsx +0 -0
  77. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/receipts-workspace.test.ts +0 -0
  78. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/receipts-workspace.tsx +0 -0
  79. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/runtime-overview.test.ts +0 -0
  80. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/runtime-overview.tsx +0 -0
  81. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/settings-workspace.test.ts +0 -0
  82. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/settings-workspace.tsx +0 -0
  83. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/styles.css +0 -0
  84. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/src/vite-env.d.ts +0 -0
  85. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/tsconfig.json +0 -0
  86. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/dashboard/vite.config.ts +0 -0
  87. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/docker-requirements.txt +0 -0
  88. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/docs/guard/approval-audit.md +0 -0
  89. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/docs/guard/architecture.md +0 -0
  90. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/docs/guard/get-started.md +0 -0
  91. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/docs/guard/harness-support.md +0 -0
  92. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/docs/guard/local-vs-cloud.md +0 -0
  93. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/docs/guard/release-checklist.md +0 -0
  94. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/docs/guard/smoke-tests.md +0 -0
  95. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/docs/trust/mcp-trust-draft.md +0 -0
  96. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/docs/trust/plugin-trust-draft.md +0 -0
  97. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/docs/trust/skill-trust-local.md +0 -0
  98. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/fuzzers/manifest_fuzzer.py +0 -0
  99. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/requirements.txt +0 -0
  100. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/schemas/plugin-quality.v1.json +0 -0
  101. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/schemas/scan-result.v1.json +0 -0
  102. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/schemas/verify-result.v1.json +0 -0
  103. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/__init__.py +0 -0
  104. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/action_runner.py +0 -0
  105. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/argparse_utils.py +0 -0
  106. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/checks/__init__.py +0 -0
  107. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
  108. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/checks/claude.py +0 -0
  109. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
  110. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
  111. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/checks/gemini.py +0 -0
  112. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/checks/manifest.py +0 -0
  113. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
  114. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
  115. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
  116. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/checks/opencode.py +0 -0
  117. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
  118. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/checks/security.py +0 -0
  119. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
  120. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/cli.py +0 -0
  121. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/cli_ui.py +0 -0
  122. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/config.py +0 -0
  123. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
  124. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
  125. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
  126. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
  127. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
  128. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
  129. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
  130. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
  131. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
  132. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/github_reporting.py +0 -0
  133. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/__init__.py +0 -0
  134. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/access_graph_events.py +0 -0
  135. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
  136. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
  137. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
  138. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
  139. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +0 -0
  140. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
  141. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/adapters/contracts.py +0 -0
  142. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
  143. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
  144. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
  145. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
  146. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
  147. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
  148. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
  149. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
  150. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
  151. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
  152. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
  153. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/approvals.py +0 -0
  154. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
  155. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
  156. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
  157. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
  158. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
  159. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
  160. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
  161. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
  162. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
  163. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
  164. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
  165. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/config.py +0 -0
  166. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
  167. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
  168. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
  169. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
  170. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
  171. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
  172. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
  173. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
  174. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
  175. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
  176. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
  177. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
  178. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
  179. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
  180. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
  181. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/incident.py +0 -0
  182. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/launcher.py +0 -0
  183. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
  184. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/models.py +0 -0
  185. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
  186. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
  187. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/protect.py +0 -0
  188. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
  189. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
  190. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
  191. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
  192. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
  193. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
  194. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/redaction.py +0 -0
  195. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/risk.py +0 -0
  196. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
  197. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
  198. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/advisory_escalation.py +0 -0
  199. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/advisory_matchers.py +0 -0
  200. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/data_flow.py +0 -0
  201. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/data_flow_rules.py +0 -0
  202. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/data_flow_variables.py +0 -0
  203. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
  204. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/mcp_protection.py +0 -0
  205. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/prompt_injection.py +0 -0
  206. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/safe_decode.py +0 -0
  207. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/sandbox.py +0 -0
  208. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
  209. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/secret_sensitivity.py +0 -0
  210. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/secret_sources.py +0 -0
  211. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/shell_commands.py +0 -0
  212. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
  213. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/skill_protection.py +0 -0
  214. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/supply_chain.py +0 -0
  215. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
  216. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/temp_files.py +0 -0
  217. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/runtime/threat_intel.py +0 -0
  218. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
  219. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
  220. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
  221. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
  222. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/shims.py +0 -0
  223. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/store.py +0 -0
  224. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
  225. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
  226. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/store_evidence.py +0 -0
  227. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/store_threat_intel.py +0 -0
  228. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/guard/types.py +0 -0
  229. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
  230. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
  231. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
  232. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/lint_fixes.py +0 -0
  233. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/marketplace_support.py +0 -0
  234. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/models.py +0 -0
  235. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/path_support.py +0 -0
  236. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/policy.py +0 -0
  237. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/quality_artifact.py +0 -0
  238. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/repo_detect.py +0 -0
  239. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/reporting.py +0 -0
  240. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/rules/__init__.py +0 -0
  241. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/rules/registry.py +0 -0
  242. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/rules/specs.py +0 -0
  243. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/scanner.py +0 -0
  244. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/submission.py +0 -0
  245. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/suppressions.py +0 -0
  246. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
  247. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/trust_helpers.py +0 -0
  248. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
  249. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/trust_models.py +0 -0
  250. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
  251. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/trust_scoring.py +0 -0
  252. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
  253. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/trust_specs.py +0 -0
  254. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/src/codex_plugin_scanner/verification.py +0 -0
  255. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/__init__.py +0 -0
  256. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/conftest.py +0 -0
  257. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/__init__.py +0 -0
  258. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
  259. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/bad-plugin/.mcp.json +0 -0
  260. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/bad-plugin/secrets.js +0 -0
  261. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
  262. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
  263. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/claude-plugin-good/README.md +0 -0
  264. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
  265. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
  266. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
  267. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/code-quality-bad/evil.js +0 -0
  268. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/code-quality-bad/inject.js +0 -0
  269. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
  270. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
  271. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/gemini-extension-good/README.md +0 -0
  272. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
  273. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
  274. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
  275. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
  276. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/good-plugin/.codexignore +0 -0
  277. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/good-plugin/LICENSE +0 -0
  278. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/good-plugin/README.md +0 -0
  279. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/good-plugin/SECURITY.md +0 -0
  280. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
  281. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
  282. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
  283. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
  284. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
  285. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/guard-red-team/canary-exfil-encoded.py +0 -0
  286. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/guard-red-team/canary-exfil.py +0 -0
  287. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/guard-red-team/smoke-evidence-template.json +0 -0
  288. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
  289. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
  290. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
  291. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
  292. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
  293. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
  294. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
  295. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
  296. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
  297. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
  298. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
  299. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
  300. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
  301. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
  302. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/mcp-canary-server.py +0 -0
  303. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
  304. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
  305. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/mit-license/LICENSE +0 -0
  306. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
  307. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
  308. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
  309. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
  310. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
  311. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
  312. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
  313. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
  314. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
  315. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
  316. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
  317. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
  318. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
  319. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
  320. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
  321. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
  322. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
  323. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
  324. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/opencode-good/LICENSE +0 -0
  325. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/opencode-good/README.md +0 -0
  326. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/opencode-good/SECURITY.md +0 -0
  327. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
  328. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
  329. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
  330. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
  331. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/supply-chain/benign-npm-package.json +0 -0
  332. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/supply-chain/benign-pnpm-package.json +0 -0
  333. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/supply-chain/benign-pyproject.toml +0 -0
  334. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/supply-chain/malicious-Dockerfile +0 -0
  335. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/supply-chain/malicious-action.yml +0 -0
  336. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/supply-chain/malicious-npm-package.json +0 -0
  337. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/supply-chain/malicious-setup.py +0 -0
  338. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
  339. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
  340. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/fixtures/with-marketplace/marketplace.json +0 -0
  341. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test-trust-scoring.py +0 -0
  342. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test-trust-specs.py +0 -0
  343. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_action_runner.py +0 -0
  344. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_best_practices.py +0 -0
  345. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_cisco_install_surfaces.py +0 -0
  346. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_cli.py +0 -0
  347. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_code_quality.py +0 -0
  348. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_config.py +0 -0
  349. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_coverage_remaining.py +0 -0
  350. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_ecosystems.py +0 -0
  351. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_edge_cases.py +0 -0
  352. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_final_coverage.py +0 -0
  353. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_access_graph.py +0 -0
  354. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_advisory_escalation.py +0 -0
  355. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_approval_store_scale.py +0 -0
  356. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_approvals.py +0 -0
  357. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_bootstrap.py +0 -0
  358. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_canary_fixtures.py +0 -0
  359. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_capabilities.py +0 -0
  360. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_claude_adapter.py +0 -0
  361. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_cli.py +0 -0
  362. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_cloud_local_sync.py +0 -0
  363. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_codex_e2e.py +0 -0
  364. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_codex_install.py +0 -0
  365. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_codex_proxy.py +0 -0
  366. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_config_paths.py +0 -0
  367. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_connect_flow.py +0 -0
  368. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_consumer_mode.py +0 -0
  369. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_copilot_adapter.py +0 -0
  370. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_copilot_proxy.py +0 -0
  371. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_daemon_manager.py +0 -0
  372. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_data_flow.py +0 -0
  373. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_event_schema_v1.py +0 -0
  374. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_events.py +0 -0
  375. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_evidence_store.py +0 -0
  376. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_harness_contracts.py +0 -0
  377. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_launch_env.py +0 -0
  378. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_mcp_protection.py +0 -0
  379. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_opencode_proxy.py +0 -0
  380. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_product_flow.py +0 -0
  381. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_prompt_injection.py +0 -0
  382. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_protect.py +0 -0
  383. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_render.py +0 -0
  384. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_risk.py +0 -0
  385. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_runtime.py +0 -0
  386. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_runtime_action_harnesses.py +0 -0
  387. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_runtime_actions.py +0 -0
  388. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_runtime_decisions.py +0 -0
  389. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_runtime_detectors.py +0 -0
  390. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_runtime_signals.py +0 -0
  391. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_safe_decode.py +0 -0
  392. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_sandbox.py +0 -0
  393. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_skill_protection.py +0 -0
  394. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_store_migrations.py +0 -0
  395. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_supply_chain.py +0 -0
  396. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_surface_server.py +0 -0
  397. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_threat_intel.py +0 -0
  398. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_guard_verdicts.py +0 -0
  399. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_hermes_adapter.py +0 -0
  400. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_integration.py +0 -0
  401. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_lint_fixes.py +0 -0
  402. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_live_cisco_smoke.py +0 -0
  403. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_manifest.py +0 -0
  404. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_marketplace.py +0 -0
  405. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_mcp_security.py +0 -0
  406. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_openclaw_adapter.py +0 -0
  407. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_operational_security.py +0 -0
  408. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_policy.py +0 -0
  409. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_quality_artifact.py +0 -0
  410. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_rule_registry.py +0 -0
  411. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_scanner.py +0 -0
  412. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_schema_contracts.py +0 -0
  413. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_security.py +0 -0
  414. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_security_ops.py +0 -0
  415. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_skill_security.py +0 -0
  416. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_submission.py +0 -0
  417. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_trust_scoring.py +0 -0
  418. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_trust_specs.py +0 -0
  419. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_verification.py +0 -0
  420. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/tests/test_versioning.py +0 -0
  421. {plugin_scanner-2.0.129 → plugin_scanner-2.0.131}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 2.0.129
3
+ Version: 2.0.131
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
@@ -132,6 +132,52 @@ See [docs/guard/get-started.md](docs/guard/get-started.md) for the full local fl
132
132
 
133
133
  </details>
134
134
 
135
+ ## Guard: Protection Levels
136
+
137
+ HOL Guard is antivirus for AI harnesses. It intercepts every tool action before your files change or your network is contacted, then decides in milliseconds whether to allow or block.
138
+
139
+ Choose a protection level with `hol-guard settings set security-level <level>`:
140
+
141
+ | Level | Who it's for | What it blocks |
142
+ | :--- | :--- | :--- |
143
+ | **Gentle** | Teams who want minimal friction; experienced users | High-confidence secrets and clear exfil only |
144
+ | **Balanced** | Most users (default) | Secrets, shell exfil, prompt injections, supply-chain hooks |
145
+ | **Strict** | Security-conscious teams | Everything above plus low-confidence signals and untrusted prompts |
146
+ | **Paranoid** | High-security environments | All the above plus any unrecognized MCP server action |
147
+
148
+ If you are unsure, start with **Balanced**. You can promote to **Strict** after reviewing your first week of receipts.
149
+
150
+ ## Guard: Troubleshooting
151
+
152
+ ### Why was my command paused?
153
+
154
+ Guard paused a command because one or more detectors fired. To see exactly what triggered:
155
+
156
+ ```bash
157
+ hol-guard receipts # review recent decisions
158
+ hol-guard doctor # run a probe and see which detectors are active
159
+ hol-guard doctor --perf # include per-detector timing
160
+ ```
161
+
162
+ If the block looks like a false positive, you can approve it from the receipts view or from the dashboard at `http://localhost:6174`.
163
+
164
+ ### How do I clear approvals?
165
+
166
+ From the terminal:
167
+
168
+ ```bash
169
+ hol-guard approvals # list pending approvals
170
+ hol-guard approvals clear # clear all pending approvals (prompts for confirmation)
171
+ ```
172
+
173
+ From the dashboard: open `http://localhost:6174`, go to the **Approval Center**, and use the **Clear all** button. You will be asked to confirm before any approvals are removed.
174
+
175
+ ## Guard: Advisory Sync Privacy
176
+
177
+ Guard's advisory database updates are optional and pull-only. When you run `hol-guard advisories sync`, Guard fetches a signed advisory list from `advisories.hol.org`. No local file paths, harness configs, receipt data, or workspace identifiers are sent to any server during sync.
178
+
179
+ Advisory sync requires a HOL Guard Cloud account. If you have not signed in, sync is skipped and Guard continues using the locally bundled advisory database. Run `hol-guard login` to connect a free account.
180
+
135
181
  ## Scanner Quickstart
136
182
 
137
183
  ```bash
@@ -92,6 +92,52 @@ See [docs/guard/get-started.md](docs/guard/get-started.md) for the full local fl
92
92
 
93
93
  </details>
94
94
 
95
+ ## Guard: Protection Levels
96
+
97
+ HOL Guard is antivirus for AI harnesses. It intercepts every tool action before your files change or your network is contacted, then decides in milliseconds whether to allow or block.
98
+
99
+ Choose a protection level with `hol-guard settings set security-level <level>`:
100
+
101
+ | Level | Who it's for | What it blocks |
102
+ | :--- | :--- | :--- |
103
+ | **Gentle** | Teams who want minimal friction; experienced users | High-confidence secrets and clear exfil only |
104
+ | **Balanced** | Most users (default) | Secrets, shell exfil, prompt injections, supply-chain hooks |
105
+ | **Strict** | Security-conscious teams | Everything above plus low-confidence signals and untrusted prompts |
106
+ | **Paranoid** | High-security environments | All the above plus any unrecognized MCP server action |
107
+
108
+ If you are unsure, start with **Balanced**. You can promote to **Strict** after reviewing your first week of receipts.
109
+
110
+ ## Guard: Troubleshooting
111
+
112
+ ### Why was my command paused?
113
+
114
+ Guard paused a command because one or more detectors fired. To see exactly what triggered:
115
+
116
+ ```bash
117
+ hol-guard receipts # review recent decisions
118
+ hol-guard doctor # run a probe and see which detectors are active
119
+ hol-guard doctor --perf # include per-detector timing
120
+ ```
121
+
122
+ If the block looks like a false positive, you can approve it from the receipts view or from the dashboard at `http://localhost:6174`.
123
+
124
+ ### How do I clear approvals?
125
+
126
+ From the terminal:
127
+
128
+ ```bash
129
+ hol-guard approvals # list pending approvals
130
+ hol-guard approvals clear # clear all pending approvals (prompts for confirmation)
131
+ ```
132
+
133
+ From the dashboard: open `http://localhost:6174`, go to the **Approval Center**, and use the **Clear all** button. You will be asked to confirm before any approvals are removed.
134
+
135
+ ## Guard: Advisory Sync Privacy
136
+
137
+ Guard's advisory database updates are optional and pull-only. When you run `hol-guard advisories sync`, Guard fetches a signed advisory list from `advisories.hol.org`. No local file paths, harness configs, receipt data, or workspace identifiers are sent to any server during sync.
138
+
139
+ Advisory sync requires a HOL Guard Cloud account. If you have not signed in, sync is skipped and Guard continues using the locally bundled advisory database. Run `hol-guard login` to connect a free account.
140
+
95
141
  ## Scanner Quickstart
96
142
 
97
143
  ```bash
@@ -81,3 +81,29 @@ Nightly release-bar coverage should include:
81
81
  - Claude Code or Cursor on a self-hosted macOS runner
82
82
  - Gemini or OpenCode on a self-hosted Windows runner
83
83
  - a release gate that only passes when those harness families stay green
84
+
85
+ ## Red-Team Fixture Suite (T646)
86
+
87
+ Run the red-team corpus to validate fixture safety and manifest integrity:
88
+
89
+ ```bash
90
+ pytest tests/test_guard_red_team.py tests/test_guard_canary_fixtures.py -q
91
+ ```
92
+
93
+ This verifies:
94
+ - All malicious fixtures use only `hol-fake-*` sentinel values and route to the canary domain
95
+ - All benign fixtures contain no exfil patterns or real key prefixes
96
+ - Every fixture listed in `expected-decisions.json` exists on disk
97
+ - No local usernames, real paths, or real tokens appear in any fixture
98
+
99
+ To run only the red-team manifest and safety tests:
100
+
101
+ ```bash
102
+ pytest tests/test_guard_red_team.py -q
103
+ ```
104
+
105
+ To run the full test suite including red-team:
106
+
107
+ ```bash
108
+ pytest -q
109
+ ```
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "plugin-scanner"
7
- version = "2.0.129"
7
+ version = "2.0.131"
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.129"
7
+ version = "2.0.131"
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"
@@ -503,6 +503,7 @@ def _configure_guard_parser(guard_parser: argparse.ArgumentParser) -> None:
503
503
  action="store_true",
504
504
  help="List all supported harnesses with their protection contract",
505
505
  )
506
+ doctor_parser.add_argument("--perf", action="store_true", help="Include detector performance timings")
506
507
 
507
508
  login_parser = guard_subparsers.add_parser(
508
509
  "login",
@@ -1208,6 +1209,8 @@ def run_guard_command(
1208
1209
  "adapters": [detection.to_dict() for detection in detect_all(context)],
1209
1210
  "runtime_detector_registry": _runtime_detector_registry_payload(config),
1210
1211
  }
1212
+ if getattr(args, "perf", False):
1213
+ payload["detector_perf"] = _runtime_detector_perf_payload(config)
1211
1214
  _emit("doctor", payload, getattr(args, "json", False))
1212
1215
  return 0
1213
1216
 
@@ -3382,6 +3385,57 @@ def _runtime_detector_registry_payload(config: GuardConfig) -> dict[str, object]
3382
3385
  }
3383
3386
 
3384
3387
 
3388
+ def _runtime_detector_perf_payload(config: GuardConfig) -> list[dict[str, object]]:
3389
+ from ..runtime.actions import GuardActionEnvelope
3390
+ from ..runtime.detectors import (
3391
+ _SLOW_DETECTOR_THRESHOLD_MS,
3392
+ DetectorContext,
3393
+ )
3394
+ from ..runtime.runner import _get_default_detector_registry
3395
+
3396
+ probe_action = GuardActionEnvelope(
3397
+ schema_version=1,
3398
+ action_id="perf-probe",
3399
+ harness="doctor",
3400
+ event_name="HarnessStart",
3401
+ action_type="harness_start",
3402
+ workspace=None,
3403
+ workspace_hash=None,
3404
+ tool_name=None,
3405
+ command=None,
3406
+ prompt_excerpt=None,
3407
+ prompt_text=None,
3408
+ target_paths=(),
3409
+ network_hosts=(),
3410
+ mcp_server=None,
3411
+ mcp_tool=None,
3412
+ package_manager=None,
3413
+ package_name=None,
3414
+ script_name=None,
3415
+ raw_payload_redacted={},
3416
+ )
3417
+ probe_context = DetectorContext(
3418
+ config=config,
3419
+ workspace=None,
3420
+ prior_decisions={},
3421
+ threat_intel={},
3422
+ redaction_settings={},
3423
+ )
3424
+ result = _get_default_detector_registry().run(
3425
+ probe_action,
3426
+ probe_context,
3427
+ timeout_ms=config.runtime_detector_timeout_ms,
3428
+ disabled_detector_ids=config.runtime_detector_disabled_ids,
3429
+ )
3430
+ return [
3431
+ {
3432
+ **t.to_dict(),
3433
+ "slow": t.elapsed_ms >= _SLOW_DETECTOR_THRESHOLD_MS,
3434
+ }
3435
+ for t in result.telemetry
3436
+ ]
3437
+
3438
+
3385
3439
  def _update_guard_cli_settings(*, args: argparse.Namespace, config: GuardConfig, guard_home: Path) -> GuardConfig:
3386
3440
  settings_command = getattr(args, "settings_set_command", None)
3387
3441
  if settings_command == "security-level":
@@ -337,6 +337,22 @@ def _render_doctor(console: Console, payload: dict[str, object]) -> None:
337
337
  artifacts = _coerce_dict_list(payload.get("artifacts"))
338
338
  if artifacts:
339
339
  console.print(_build_artifact_table(artifacts))
340
+ perf_items = payload.get("detector_perf")
341
+ if isinstance(perf_items, list) and perf_items:
342
+ perf_table = Table(title="Detector performance", box=box.SIMPLE_HEAVY, show_header=True)
343
+ perf_table.add_column("Detector", style="bold")
344
+ perf_table.add_column("Status")
345
+ perf_table.add_column("ms", justify="right")
346
+ perf_table.add_column("Slow?")
347
+ for item in perf_items:
348
+ slow = bool(item.get("slow"))
349
+ perf_table.add_row(
350
+ str(item.get("detector_id", "")),
351
+ str(item.get("status", "")),
352
+ str(item.get("elapsed_ms", 0)),
353
+ "[red]yes[/red]" if slow else "no",
354
+ )
355
+ console.print(perf_table)
340
356
  console.print(_build_diagnostic_command_panel())
341
357
 
342
358
 
@@ -24,6 +24,10 @@ class GuardDaemonTransportError(GuardDaemonRequestError):
24
24
  """Raised when the Guard daemon request fails due to transport issues."""
25
25
 
26
26
 
27
+ _DEFAULT_REQUEST_TIMEOUT_S: float = 5.0
28
+ _STATUS_REQUEST_TIMEOUT_S: float = 0.25
29
+
30
+
27
31
  class GuardSurfaceDaemonClient:
28
32
  """Small authenticated client for the local Guard daemon."""
29
33
 
@@ -156,7 +160,7 @@ class GuardSurfaceDaemonClient:
156
160
  method="GET",
157
161
  )
158
162
  try:
159
- with urllib.request.urlopen(request, timeout=5) as response:
163
+ with urllib.request.urlopen(request, timeout=_STATUS_REQUEST_TIMEOUT_S) as response:
160
164
  payload = self._decode_json_response(response.read().decode("utf-8"))
161
165
  except urllib.error.HTTPError as error:
162
166
  try:
@@ -196,7 +200,13 @@ class GuardSurfaceDaemonClient:
196
200
  return state
197
201
  return response
198
202
 
199
- def _post(self, path: str, payload: dict[str, object]) -> dict[str, object]:
203
+ def _post(
204
+ self,
205
+ path: str,
206
+ payload: dict[str, object],
207
+ *,
208
+ timeout: float = _DEFAULT_REQUEST_TIMEOUT_S,
209
+ ) -> dict[str, object]:
200
210
  request = urllib.request.Request(
201
211
  f"{self.daemon_url}{path}",
202
212
  data=json.dumps(payload).encode("utf-8"),
@@ -207,7 +217,7 @@ class GuardSurfaceDaemonClient:
207
217
  method="POST",
208
218
  )
209
219
  try:
210
- with urllib.request.urlopen(request, timeout=5) as response:
220
+ with urllib.request.urlopen(request, timeout=timeout) as response:
211
221
  return self._decode_json_response(response.read().decode("utf-8"))
212
222
  except urllib.error.HTTPError as error:
213
223
  try:
@@ -41,6 +41,7 @@ DETECTOR_CATEGORY_TAGS: tuple[RiskSignalCategory, ...] = (
41
41
  "execution",
42
42
  )
43
43
  DetectorRunStatus = Literal["ok", "disabled", "filtered", "timeout", "error"]
44
+ _SLOW_DETECTOR_THRESHOLD_MS: int = 100
44
45
 
45
46
 
46
47
  @dataclass(frozen=True, slots=True)
@@ -91,6 +92,10 @@ class DetectorRunResult:
91
92
  signals: tuple[RiskSignalV2, ...]
92
93
  telemetry: tuple[DetectorTelemetry, ...]
93
94
 
95
+ def slow_detectors(self, threshold_ms: int = _SLOW_DETECTOR_THRESHOLD_MS) -> tuple[DetectorTelemetry, ...]:
96
+ """Return telemetry entries that exceeded *threshold_ms*."""
97
+ return tuple(t for t in self.telemetry if t.elapsed_ms >= threshold_ms)
98
+
94
99
 
95
100
  class DetectorRegistry:
96
101
  """Runs detectors in deterministic order with failure isolation."""
@@ -38,6 +38,12 @@ _APPROVAL_METADATA_KEYS = (
38
38
  "approval_wait",
39
39
  "review_hint",
40
40
  )
41
+
42
+
43
+ def _get_default_detector_registry() -> DetectorRegistry:
44
+ return DetectorRegistry(register_default_detectors())
45
+
46
+
41
47
  _PAIN_SIGNAL_EVENTS = frozenset(
42
48
  {
43
49
  "changed_artifact_caught",
@@ -364,7 +370,7 @@ def _evaluation_with_detector_registry(
364
370
  threat_intel={},
365
371
  redaction_settings={},
366
372
  )
367
- result = DetectorRegistry(register_default_detectors()).run(
373
+ result = _get_default_detector_registry().run(
368
374
  action_envelope,
369
375
  detector_context,
370
376
  timeout_ms=config.runtime_detector_timeout_ms,
@@ -1,3 +1,3 @@
1
1
  """Single source of truth for tool version."""
2
2
 
3
- __version__ = "2.0.129"
3
+ __version__ = "2.0.131"
@@ -0,0 +1,74 @@
1
+ # Guard Red-Team Fixtures
2
+
3
+ Fixtures in this directory contain intentionally suspicious-looking content used to test
4
+ that HOL Guard correctly detects and blocks malicious AI agent behaviors.
5
+
6
+ **All credentials, tokens, API keys, and webhook URLs in these fixtures are fake.**
7
+ They use the pattern `hol-fake-*` and route to `https://evil.hol.org/collect`,
8
+ a domain owned by Hashgraph Online solely for testing canary detection.
9
+
10
+ No real secrets or infrastructure are touched by these tests.
11
+
12
+ ## Files
13
+
14
+ ### Canary Fixtures
15
+
16
+ | File | Fixture ID | Purpose |
17
+ |------|-----------|---------|
18
+ | `canary-exfil.py` | T604 | Plain-text canary: reads a fake API key and posts it to the canary endpoint |
19
+ | `canary-exfil-encoded.py` | T605 | Encoded canary: base64-encoded exfil payload to test encoded-execution detection |
20
+
21
+ ### Malicious Prompt Fixtures
22
+
23
+ | File | Fixture ID | Purpose |
24
+ |------|-----------|---------|
25
+ | `malicious-prompt-env-read.md` | T629 | Prompt injection instructing harness to exfiltrate `.env` file contents |
26
+ | `malicious-prompt-npmrc-read.md` | T630 | Prompt injection instructing harness to read npm auth tokens |
27
+ | `malicious-prompt-guard-bypass.md` | T631 | Prompt injection attempting to disable HOL Guard monitoring |
28
+
29
+ ### Malicious MCP Fixtures
30
+
31
+ | File | Fixture ID | Purpose |
32
+ |------|-----------|---------|
33
+ | `malicious-mcp-delete.md` | T632 | MCP tool call attempting destructive file system deletion |
34
+ | `malicious-mcp-secret-read.md` | T633 | MCP tool call reading credential files then posting to external endpoint |
35
+ | `malicious-mcp-skill-exfil.md` | T634 | MCP skill that exfiltrates workspace data with fake bearer token |
36
+
37
+ ### Malicious Package/Infra Fixtures
38
+
39
+ | File | Fixture ID | Purpose |
40
+ |------|-----------|---------|
41
+ | `malicious-npm-postinstall.js` | T635 | npm postinstall hook harvesting local credential files |
42
+ | `malicious-python-setup.py` | T636 | Python setup.py exfiltrating credential files on install |
43
+ | `malicious-dockerfile.txt` | T637 | Dockerfile that exfiltrates secrets during image build |
44
+ | `malicious-github-action.yml` | T638 | GitHub Actions workflow exfiltrating CI secrets |
45
+ | `malicious-encoded-shell-exfil.py` | T639 | Base64-encoded exfil payload to test obfuscation detection |
46
+
47
+ ### Benign Fixtures
48
+
49
+ | File | Fixture ID | Purpose |
50
+ |------|-----------|---------|
51
+ | `benign-source-search.py` | T640 | Legitimate source code search — should not trigger any detectors |
52
+ | `benign-health-endpoint.py` | T641 | Legitimate loopback health check — should not trigger any detectors |
53
+ | `benign-docs-fake-token.py` | T642 | Documentation with explanatory fake tokens — should not be blocked |
54
+ | `benign-nvmrc-fake-creds.py` | T643 | .nvmrc read with version string that looks like a credential |
55
+
56
+ ### Manifests
57
+
58
+ | File | Purpose |
59
+ |------|---------|
60
+ | `expected-decisions.json` | Expected Guard decision for every fixture (used by red-team test runner) |
61
+ | `smoke-evidence-template.json` | Template for recording smoke test evidence during manual harness verification |
62
+
63
+ ## Running Red-Team Tests
64
+
65
+ ```bash
66
+ pytest tests/test_guard_red_team.py tests/test_guard_canary_fixtures.py -q
67
+ ```
68
+
69
+ The red-team test runner (`tests/test_guard_red_team.py`) validates:
70
+ - All malicious fixtures contain only fake key material (no real secrets)
71
+ - All benign fixtures contain no network exfil patterns
72
+ - Fixture structure matches the expected-decisions manifest
73
+ - No local usernames, real paths, or real tokens appear in any fixture
74
+
@@ -0,0 +1,28 @@
1
+ """Benign docs with fake token fixture (T642).
2
+
3
+ This fixture is documentation that happens to contain fake token strings
4
+ that look like real tokens. Guard should NOT block documentation reads
5
+ that only mention tokens in explanatory context.
6
+
7
+ The tokens below are clearly fake and used only for illustrative purposes.
8
+ """
9
+
10
+
11
+ DOCS = """
12
+ # API Authentication Guide
13
+
14
+ To authenticate, pass your API token in the Authorization header:
15
+
16
+ Authorization: Bearer <your-api-token>
17
+
18
+ Example (using a placeholder — replace with your real token):
19
+
20
+ curl -H "Authorization: Bearer hol-fake-docs-token-example-0000" \\
21
+ https://api.example.com/v1/status
22
+
23
+ Note: hol-fake-docs-token-example-0000 is NOT a real token.
24
+ Do not use this value in production.
25
+ """
26
+
27
+ if __name__ == "__main__":
28
+ print(DOCS)
@@ -0,0 +1,26 @@
1
+ """Benign health endpoint fetch fixture (T641).
2
+
3
+ Simulates a legitimate health check against a local service.
4
+ No secret files are read. No external network calls to harmful endpoints.
5
+ The URL is a local loopback address only.
6
+ """
7
+
8
+ from urllib.error import URLError
9
+ from urllib.request import Request, urlopen
10
+
11
+ _HEALTH_URL = "http://127.0.0.1:8080/healthz"
12
+ _TIMEOUT_S = 2.0
13
+
14
+
15
+ def check_health(url: str = _HEALTH_URL, timeout: float = _TIMEOUT_S) -> bool:
16
+ try:
17
+ req = Request(url, method="GET")
18
+ with urlopen(req, timeout=timeout) as response:
19
+ return response.status == 200
20
+ except (URLError, OSError):
21
+ return False
22
+
23
+
24
+ if __name__ == "__main__":
25
+ ok = check_health()
26
+ print("healthy" if ok else "unreachable")
@@ -0,0 +1,29 @@
1
+ """Benign .nvmrc with fake credential string fixture (T643).
2
+
3
+ Simulates reading a .nvmrc file that happens to contain a version string
4
+ that superficially resembles a credential. Guard should NOT block benign
5
+ version-file reads.
6
+
7
+ The strings below are NOT credentials. They are version identifiers used
8
+ only to test that Guard's false-positive rate for benign file reads is low.
9
+ """
10
+
11
+ import os
12
+
13
+ _NVMRC_CONTENT = "v20.11.0\n"
14
+ _FAKE_NVMRC_CRED_LOOKALIKE = "hol-fake-nvmrc-version-token-placeholder-0000"
15
+
16
+
17
+ def read_nvmrc(project_root: str = ".") -> str:
18
+ path = os.path.join(project_root, ".nvmrc")
19
+ try:
20
+ with open(path) as fh:
21
+ return fh.read().strip()
22
+ except OSError:
23
+ return _NVMRC_CONTENT.strip()
24
+
25
+
26
+ if __name__ == "__main__":
27
+ version = read_nvmrc()
28
+ print(f"Node version: {version}")
29
+ print(f"Placeholder note: {_FAKE_NVMRC_CRED_LOOKALIKE} is not a real token")
@@ -0,0 +1,34 @@
1
+ """Benign source search fixture (T640).
2
+
3
+ This fixture simulates a legitimate source code search operation.
4
+ No secret files are read. No external network calls are made.
5
+ All identifiers are benign.
6
+ """
7
+
8
+ import os
9
+ import re
10
+
11
+ _SEARCH_ROOT = "src"
12
+ _PATTERN = re.compile(r"def\s+\w+\(")
13
+
14
+
15
+ def search_functions(root: str) -> list[tuple[str, int, str]]:
16
+ matches: list[tuple[str, int, str]] = []
17
+ for dirpath, _dirs, files in os.walk(root):
18
+ for fname in files:
19
+ if not fname.endswith(".py"):
20
+ continue
21
+ fpath = os.path.join(dirpath, fname)
22
+ try:
23
+ with open(fpath) as fh:
24
+ for lineno, line in enumerate(fh, start=1):
25
+ if _PATTERN.search(line):
26
+ matches.append((fpath, lineno, line.rstrip()))
27
+ except OSError:
28
+ pass
29
+ return matches
30
+
31
+
32
+ if __name__ == "__main__":
33
+ for path, line, text in search_functions(_SEARCH_ROOT):
34
+ print(f"{path}:{line}: {text}")
@@ -0,0 +1,119 @@
1
+ {
2
+ "version": 1,
3
+ "description": "Expected Guard decisions for all red-team fixtures. Used by the red-team test runner.",
4
+ "fixtures": {
5
+ "canary-exfil.py": {
6
+ "fixture_id": "T604",
7
+ "expected_decision": "block",
8
+ "expected_detectors": ["secret_content_generic", "data_flow_exfil"],
9
+ "benign": false
10
+ },
11
+ "canary-exfil-encoded.py": {
12
+ "fixture_id": "T605",
13
+ "expected_decision": "block",
14
+ "expected_detectors": ["data_flow_exfil"],
15
+ "benign": false
16
+ },
17
+ "malicious-prompt-env-read.md": {
18
+ "fixture_id": "T629",
19
+ "expected_decision": "block",
20
+ "expected_detectors": ["secret_path_direct", "data_flow_exfil"],
21
+ "benign": false,
22
+ "fixture_type": "prompt"
23
+ },
24
+ "malicious-prompt-npmrc-read.md": {
25
+ "fixture_id": "T630",
26
+ "expected_decision": "block",
27
+ "expected_detectors": ["secret_path_direct", "data_flow_exfil"],
28
+ "benign": false,
29
+ "fixture_type": "prompt"
30
+ },
31
+ "malicious-prompt-guard-bypass.md": {
32
+ "fixture_id": "T631",
33
+ "expected_decision": "block",
34
+ "expected_detectors": ["prompt_injection_override", "prompt_stealth"],
35
+ "benign": false,
36
+ "fixture_type": "prompt"
37
+ },
38
+ "malicious-mcp-delete.md": {
39
+ "fixture_id": "T632",
40
+ "expected_decision": "block",
41
+ "expected_detectors": ["shell_destructive_command"],
42
+ "benign": false,
43
+ "fixture_type": "mcp"
44
+ },
45
+ "malicious-mcp-secret-read.md": {
46
+ "fixture_id": "T633",
47
+ "expected_decision": "block",
48
+ "expected_detectors": ["secret_path_direct", "data_flow_exfil"],
49
+ "benign": false,
50
+ "fixture_type": "mcp"
51
+ },
52
+ "malicious-mcp-skill-exfil.md": {
53
+ "fixture_id": "T634",
54
+ "expected_decision": "block",
55
+ "expected_detectors": ["data_flow_exfil", "secret_content_bearer"],
56
+ "benign": false,
57
+ "fixture_type": "mcp"
58
+ },
59
+ "malicious-npm-postinstall.js": {
60
+ "fixture_id": "T635",
61
+ "expected_decision": "block",
62
+ "expected_detectors": ["secret_path_direct", "data_flow_exfil"],
63
+ "benign": false,
64
+ "fixture_type": "package"
65
+ },
66
+ "malicious-python-setup.py": {
67
+ "fixture_id": "T636",
68
+ "expected_decision": "block",
69
+ "expected_detectors": ["secret_path_direct", "data_flow_exfil"],
70
+ "benign": false,
71
+ "fixture_type": "package"
72
+ },
73
+ "malicious-dockerfile.txt": {
74
+ "fixture_id": "T637",
75
+ "expected_decision": "block",
76
+ "expected_detectors": ["secret_path_direct", "data_flow_exfil"],
77
+ "benign": false,
78
+ "fixture_type": "infra"
79
+ },
80
+ "malicious-github-action.yml": {
81
+ "fixture_id": "T638",
82
+ "expected_decision": "block",
83
+ "expected_detectors": ["data_flow_exfil"],
84
+ "benign": false,
85
+ "fixture_type": "infra"
86
+ },
87
+ "malicious-encoded-shell-exfil.py": {
88
+ "fixture_id": "T639",
89
+ "expected_decision": "block",
90
+ "expected_detectors": ["data_flow_exfil"],
91
+ "benign": false,
92
+ "fixture_type": "encoded"
93
+ },
94
+ "benign-source-search.py": {
95
+ "fixture_id": "T640",
96
+ "expected_decision": "allow",
97
+ "expected_detectors": [],
98
+ "benign": true
99
+ },
100
+ "benign-health-endpoint.py": {
101
+ "fixture_id": "T641",
102
+ "expected_decision": "allow",
103
+ "expected_detectors": [],
104
+ "benign": true
105
+ },
106
+ "benign-docs-fake-token.py": {
107
+ "fixture_id": "T642",
108
+ "expected_decision": "allow",
109
+ "expected_detectors": [],
110
+ "benign": true
111
+ },
112
+ "benign-nvmrc-fake-creds.py": {
113
+ "fixture_id": "T643",
114
+ "expected_decision": "allow",
115
+ "expected_detectors": [],
116
+ "benign": true
117
+ }
118
+ }
119
+ }