plugin-scanner 2.0.77__tar.gz → 2.0.78__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 (333) hide show
  1. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/PKG-INFO +1 -1
  2. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/pyproject.toml +1 -1
  3. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/pyproject.toml.bak +1 -1
  4. plugin_scanner-2.0.78/src/codex_plugin_scanner/guard/advisory_model.py +150 -0
  5. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/cli/commands.py +2 -0
  6. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/protect.py +36 -13
  7. plugin_scanner-2.0.78/src/codex_plugin_scanner/guard/redaction.py +93 -0
  8. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/version.py +1 -1
  9. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_protect.py +326 -0
  10. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.clusterfuzzlite/Dockerfile +0 -0
  11. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.clusterfuzzlite/build.sh +0 -0
  12. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.clusterfuzzlite/project.yaml +0 -0
  13. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.clusterfuzzlite/requirements-atheris.txt +0 -0
  14. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.dockerignore +0 -0
  15. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.github/CODEOWNERS +0 -0
  16. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  17. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  18. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  19. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.github/dependabot.yml +0 -0
  20. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.github/workflows/ci.yml +0 -0
  21. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.github/workflows/codeql.yml +0 -0
  22. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.github/workflows/dependabot-uv-lock.yml +0 -0
  23. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.github/workflows/fuzz.yml +0 -0
  24. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.github/workflows/harness-smoke.yml +0 -0
  25. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.github/workflows/publish.yml +0 -0
  26. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.github/workflows/scorecard.yml +0 -0
  27. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.gitignore +0 -0
  28. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/.pre-commit-hooks.yaml +0 -0
  29. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/CONTRIBUTING.md +0 -0
  30. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/Dockerfile +0 -0
  31. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/LICENSE +0 -0
  32. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/README.md +0 -0
  33. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/SECURITY.md +0 -0
  34. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/index.html +0 -0
  35. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/package.json +0 -0
  36. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/pnpm-lock.yaml +0 -0
  37. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/public/apple-touch-icon.png +0 -0
  38. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
  39. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/public/brand/Logo_Whole.png +0 -0
  40. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/public/favicon-16x16.png +0 -0
  41. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/public/favicon-32x32.png +0 -0
  42. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/public/favicon.ico +0 -0
  43. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/src/app.tsx +0 -0
  44. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/src/approval-center-layout.tsx +0 -0
  45. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/src/approval-center-primitives.tsx +0 -0
  46. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/src/approval-center-utils.ts +0 -0
  47. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/src/fleet-workspace.tsx +0 -0
  48. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/src/guard-api.ts +0 -0
  49. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/src/guard-demo.ts +0 -0
  50. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/src/guard-types.ts +0 -0
  51. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/src/main.tsx +0 -0
  52. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/src/receipts-workspace.tsx +0 -0
  53. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/src/runtime-overview.tsx +0 -0
  54. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/src/settings-workspace.tsx +0 -0
  55. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/src/styles.css +0 -0
  56. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/src/vite-env.d.ts +0 -0
  57. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/tsconfig.json +0 -0
  58. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/dashboard/vite.config.ts +0 -0
  59. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/docker-requirements.txt +0 -0
  60. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/docs/guard/approval-audit.md +0 -0
  61. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/docs/guard/architecture.md +0 -0
  62. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/docs/guard/get-started.md +0 -0
  63. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/docs/guard/harness-support.md +0 -0
  64. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/docs/guard/local-vs-cloud.md +0 -0
  65. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/docs/guard/testing-matrix.md +0 -0
  66. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/docs/trust/mcp-trust-draft.md +0 -0
  67. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/docs/trust/plugin-trust-draft.md +0 -0
  68. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/docs/trust/skill-trust-local.md +0 -0
  69. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/fuzzers/manifest_fuzzer.py +0 -0
  70. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/requirements.txt +0 -0
  71. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/schemas/plugin-quality.v1.json +0 -0
  72. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/schemas/scan-result.v1.json +0 -0
  73. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/schemas/verify-result.v1.json +0 -0
  74. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/__init__.py +0 -0
  75. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/action_runner.py +0 -0
  76. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/argparse_utils.py +0 -0
  77. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/checks/__init__.py +0 -0
  78. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
  79. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/checks/claude.py +0 -0
  80. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
  81. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
  82. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/checks/gemini.py +0 -0
  83. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/checks/manifest.py +0 -0
  84. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
  85. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
  86. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
  87. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/checks/opencode.py +0 -0
  88. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
  89. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/checks/security.py +0 -0
  90. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
  91. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/cli.py +0 -0
  92. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/cli_ui.py +0 -0
  93. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/config.py +0 -0
  94. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
  95. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
  96. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
  97. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
  98. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
  99. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
  100. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
  101. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
  102. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
  103. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/github_reporting.py +0 -0
  104. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/__init__.py +0 -0
  105. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
  106. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
  107. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
  108. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
  109. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
  110. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
  111. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
  112. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
  113. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
  114. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
  115. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
  116. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
  117. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/approvals.py +0 -0
  118. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
  119. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
  120. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
  121. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
  122. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
  123. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
  124. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
  125. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
  126. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
  127. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
  128. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
  129. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
  130. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/config.py +0 -0
  131. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
  132. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
  133. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
  134. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
  135. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
  136. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
  137. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
  138. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
  139. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
  140. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
  141. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
  142. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
  143. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
  144. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
  145. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
  146. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
  147. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/incident.py +0 -0
  148. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/launcher.py +0 -0
  149. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
  150. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/models.py +0 -0
  151. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
  152. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
  153. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
  154. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
  155. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
  156. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
  157. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
  158. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
  159. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/risk.py +0 -0
  160. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
  161. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
  162. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
  163. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
  164. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
  165. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
  166. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
  167. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
  168. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/shims.py +0 -0
  169. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/store.py +0 -0
  170. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
  171. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
  172. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/guard/types.py +0 -0
  173. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
  174. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
  175. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
  176. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/lint_fixes.py +0 -0
  177. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/marketplace_support.py +0 -0
  178. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/models.py +0 -0
  179. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/path_support.py +0 -0
  180. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/policy.py +0 -0
  181. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/quality_artifact.py +0 -0
  182. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/repo_detect.py +0 -0
  183. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/reporting.py +0 -0
  184. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/rules/__init__.py +0 -0
  185. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/rules/registry.py +0 -0
  186. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/rules/specs.py +0 -0
  187. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/scanner.py +0 -0
  188. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/submission.py +0 -0
  189. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/suppressions.py +0 -0
  190. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
  191. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/trust_helpers.py +0 -0
  192. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
  193. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/trust_models.py +0 -0
  194. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
  195. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/trust_scoring.py +0 -0
  196. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
  197. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/trust_specs.py +0 -0
  198. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/src/codex_plugin_scanner/verification.py +0 -0
  199. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/__init__.py +0 -0
  200. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/conftest.py +0 -0
  201. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/__init__.py +0 -0
  202. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
  203. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/bad-plugin/.mcp.json +0 -0
  204. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/bad-plugin/secrets.js +0 -0
  205. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
  206. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
  207. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/claude-plugin-good/README.md +0 -0
  208. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
  209. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
  210. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
  211. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/code-quality-bad/evil.js +0 -0
  212. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/code-quality-bad/inject.js +0 -0
  213. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
  214. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
  215. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/gemini-extension-good/README.md +0 -0
  216. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
  217. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
  218. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
  219. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
  220. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/good-plugin/.codexignore +0 -0
  221. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/good-plugin/LICENSE +0 -0
  222. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/good-plugin/README.md +0 -0
  223. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/good-plugin/SECURITY.md +0 -0
  224. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
  225. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
  226. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
  227. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
  228. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
  229. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
  230. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
  231. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
  232. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
  233. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
  234. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
  235. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
  236. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
  237. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
  238. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
  239. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
  240. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
  241. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
  242. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
  243. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/mcp-canary-server.py +0 -0
  244. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
  245. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
  246. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/mit-license/LICENSE +0 -0
  247. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
  248. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
  249. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
  250. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
  251. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
  252. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
  253. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
  254. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
  255. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
  256. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
  257. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
  258. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
  259. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
  260. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
  261. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
  262. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
  263. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
  264. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
  265. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/opencode-good/LICENSE +0 -0
  266. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/opencode-good/README.md +0 -0
  267. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/opencode-good/SECURITY.md +0 -0
  268. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
  269. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
  270. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
  271. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
  272. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
  273. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
  274. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/fixtures/with-marketplace/marketplace.json +0 -0
  275. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test-trust-scoring.py +0 -0
  276. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test-trust-specs.py +0 -0
  277. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_action_runner.py +0 -0
  278. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_best_practices.py +0 -0
  279. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_cisco_install_surfaces.py +0 -0
  280. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_cli.py +0 -0
  281. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_code_quality.py +0 -0
  282. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_config.py +0 -0
  283. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_coverage_remaining.py +0 -0
  284. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_ecosystems.py +0 -0
  285. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_edge_cases.py +0 -0
  286. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_final_coverage.py +0 -0
  287. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_approvals.py +0 -0
  288. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_bootstrap.py +0 -0
  289. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_capabilities.py +0 -0
  290. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_claude_adapter.py +0 -0
  291. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_cli.py +0 -0
  292. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_codex_e2e.py +0 -0
  293. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_codex_install.py +0 -0
  294. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_codex_proxy.py +0 -0
  295. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_config_paths.py +0 -0
  296. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_connect_flow.py +0 -0
  297. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_consumer_mode.py +0 -0
  298. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_copilot_adapter.py +0 -0
  299. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_copilot_proxy.py +0 -0
  300. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_daemon_manager.py +0 -0
  301. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_event_schema_v1.py +0 -0
  302. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_events.py +0 -0
  303. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_launch_env.py +0 -0
  304. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_opencode_proxy.py +0 -0
  305. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_product_flow.py +0 -0
  306. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_render.py +0 -0
  307. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_risk.py +0 -0
  308. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_runtime.py +0 -0
  309. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_store_migrations.py +0 -0
  310. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_surface_server.py +0 -0
  311. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_guard_verdicts.py +0 -0
  312. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_hermes_adapter.py +0 -0
  313. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_integration.py +0 -0
  314. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_lint_fixes.py +0 -0
  315. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_live_cisco_smoke.py +0 -0
  316. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_manifest.py +0 -0
  317. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_marketplace.py +0 -0
  318. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_mcp_security.py +0 -0
  319. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_operational_security.py +0 -0
  320. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_policy.py +0 -0
  321. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_quality_artifact.py +0 -0
  322. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_rule_registry.py +0 -0
  323. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_scanner.py +0 -0
  324. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_schema_contracts.py +0 -0
  325. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_security.py +0 -0
  326. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_security_ops.py +0 -0
  327. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_skill_security.py +0 -0
  328. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_submission.py +0 -0
  329. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_trust_scoring.py +0 -0
  330. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_trust_specs.py +0 -0
  331. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_verification.py +0 -0
  332. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/tests/test_versioning.py +0 -0
  333. {plugin_scanner-2.0.77 → plugin_scanner-2.0.78}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 2.0.77
3
+ Version: 2.0.78
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.77"
7
+ version = "2.0.78"
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.77"
7
+ version = "2.0.78"
8
8
  description = "Protect local AI harnesses with HOL Guard and run scanner checks for Codex, Claude, Cursor, Gemini, and OpenCode."
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -0,0 +1,150 @@
1
+ """Guard advisory identity helpers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from urllib.parse import urlsplit
7
+
8
+ _PACKAGE_URL_ECOSYSTEMS = {
9
+ "npm": "npm",
10
+ "pnpm": "npm",
11
+ "yarn": "npm",
12
+ "pip": "pypi",
13
+ "uv": "pypi",
14
+ "go": "golang",
15
+ }
16
+
17
+
18
+ @dataclass(frozen=True, slots=True)
19
+ class ProtectTargetIdentity:
20
+ """Subset of install target data advisory matching needs."""
21
+
22
+ artifact_id: str
23
+ artifact_name: str
24
+ ecosystem: str
25
+ package_name: str | None
26
+ package_url: str | None
27
+ source_url: str | None
28
+
29
+
30
+ def build_package_url(ecosystem: str, package_name: str | None, version: str | None) -> str | None:
31
+ """Build a simple purl-style identifier for registry package installs."""
32
+
33
+ if package_name is None:
34
+ return None
35
+ purl_type = _PACKAGE_URL_ECOSYSTEMS.get(ecosystem)
36
+ if purl_type is None:
37
+ return None
38
+ base = f"pkg:{purl_type}/{normalize_identity_value(package_name)}"
39
+ if version is None or not version.strip():
40
+ return base
41
+ return f"{base}@{version.strip()}"
42
+
43
+
44
+ def advisory_matches_target(advisory: dict[str, object], target: ProtectTargetIdentity) -> bool:
45
+ """Match advisories against install targets using stable identities first."""
46
+
47
+ advisory_id = advisory.get("artifact_id")
48
+ if isinstance(advisory_id, str) and advisory_id == target.artifact_id:
49
+ return True
50
+
51
+ advisory_ecosystem = advisory.get("ecosystem")
52
+ if isinstance(advisory_ecosystem, str) and advisory_ecosystem not in {target.ecosystem, "*"}:
53
+ return False
54
+
55
+ package_url = advisory.get("package_url")
56
+ if isinstance(package_url, str) and _package_url_matches(package_url, target.package_url):
57
+ return True
58
+
59
+ if _normalized_membership(advisory.get("aliases"), target.package_name, target.artifact_name):
60
+ return True
61
+
62
+ advisory_package = advisory.get("package") or advisory.get("name")
63
+ normalized_advisory_package = (
64
+ normalize_identity_value(advisory_package) if isinstance(advisory_package, str) else ""
65
+ )
66
+ if normalized_advisory_package != "" and normalized_advisory_package in {
67
+ normalize_identity_value(target.package_name),
68
+ normalize_identity_value(target.artifact_name),
69
+ }:
70
+ return True
71
+
72
+ publisher = advisory.get("publisher")
73
+ normalized_publisher = normalize_identity_value(publisher) if isinstance(publisher, str) else ""
74
+ if normalized_publisher != "" and normalized_publisher == normalize_identity_value(target.package_name):
75
+ return True
76
+
77
+ if _normalized_membership(advisory.get("publisher_identities"), target.package_name):
78
+ return True
79
+
80
+ if _endpoint_indicator_matches(advisory.get("endpoint_indicators"), target.source_url):
81
+ return True
82
+
83
+ advisory_source_url = advisory.get("source_url")
84
+ if not isinstance(advisory_source_url, str):
85
+ return False
86
+
87
+ normalized_advisory_source = _normalized_url_indicator(advisory_source_url)
88
+ normalized_target_source = _normalized_url_indicator(target.source_url)
89
+ return (
90
+ normalized_advisory_source != ""
91
+ and normalized_target_source != ""
92
+ and normalized_advisory_source == normalized_target_source
93
+ )
94
+
95
+
96
+ def normalize_identity_value(value: str | None) -> str:
97
+ return value.strip().lower() if isinstance(value, str) and value.strip() else ""
98
+
99
+
100
+ def _normalized_membership(values: object, *candidates: str | None) -> bool:
101
+ if not isinstance(values, list):
102
+ return False
103
+ normalized_values = {normalize_identity_value(item) for item in values if isinstance(item, str)}
104
+ normalized_candidates = {normalize_identity_value(candidate) for candidate in candidates if candidate is not None}
105
+ normalized_candidates.discard("")
106
+ return bool(normalized_values & normalized_candidates)
107
+
108
+
109
+ def _package_url_matches(advisory_url: str, target_url: str | None) -> bool:
110
+ if target_url is None:
111
+ return False
112
+ normalized_advisory = _package_url_base(advisory_url)
113
+ normalized_target = _package_url_base(target_url)
114
+ return normalized_advisory != "" and normalized_advisory == normalized_target
115
+
116
+
117
+ def _package_url_base(package_url: str) -> str:
118
+ normalized = normalize_identity_value(package_url)
119
+ for separator in ("?", "#"):
120
+ normalized = normalized.split(separator, 1)[0]
121
+ last_at = normalized.rfind("@")
122
+ if last_at == -1 or last_at < normalized.rfind("/"):
123
+ return normalized
124
+ return normalized[:last_at]
125
+
126
+
127
+ def _endpoint_indicator_matches(values: object, source_url: str | None) -> bool:
128
+ if source_url is None or not isinstance(values, list):
129
+ return False
130
+ normalized_source = _normalized_url_indicator(source_url)
131
+ return any(
132
+ isinstance(item, str) and _url_indicator_matches(normalized_source, _normalized_url_indicator(item))
133
+ for item in values
134
+ )
135
+
136
+
137
+ def _normalized_url_indicator(value: str | None) -> str:
138
+ if value is None:
139
+ return ""
140
+ parsed = urlsplit(value)
141
+ if not parsed.scheme or not parsed.netloc:
142
+ return normalize_identity_value(value)
143
+ path = parsed.path.rstrip("/")
144
+ return normalize_identity_value(f"{parsed.netloc}{path}")
145
+
146
+
147
+ def _url_indicator_matches(normalized_source: str, normalized_indicator: str) -> bool:
148
+ if normalized_source == "" or normalized_indicator == "":
149
+ return False
150
+ return normalized_source == normalized_indicator or normalized_source.startswith(f"{normalized_indicator}/")
@@ -285,6 +285,7 @@ def _configure_guard_parser(guard_parser: argparse.ArgumentParser) -> None:
285
285
  )
286
286
  _add_guard_common_args(protect_parser)
287
287
  protect_parser.add_argument("--dry-run", action="store_true")
288
+ protect_parser.add_argument("--unsafe-raw-output", action="store_true")
288
289
  protect_parser.add_argument("--json", action="store_true")
289
290
  protect_parser.add_argument("protect_command", nargs=argparse.REMAINDER)
290
291
 
@@ -659,6 +660,7 @@ def run_guard_command(
659
660
  workspace_dir=workspace or Path.cwd(),
660
661
  dry_run=bool(getattr(args, "dry_run", False)),
661
662
  now=_now(),
663
+ unsafe_raw_output=bool(getattr(args, "unsafe_raw_output", False)),
662
664
  )
663
665
  _emit("protect", payload, getattr(args, "json", False))
664
666
  return exit_code
@@ -12,8 +12,10 @@ from pathlib import Path
12
12
  from typing import Literal
13
13
  from urllib.parse import urlparse
14
14
 
15
+ from .advisory_model import ProtectTargetIdentity, advisory_matches_target, build_package_url
15
16
  from .models import GuardReceipt
16
17
  from .receipts import build_receipt
18
+ from .redaction import redact_text
17
19
  from .store import GuardStore
18
20
 
19
21
  ProtectAction = Literal["allow", "review", "block"]
@@ -38,6 +40,7 @@ class ProtectTarget:
38
40
  artifact_type: str
39
41
  ecosystem: str
40
42
  package_name: str | None
43
+ package_url: str | None
41
44
  raw_spec: str | None
42
45
  version: str | None
43
46
  source_url: str | None
@@ -50,6 +53,7 @@ class ProtectTarget:
50
53
  "artifact_type": self.artifact_type,
51
54
  "ecosystem": self.ecosystem,
52
55
  "package_name": self.package_name,
56
+ "package_url": self.package_url,
53
57
  "raw_spec": self.raw_spec,
54
58
  "version": self.version,
55
59
  "source_url": self.source_url,
@@ -109,6 +113,7 @@ def build_protect_payload(
109
113
  workspace_dir: Path,
110
114
  dry_run: bool,
111
115
  now: str,
116
+ unsafe_raw_output: bool = False,
112
117
  ) -> tuple[dict[str, object], int]:
113
118
  """Evaluate and optionally execute an install command."""
114
119
 
@@ -151,11 +156,16 @@ def build_protect_payload(
151
156
  text=True,
152
157
  timeout=_protect_command_timeout_seconds(),
153
158
  )
159
+ redacted_stdout = redact_text(execution.stdout)
160
+ redacted_stderr = redact_text(execution.stderr)
154
161
  payload["executed"] = True
155
162
  payload["execution"] = {
156
163
  "returncode": execution.returncode,
157
- "stdout": execution.stdout,
158
- "stderr": execution.stderr,
164
+ "stdout": execution.stdout if unsafe_raw_output else redacted_stdout.text,
165
+ "stderr": execution.stderr if unsafe_raw_output else redacted_stderr.text,
166
+ "stdout_redactions": redacted_stdout.to_dict(),
167
+ "stderr_redactions": redacted_stderr.to_dict(),
168
+ "raw_output_enabled": unsafe_raw_output,
159
169
  }
160
170
  if execution.returncode == 0:
161
171
  store.add_receipt(receipt)
@@ -287,6 +297,7 @@ def _parse_codex_request(command: list[str]) -> ProtectRequest:
287
297
  artifact_type="mcp_server",
288
298
  ecosystem="codex",
289
299
  package_name=name,
300
+ package_url=None,
290
301
  raw_spec=name,
291
302
  version=None,
292
303
  source_url=_option_value(command, "--url"),
@@ -309,6 +320,7 @@ def _parse_claude_request(command: list[str]) -> ProtectRequest:
309
320
  artifact_type="mcp_server",
310
321
  ecosystem="claude-code",
311
322
  package_name=name,
323
+ package_url=None,
312
324
  raw_spec=command_or_url,
313
325
  version=None,
314
326
  source_url=command_or_url if command_or_url.startswith(("http://", "https://")) else None,
@@ -334,6 +346,7 @@ def _parse_cursor_request(command: list[str]) -> ProtectRequest:
334
346
  artifact_type="mcp_server",
335
347
  ecosystem="cursor",
336
348
  package_name=name,
349
+ package_url=None,
337
350
  raw_spec=name,
338
351
  version=None,
339
352
  source_url=_option_value(command, "--url"),
@@ -352,6 +365,7 @@ def _parse_gemini_request(command: list[str]) -> ProtectRequest:
352
365
  artifact_type="extension",
353
366
  ecosystem="gemini",
354
367
  package_name=name,
368
+ package_url=None,
355
369
  raw_spec=name,
356
370
  version=None,
357
371
  source_url=_option_value(command, "--url"),
@@ -372,6 +386,7 @@ def _parse_gemini_request(command: list[str]) -> ProtectRequest:
372
386
  artifact_type=artifact_type,
373
387
  ecosystem="gemini",
374
388
  package_name=name if artifact_type == "extension" else None,
389
+ package_url=build_package_url("gemini", name if artifact_type == "extension" else None, None),
375
390
  raw_spec=spec,
376
391
  version=None,
377
392
  source_url=_spec_url(spec),
@@ -389,6 +404,7 @@ def _parse_gemini_request(command: list[str]) -> ProtectRequest:
389
404
  artifact_type="mcp_server",
390
405
  ecosystem="gemini",
391
406
  package_name=name,
407
+ package_url=None,
392
408
  raw_spec=command_or_url,
393
409
  version=None,
394
410
  source_url=source_url,
@@ -407,6 +423,7 @@ def _parse_antigravity_request(command: list[str]) -> ProtectRequest:
407
423
  artifact_type="extension",
408
424
  ecosystem="antigravity",
409
425
  package_name=extension_name,
426
+ package_url=build_package_url("antigravity", extension_name, None),
410
427
  raw_spec=extension_name,
411
428
  version=None,
412
429
  source_url=_spec_url(extension_name),
@@ -429,6 +446,7 @@ def _parse_opencode_request(command: list[str]) -> ProtectRequest:
429
446
  artifact_type="plugin" if command[1] == "plugin" else "skill",
430
447
  ecosystem="opencode",
431
448
  package_name=name,
449
+ package_url=None,
432
450
  raw_spec=name,
433
451
  version=None,
434
452
  source_url=_option_value(command, "--url"),
@@ -446,6 +464,7 @@ def _parse_custom_request(command: list[str]) -> ProtectRequest:
446
464
  artifact_type="custom_command",
447
465
  ecosystem="custom",
448
466
  package_name=None,
467
+ package_url=None,
449
468
  raw_spec=shlex.join(command),
450
469
  version=None,
451
470
  source_url=_first_url(command),
@@ -464,6 +483,7 @@ def _package_manager_request(command: list[str], ecosystem: str, specs: tuple[st
464
483
  artifact_type="package_request",
465
484
  ecosystem=ecosystem,
466
485
  package_name=None,
486
+ package_url=None,
467
487
  raw_spec=shlex.join(command),
468
488
  version=None,
469
489
  source_url=_first_url(command),
@@ -483,6 +503,7 @@ def _package_target(ecosystem: str, spec: str) -> ProtectTarget:
483
503
  artifact_type=f"{ecosystem}_package",
484
504
  ecosystem=ecosystem,
485
505
  package_name=package_name,
506
+ package_url=build_package_url(ecosystem, package_name, version),
486
507
  raw_spec=spec,
487
508
  version=version,
488
509
  source_url=source_url,
@@ -613,6 +634,7 @@ def _parse_antigravity_mcp_target(raw_payload: str) -> ProtectTarget:
613
634
  artifact_type="mcp_server",
614
635
  ecosystem="antigravity",
615
636
  package_name=name,
637
+ package_url=None,
616
638
  raw_spec=raw_payload,
617
639
  version=None,
618
640
  source_url=source_url,
@@ -640,6 +662,7 @@ def _parse_claude_mcp_target(name: str, raw_payload: str) -> ProtectTarget:
640
662
  artifact_type="mcp_server",
641
663
  ecosystem="claude-code",
642
664
  package_name=name,
665
+ package_url=None,
643
666
  raw_spec=raw_payload,
644
667
  version=None,
645
668
  source_url=source_url,
@@ -670,17 +693,17 @@ def _matching_advisories(
670
693
 
671
694
 
672
695
  def _advisory_matches_target(advisory: dict[str, object], target: ProtectTarget) -> bool:
673
- advisory_id = advisory.get("artifact_id")
674
- if isinstance(advisory_id, str) and advisory_id == target.artifact_id:
675
- return True
676
- advisory_ecosystem = advisory.get("ecosystem")
677
- if isinstance(advisory_ecosystem, str) and advisory_ecosystem not in {target.ecosystem, "*"}:
678
- return False
679
- advisory_package = advisory.get("package") or advisory.get("name")
680
- if isinstance(advisory_package, str):
681
- return advisory_package == target.package_name or advisory_package == target.artifact_name
682
- advisory_publisher = advisory.get("publisher")
683
- return isinstance(advisory_publisher, str) and advisory_publisher == target.package_name
696
+ return advisory_matches_target(
697
+ advisory,
698
+ ProtectTargetIdentity(
699
+ artifact_id=target.artifact_id,
700
+ artifact_name=target.artifact_name,
701
+ ecosystem=target.ecosystem,
702
+ package_name=target.package_name,
703
+ package_url=target.package_url,
704
+ source_url=target.source_url,
705
+ ),
706
+ )
684
707
 
685
708
 
686
709
  def _advisory_severity(advisory: dict[str, object]) -> SeverityLabel:
@@ -0,0 +1,93 @@
1
+ """Output redaction helpers for Guard command payloads."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import re
7
+ from dataclasses import dataclass
8
+
9
+
10
+ @dataclass(frozen=True, slots=True)
11
+ class RedactedText:
12
+ """Safe text plus minimal metadata about removed secrets."""
13
+
14
+ text: str
15
+ count: int
16
+ classifiers: tuple[str, ...]
17
+ original_sha256: str
18
+
19
+ def to_dict(self) -> dict[str, object]:
20
+ return {
21
+ "count": self.count,
22
+ "classifiers": list(self.classifiers),
23
+ "original_sha256": self.original_sha256,
24
+ }
25
+
26
+
27
+ _REDACTION_PATTERNS: tuple[tuple[str, re.Pattern[str], str], ...] = (
28
+ (
29
+ "bearer-token",
30
+ re.compile(r"(?i)\b(Bearer)\s+([A-Za-z0-9._\-]{8,})"),
31
+ r"\1 *****",
32
+ ),
33
+ (
34
+ "github-token",
35
+ re.compile(r"\bgh[pousr]_[A-Za-z0-9_]{8,}\b"),
36
+ "gh*****",
37
+ ),
38
+ (
39
+ "aws-access-key",
40
+ re.compile(r"\bAKIA[0-9A-Z]{16}\b"),
41
+ "AKIA****************",
42
+ ),
43
+ (
44
+ "npm-token",
45
+ re.compile(r"(?im)\b(_authToken|npm[_ -]?token)\s*[:=]\s*([^\s]+)"),
46
+ r"\1=*****",
47
+ ),
48
+ (
49
+ "private-key",
50
+ re.compile(
51
+ r"-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----.*?-----END [A-Z0-9 ]*PRIVATE KEY-----",
52
+ re.DOTALL,
53
+ ),
54
+ "-----BEGIN PRIVATE KEY-----\n*****\n-----END PRIVATE KEY-----",
55
+ ),
56
+ (
57
+ "secret-env",
58
+ re.compile(
59
+ r"(?im)^([ \t]*)([A-Z0-9_]*(?:TOKEN|SECRET|PASSWORD|KEY|CREDENTIAL)[A-Z0-9_]*)=(.+)$",
60
+ ),
61
+ r"\1\2=*****",
62
+ ),
63
+ (
64
+ "connection-env",
65
+ re.compile(r"(?im)^([ \t]*)([A-Z0-9_]*(?:URL|URI|DSN))=([A-Za-z][A-Za-z0-9+.-]*://.+)$"),
66
+ r"\1\2=*****",
67
+ ),
68
+ (
69
+ "connection-string",
70
+ re.compile(r"\b(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqp)://[^\s]+", re.IGNORECASE),
71
+ "*****",
72
+ ),
73
+ )
74
+
75
+
76
+ def redact_text(value: str) -> RedactedText:
77
+ """Redact common secret-like values before Guard prints or syncs them."""
78
+
79
+ redacted_value = value
80
+ classifiers: list[str] = []
81
+ total_count = 0
82
+ for classifier, pattern, replacement in _REDACTION_PATTERNS:
83
+ redacted_value, match_count = pattern.subn(replacement, redacted_value)
84
+ if match_count == 0:
85
+ continue
86
+ classifiers.extend([classifier] * match_count)
87
+ total_count += match_count
88
+ return RedactedText(
89
+ text=redacted_value,
90
+ count=total_count,
91
+ classifiers=tuple(dict.fromkeys(classifiers)),
92
+ original_sha256=hashlib.sha256(value.encode("utf-8")).hexdigest(),
93
+ )
@@ -1,3 +1,3 @@
1
1
  """Single source of truth for tool version."""
2
2
 
3
- __version__ = "2.0.77"
3
+ __version__ = "2.0.78"