plugin-scanner 2.0.108__tar.gz → 2.0.110__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 (350) hide show
  1. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/PKG-INFO +20 -9
  2. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/README.md +19 -8
  3. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/docs/guard/get-started.md +24 -0
  4. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/docs/guard/testing-matrix.md +10 -0
  5. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/pyproject.toml +1 -1
  6. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/pyproject.toml.bak +1 -1
  7. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/cli/commands.py +260 -10
  8. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/cli/render.py +117 -51
  9. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/consumer/service.py +9 -1
  10. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/runtime/secret_sensitivity.py +25 -2
  11. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/version.py +1 -1
  12. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_cli.py +36 -0
  13. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_cli.py +157 -0
  14. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_product_flow.py +11 -0
  15. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_risk.py +20 -0
  16. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_runtime.py +473 -1
  17. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.clusterfuzzlite/Dockerfile +0 -0
  18. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.clusterfuzzlite/build.sh +0 -0
  19. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.clusterfuzzlite/project.yaml +0 -0
  20. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.clusterfuzzlite/requirements-atheris.txt +0 -0
  21. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.dockerignore +0 -0
  22. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.github/CODEOWNERS +0 -0
  23. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  24. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  25. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  26. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.github/dependabot.yml +0 -0
  27. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.github/workflows/ci.yml +0 -0
  28. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.github/workflows/codeql.yml +0 -0
  29. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.github/workflows/dependabot-uv-lock.yml +0 -0
  30. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.github/workflows/fuzz.yml +0 -0
  31. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.github/workflows/harness-smoke.yml +0 -0
  32. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.github/workflows/publish.yml +0 -0
  33. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.github/workflows/scorecard.yml +0 -0
  34. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.gitignore +0 -0
  35. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/.pre-commit-hooks.yaml +0 -0
  36. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/CONTRIBUTING.md +0 -0
  37. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/Dockerfile +0 -0
  38. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/LICENSE +0 -0
  39. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/SECURITY.md +0 -0
  40. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/index.html +0 -0
  41. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/package.json +0 -0
  42. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/pnpm-lock.yaml +0 -0
  43. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/public/apple-touch-icon.png +0 -0
  44. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
  45. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/public/brand/Logo_Whole.png +0 -0
  46. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/public/favicon-16x16.png +0 -0
  47. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/public/favicon-32x32.png +0 -0
  48. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/public/favicon.ico +0 -0
  49. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/src/app.tsx +0 -0
  50. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/src/approval-center-layout.tsx +0 -0
  51. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/src/approval-center-primitives.tsx +0 -0
  52. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/src/approval-center-utils.ts +0 -0
  53. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/src/fleet-workspace.tsx +0 -0
  54. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/src/guard-api.test.ts +0 -0
  55. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/src/guard-api.ts +0 -0
  56. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/src/guard-demo.ts +0 -0
  57. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/src/guard-types.ts +0 -0
  58. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/src/main.tsx +0 -0
  59. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/src/receipts-workspace.tsx +0 -0
  60. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/src/runtime-overview.tsx +0 -0
  61. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/src/settings-workspace.tsx +0 -0
  62. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/src/styles.css +0 -0
  63. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/src/vite-env.d.ts +0 -0
  64. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/tsconfig.json +0 -0
  65. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/dashboard/vite.config.ts +0 -0
  66. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/docker-requirements.txt +0 -0
  67. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/docs/guard/approval-audit.md +0 -0
  68. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/docs/guard/architecture.md +0 -0
  69. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/docs/guard/harness-support.md +0 -0
  70. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/docs/guard/local-vs-cloud.md +0 -0
  71. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/docs/trust/mcp-trust-draft.md +0 -0
  72. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/docs/trust/plugin-trust-draft.md +0 -0
  73. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/docs/trust/skill-trust-local.md +0 -0
  74. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/fuzzers/manifest_fuzzer.py +0 -0
  75. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/requirements.txt +0 -0
  76. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/schemas/plugin-quality.v1.json +0 -0
  77. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/schemas/scan-result.v1.json +0 -0
  78. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/schemas/verify-result.v1.json +0 -0
  79. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/__init__.py +0 -0
  80. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/action_runner.py +0 -0
  81. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/argparse_utils.py +0 -0
  82. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/checks/__init__.py +0 -0
  83. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
  84. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/checks/claude.py +0 -0
  85. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
  86. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
  87. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/checks/gemini.py +0 -0
  88. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/checks/manifest.py +0 -0
  89. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
  90. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
  91. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
  92. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/checks/opencode.py +0 -0
  93. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
  94. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/checks/security.py +0 -0
  95. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
  96. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/cli.py +0 -0
  97. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/cli_ui.py +0 -0
  98. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/config.py +0 -0
  99. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
  100. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
  101. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
  102. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
  103. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
  104. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
  105. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
  106. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
  107. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
  108. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/github_reporting.py +0 -0
  109. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/__init__.py +0 -0
  110. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
  111. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
  112. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
  113. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
  114. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +0 -0
  115. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
  116. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
  117. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
  118. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
  119. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
  120. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
  121. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
  122. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
  123. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
  124. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
  125. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
  126. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
  127. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/approvals.py +0 -0
  128. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
  129. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
  130. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
  131. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
  132. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
  133. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
  134. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
  135. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
  136. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
  137. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
  138. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
  139. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/config.py +0 -0
  140. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
  141. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
  142. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
  143. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
  144. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
  145. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
  146. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
  147. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
  148. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
  149. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
  150. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
  151. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
  152. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
  153. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
  154. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
  155. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/incident.py +0 -0
  156. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/launcher.py +0 -0
  157. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
  158. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/models.py +0 -0
  159. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
  160. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
  161. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/protect.py +0 -0
  162. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
  163. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
  164. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
  165. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
  166. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
  167. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
  168. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/redaction.py +0 -0
  169. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/risk.py +0 -0
  170. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
  171. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
  172. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
  173. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/runtime/detectors.py +0 -0
  174. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
  175. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
  176. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
  177. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
  178. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
  179. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
  180. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
  181. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
  182. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/shims.py +0 -0
  183. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/store.py +0 -0
  184. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
  185. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
  186. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/guard/types.py +0 -0
  187. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
  188. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
  189. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
  190. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/lint_fixes.py +0 -0
  191. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/marketplace_support.py +0 -0
  192. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/models.py +0 -0
  193. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/path_support.py +0 -0
  194. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/policy.py +0 -0
  195. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/quality_artifact.py +0 -0
  196. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/repo_detect.py +0 -0
  197. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/reporting.py +0 -0
  198. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/rules/__init__.py +0 -0
  199. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/rules/registry.py +0 -0
  200. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/rules/specs.py +0 -0
  201. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/scanner.py +0 -0
  202. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/submission.py +0 -0
  203. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/suppressions.py +0 -0
  204. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
  205. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/trust_helpers.py +0 -0
  206. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
  207. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/trust_models.py +0 -0
  208. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
  209. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/trust_scoring.py +0 -0
  210. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
  211. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/trust_specs.py +0 -0
  212. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/src/codex_plugin_scanner/verification.py +0 -0
  213. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/__init__.py +0 -0
  214. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/conftest.py +0 -0
  215. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/__init__.py +0 -0
  216. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
  217. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/bad-plugin/.mcp.json +0 -0
  218. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/bad-plugin/secrets.js +0 -0
  219. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
  220. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
  221. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/claude-plugin-good/README.md +0 -0
  222. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
  223. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
  224. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
  225. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/code-quality-bad/evil.js +0 -0
  226. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/code-quality-bad/inject.js +0 -0
  227. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
  228. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
  229. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/gemini-extension-good/README.md +0 -0
  230. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
  231. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
  232. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
  233. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
  234. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/good-plugin/.codexignore +0 -0
  235. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/good-plugin/LICENSE +0 -0
  236. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/good-plugin/README.md +0 -0
  237. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/good-plugin/SECURITY.md +0 -0
  238. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
  239. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
  240. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
  241. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
  242. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
  243. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
  244. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
  245. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
  246. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
  247. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
  248. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
  249. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
  250. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
  251. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
  252. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
  253. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
  254. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
  255. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
  256. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
  257. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/mcp-canary-server.py +0 -0
  258. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
  259. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
  260. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/mit-license/LICENSE +0 -0
  261. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
  262. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
  263. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
  264. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
  265. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
  266. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
  267. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
  268. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
  269. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
  270. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
  271. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
  272. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
  273. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
  274. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
  275. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
  276. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
  277. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
  278. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
  279. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/opencode-good/LICENSE +0 -0
  280. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/opencode-good/README.md +0 -0
  281. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/opencode-good/SECURITY.md +0 -0
  282. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
  283. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
  284. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
  285. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
  286. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
  287. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
  288. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/fixtures/with-marketplace/marketplace.json +0 -0
  289. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test-trust-scoring.py +0 -0
  290. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test-trust-specs.py +0 -0
  291. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_action_runner.py +0 -0
  292. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_best_practices.py +0 -0
  293. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_cisco_install_surfaces.py +0 -0
  294. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_code_quality.py +0 -0
  295. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_config.py +0 -0
  296. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_coverage_remaining.py +0 -0
  297. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_ecosystems.py +0 -0
  298. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_edge_cases.py +0 -0
  299. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_final_coverage.py +0 -0
  300. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_access_graph.py +0 -0
  301. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_approvals.py +0 -0
  302. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_bootstrap.py +0 -0
  303. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_capabilities.py +0 -0
  304. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_claude_adapter.py +0 -0
  305. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_codex_e2e.py +0 -0
  306. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_codex_install.py +0 -0
  307. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_codex_proxy.py +0 -0
  308. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_config_paths.py +0 -0
  309. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_connect_flow.py +0 -0
  310. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_consumer_mode.py +0 -0
  311. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_copilot_adapter.py +0 -0
  312. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_copilot_proxy.py +0 -0
  313. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_daemon_manager.py +0 -0
  314. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_event_schema_v1.py +0 -0
  315. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_events.py +0 -0
  316. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_launch_env.py +0 -0
  317. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_opencode_proxy.py +0 -0
  318. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_protect.py +0 -0
  319. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_render.py +0 -0
  320. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_runtime_action_harnesses.py +0 -0
  321. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_runtime_actions.py +0 -0
  322. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_runtime_decisions.py +0 -0
  323. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_runtime_detectors.py +0 -0
  324. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_runtime_signals.py +0 -0
  325. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_store_migrations.py +0 -0
  326. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_surface_server.py +0 -0
  327. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_guard_verdicts.py +0 -0
  328. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_hermes_adapter.py +0 -0
  329. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_integration.py +0 -0
  330. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_lint_fixes.py +0 -0
  331. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_live_cisco_smoke.py +0 -0
  332. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_manifest.py +0 -0
  333. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_marketplace.py +0 -0
  334. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_mcp_security.py +0 -0
  335. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_openclaw_adapter.py +0 -0
  336. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_operational_security.py +0 -0
  337. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_policy.py +0 -0
  338. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_quality_artifact.py +0 -0
  339. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_rule_registry.py +0 -0
  340. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_scanner.py +0 -0
  341. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_schema_contracts.py +0 -0
  342. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_security.py +0 -0
  343. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_security_ops.py +0 -0
  344. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_skill_security.py +0 -0
  345. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_submission.py +0 -0
  346. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_trust_scoring.py +0 -0
  347. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_trust_specs.py +0 -0
  348. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_verification.py +0 -0
  349. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/tests/test_versioning.py +0 -0
  350. {plugin_scanner-2.0.108 → plugin_scanner-2.0.110}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 2.0.108
3
+ Version: 2.0.110
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
@@ -302,33 +302,44 @@ The scanner evaluates only the surfaces a plugin actually exposes, then normaliz
302
302
 
303
303
  ```bash
304
304
  # Scan a plugin directory
305
- plugin-scanner ./my-plugin
305
+ plugin-scanner scan ./my-plugin
306
306
 
307
307
  # Auto-detect all supported ecosystems inside a repo (default)
308
- plugin-scanner ./plugins-repo --ecosystem auto
308
+ plugin-scanner scan ./plugins-repo --ecosystem auto
309
309
 
310
310
  # Scan only Claude package surfaces
311
- plugin-scanner ./plugins-repo --ecosystem claude
311
+ plugin-scanner scan ./plugins-repo --ecosystem claude
312
312
 
313
313
  # List supported ecosystems
314
314
  plugin-scanner --list-ecosystems
315
315
 
316
316
  # Output JSON
317
- plugin-scanner ./my-plugin --json
317
+ plugin-scanner scan ./my-plugin --format json
318
318
 
319
319
  # Write a SARIF report for GitHub code scanning
320
- plugin-scanner ./my-plugin --format sarif --output plugin-scanner.sarif
320
+ plugin-scanner scan ./my-plugin --format sarif --output plugin-scanner.sarif
321
321
 
322
322
  # Fail CI on findings at or above high severity
323
- plugin-scanner ./my-plugin --fail-on-severity high
323
+ plugin-scanner scan ./my-plugin --fail-on-severity high
324
324
 
325
325
  # Require Cisco skill scanning with a strict policy
326
- plugin-scanner ./my-plugin --cisco-skill-scan on --cisco-policy strict
326
+ plugin-scanner scan ./my-plugin --cisco-skill-scan on --cisco-policy strict
327
327
 
328
328
  # Require optional Cisco MCP static analysis
329
- plugin-scanner ./my-plugin --cisco-mcp-scan on
329
+ plugin-scanner scan ./my-plugin --cisco-mcp-scan on
330
330
  ```
331
331
 
332
+ Use the bare `plugin-scanner ./my-plugin` form only for compatibility with older automation. New scripts and docs should
333
+ prefer explicit subcommands so `scan`, `lint`, `verify`, `submit`, and `doctor` have predictable help, flags, and output.
334
+
335
+ | Need | Command | Output contract |
336
+ | :--- | :--- | :--- |
337
+ | Human release summary | `plugin-scanner scan ./my-plugin` | terminal summary first, optional JSON/Markdown/SARIF with `--format` |
338
+ | Rule-level authoring feedback | `plugin-scanner lint ./my-plugin` | human findings by default, JSON with `--format json` |
339
+ | Runtime readiness details | `plugin-scanner verify ./my-plugin` | human pass/fail by default, JSON with `--format json` |
340
+ | Publishable quality artifact | `plugin-scanner submit ./my-plugin --attest dist/plugin-quality.json` | writes one artifact for one plugin directory |
341
+ | Troubleshooting bundle | `plugin-scanner doctor ./my-plugin --component mcp --bundle dist/doctor.zip` | diagnostic JSON and bundle artifacts |
342
+
332
343
  ## Quality Suite Commands
333
344
 
334
345
  ```bash
@@ -262,33 +262,44 @@ The scanner evaluates only the surfaces a plugin actually exposes, then normaliz
262
262
 
263
263
  ```bash
264
264
  # Scan a plugin directory
265
- plugin-scanner ./my-plugin
265
+ plugin-scanner scan ./my-plugin
266
266
 
267
267
  # Auto-detect all supported ecosystems inside a repo (default)
268
- plugin-scanner ./plugins-repo --ecosystem auto
268
+ plugin-scanner scan ./plugins-repo --ecosystem auto
269
269
 
270
270
  # Scan only Claude package surfaces
271
- plugin-scanner ./plugins-repo --ecosystem claude
271
+ plugin-scanner scan ./plugins-repo --ecosystem claude
272
272
 
273
273
  # List supported ecosystems
274
274
  plugin-scanner --list-ecosystems
275
275
 
276
276
  # Output JSON
277
- plugin-scanner ./my-plugin --json
277
+ plugin-scanner scan ./my-plugin --format json
278
278
 
279
279
  # Write a SARIF report for GitHub code scanning
280
- plugin-scanner ./my-plugin --format sarif --output plugin-scanner.sarif
280
+ plugin-scanner scan ./my-plugin --format sarif --output plugin-scanner.sarif
281
281
 
282
282
  # Fail CI on findings at or above high severity
283
- plugin-scanner ./my-plugin --fail-on-severity high
283
+ plugin-scanner scan ./my-plugin --fail-on-severity high
284
284
 
285
285
  # Require Cisco skill scanning with a strict policy
286
- plugin-scanner ./my-plugin --cisco-skill-scan on --cisco-policy strict
286
+ plugin-scanner scan ./my-plugin --cisco-skill-scan on --cisco-policy strict
287
287
 
288
288
  # Require optional Cisco MCP static analysis
289
- plugin-scanner ./my-plugin --cisco-mcp-scan on
289
+ plugin-scanner scan ./my-plugin --cisco-mcp-scan on
290
290
  ```
291
291
 
292
+ Use the bare `plugin-scanner ./my-plugin` form only for compatibility with older automation. New scripts and docs should
293
+ prefer explicit subcommands so `scan`, `lint`, `verify`, `submit`, and `doctor` have predictable help, flags, and output.
294
+
295
+ | Need | Command | Output contract |
296
+ | :--- | :--- | :--- |
297
+ | Human release summary | `plugin-scanner scan ./my-plugin` | terminal summary first, optional JSON/Markdown/SARIF with `--format` |
298
+ | Rule-level authoring feedback | `plugin-scanner lint ./my-plugin` | human findings by default, JSON with `--format json` |
299
+ | Runtime readiness details | `plugin-scanner verify ./my-plugin` | human pass/fail by default, JSON with `--format json` |
300
+ | Publishable quality artifact | `plugin-scanner submit ./my-plugin --attest dist/plugin-quality.json` | writes one artifact for one plugin directory |
301
+ | Troubleshooting bundle | `plugin-scanner doctor ./my-plugin --component mcp --bundle dist/doctor.zip` | diagnostic JSON and bundle artifacts |
302
+
292
303
  ## Quality Suite Commands
293
304
 
294
305
  ```bash
@@ -76,6 +76,30 @@ Use it when you want to protect a harness before local MCP servers, skills, hook
76
76
  hol-guard device rotate
77
77
  ```
78
78
 
79
+ ## Which command should I use?
80
+
81
+ | Situation | Command | What it answers |
82
+ | :--- | :--- | :--- |
83
+ | I need the current protection posture | `hol-guard status` | What is Guard watching, is sync connected, and what is the next action? |
84
+ | I need setup or runtime troubleshooting | `hol-guard doctor <harness>` | Why is this harness or Guard runtime not behaving correctly? |
85
+ | A launch was blocked or changed | `hol-guard diff <harness>` | What changed since the last recorded snapshot? |
86
+ | I need to resolve a queued block | `hol-guard approvals` | Which requests are waiting, and how do I approve or deny them? |
87
+ | I need decision history | `hol-guard receipts` | What decisions did Guard record locally? |
88
+ | I need the tracked catalog | `hol-guard inventory` | Which artifacts are currently tracked and present? |
89
+ | I need an exportable evidence artifact | `hol-guard abom` | What local AI-BOM can I attach to an audit or handoff? |
90
+ | I need the chronological log | `hol-guard events` | What happened over time on this machine? |
91
+
92
+ ## Troubleshooting
93
+
94
+ | Symptom | Start here | Then try |
95
+ | :--- | :--- | :--- |
96
+ | Guard did not find my harness | `hol-guard detect --json` | `hol-guard doctor <harness> --json` for adapter-specific warnings |
97
+ | `hol-guard run` paused a launch | `hol-guard diff <harness>` | `hol-guard approvals`, then retry `hol-guard run <harness>` |
98
+ | I approved a prompt and want proof | `hol-guard receipts` | `hol-guard explain <artifact-id>` for the latest receipt and diff context |
99
+ | I need audit or handoff evidence | `hol-guard inventory` | `hol-guard abom --format json` for machine-readable export |
100
+ | I need to understand recent activity | `hol-guard events` | Use `--name <event>` to filter a noisy local timeline |
101
+ | Cloud sync or pairing looks wrong | `hol-guard status` | `hol-guard connect` or `hol-guard sync --json` depending on the status output |
102
+
79
103
  ## Evidence-first decisions
80
104
 
81
105
  Guard now scores local decisions from structured evidence, not only string heuristics. Each changed artifact carries:
@@ -10,6 +10,8 @@ Automated coverage in this phase includes:
10
10
  - consumer-mode JSON contract generation against scanner fixtures
11
11
  - local HTTP sync against a live in-process server instead of mocked transport
12
12
  - scheduled self-hosted harness smoke through `.github/workflows/harness-smoke.yml`
13
+ - CLI DX contract tests for summary-first `run`, `explain`, `doctor`, `scan`, `lint`, and `verify` output
14
+ - scanner command consistency tests for nonexistent target handling across `scan`, `lint`, `verify`, `doctor`, and `submit`
13
15
 
14
16
  Manual verification should include:
15
17
 
@@ -32,6 +34,14 @@ Manual verification should include:
32
34
  - `hol-guard install codex`
33
35
  - `hol-guard run codex --dry-run --default-action allow --json`
34
36
  - `hol-guard receipts`
37
+ - `hol-guard explain codex:project:<artifact-name>`
38
+ - `hol-guard diff codex`
39
+ - `hol-guard events`
40
+ - `hol-guard abom`
41
+ - `plugin-scanner scan tests/fixtures/good-plugin --format json`
42
+ - `plugin-scanner lint tests/fixtures/good-plugin --format json`
43
+ - `plugin-scanner verify tests/fixtures/good-plugin --format json`
44
+ - `plugin-scanner doctor tests/fixtures/good-plugin --component mcp --bundle dist/doctor.zip`
35
45
  - `codex mcp list`
36
46
  - `cursor-agent mcp list`
37
47
  - `antigravity --help`
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "plugin-scanner"
7
- version = "2.0.108"
7
+ version = "2.0.110"
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.108"
7
+ version = "2.0.110"
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"
@@ -97,7 +97,7 @@ from ..runtime.secret_file_requests import (
97
97
  extract_sensitive_tool_action_request,
98
98
  is_explicitly_benign_tool_action_request,
99
99
  )
100
- from ..runtime.secret_sensitivity import SecretContentMatch, classify_secret_content
100
+ from ..runtime.secret_sensitivity import SecretContentMatch, classify_secret_content, classify_secret_path
101
101
  from ..runtime.surface_server import GuardSurfaceRuntime
102
102
  from ..store import GuardStore
103
103
  from .approval_commands import add_approval_parser, run_approval_command
@@ -150,7 +150,15 @@ _GUARD_HELP_GROUPS = (
150
150
  " bootstrap Detect, install, and launch the approval center\n"
151
151
  " install Enable Guard management for a harness\n"
152
152
  " uninstall Disable Guard management for a harness\n"
153
- " update Update hol-guard in the current environment"
153
+ " update Update hol-guard in the current environment\n"
154
+ "\n"
155
+ "Command selection:\n"
156
+ " Use status for current posture and the next safe step\n"
157
+ " Use doctor for setup and runtime probes\n"
158
+ " Use diff for changed artifacts after a blocked launch\n"
159
+ " Use explain for detailed artifact evidence\n"
160
+ " Use approvals for queued decisions and receipts for audit history\n"
161
+ " Use events for the local timeline"
154
162
  )
155
163
 
156
164
 
@@ -2991,16 +2999,47 @@ def _runtime_stored_policy_action(
2991
2999
  def _runtime_artifact_policy_action(config: GuardConfig, artifact: GuardArtifact, harness: str) -> str:
2992
3000
  if _prompt_requires_hard_block(artifact):
2993
3001
  return "block"
2994
- risk_actions = [
2995
- resolve_risk_action(config, risk_class, harness=_canonical_harness_name(harness))
2996
- for risk_class in _runtime_artifact_risk_classes(artifact)
2997
- ]
3002
+ canonical_harness = _canonical_harness_name(harness)
3003
+ risk_classes = _runtime_artifact_risk_classes(artifact)
3004
+ has_configured_risk_action = any(
3005
+ _resolve_configured_risk_action(config, risk_class, harness=canonical_harness) for risk_class in risk_classes
3006
+ )
3007
+ if has_configured_risk_action:
3008
+ risk_actions = [
3009
+ _resolve_configured_risk_action(config, risk_class, harness=canonical_harness)
3010
+ or resolve_risk_action(config, risk_class, harness=canonical_harness)
3011
+ for risk_class in risk_classes
3012
+ ]
3013
+ resolved_actions = [action for action in risk_actions if action in VALID_GUARD_ACTIONS]
3014
+ if resolved_actions:
3015
+ return max(resolved_actions, key=_guard_action_severity)
3016
+ guard_default_action = _runtime_artifact_guard_default_action(artifact)
3017
+ if guard_default_action is not None:
3018
+ return guard_default_action
3019
+ risk_actions = [resolve_risk_action(config, risk_class, harness=canonical_harness) for risk_class in risk_classes]
2998
3020
  resolved_actions = [action for action in risk_actions if action in VALID_GUARD_ACTIONS]
2999
3021
  if resolved_actions:
3000
3022
  return max(resolved_actions, key=_guard_action_severity)
3001
3023
  return SAFE_CHANGED_HASH_ACTION
3002
3024
 
3003
3025
 
3026
+ def _resolve_configured_risk_action(config: GuardConfig, risk_class: str, *, harness: str) -> str | None:
3027
+ if config.harness_risk_actions is not None:
3028
+ harness_actions = config.harness_risk_actions.get(harness)
3029
+ if harness_actions is not None and risk_class in harness_actions:
3030
+ return harness_actions[risk_class]
3031
+ if config.risk_actions is not None and risk_class in config.risk_actions:
3032
+ return config.risk_actions[risk_class]
3033
+ return None
3034
+
3035
+
3036
+ def _runtime_artifact_guard_default_action(artifact: GuardArtifact) -> str | None:
3037
+ value = artifact.metadata.get("guard_default_action")
3038
+ if value in VALID_GUARD_ACTIONS:
3039
+ return str(value)
3040
+ return None
3041
+
3042
+
3004
3043
  def _guard_action_severity(action: str) -> int:
3005
3044
  return {
3006
3045
  "allow": 0,
@@ -3977,13 +4016,16 @@ def _codex_post_tool_output_artifact(
3977
4016
  cwd: Path | None,
3978
4017
  ) -> GuardArtifact | None:
3979
4018
  response_text = _collect_codex_tool_response_text(payload.get("tool_response"))
3980
- content_matches = classify_secret_content(response_text)
3981
- if not content_matches:
3982
- return None
3983
4019
  tool_name = _coalesce_string(payload.get("tool_name"), "Bash")
3984
4020
  command_text = _codex_post_tool_command_text(payload)
3985
4021
  if not command_text:
3986
4022
  command_text = tool_name
4023
+ references_local_content = _codex_command_may_read_local_content(command_text, cwd=cwd)
4024
+ content_matches = classify_secret_content(response_text)
4025
+ if not content_matches and references_local_content:
4026
+ content_matches = classify_secret_content(response_text, suppress_samples=False)
4027
+ if not content_matches:
4028
+ return None
3987
4029
  if _codex_source_inspection_can_skip_secret_output(
3988
4030
  command_text=command_text,
3989
4031
  response_text=response_text,
@@ -4001,6 +4043,10 @@ def _codex_post_tool_output_artifact(
4001
4043
  sort_keys=True,
4002
4044
  ).encode("utf-8")
4003
4045
  ).hexdigest()
4046
+ runtime_default_action = "require-reapproval" if references_local_content else "warn"
4047
+ runtime_request_signals = ["tool output contains credential-looking material"]
4048
+ if references_local_content:
4049
+ runtime_request_signals.append("command references a sensitive local source")
4004
4050
  return GuardArtifact(
4005
4051
  artifact_id=f"codex:{source_scope}:tool-output:{fingerprint}",
4006
4052
  name=f"{tool_name} credential-looking output",
@@ -4012,10 +4058,11 @@ def _codex_post_tool_output_artifact(
4012
4058
  "tool_name": tool_name,
4013
4059
  "command_text": command_text,
4014
4060
  "action_class": "credential exfiltration shell command",
4061
+ "guard_default_action": runtime_default_action,
4015
4062
  "request_summary": (
4016
4063
  f"Codex tool `{tool_name}` produced credential-looking output while running `{command_text}`."
4017
4064
  ),
4018
- "runtime_request_signals": ["tool output contains credential-looking material"],
4065
+ "runtime_request_signals": runtime_request_signals,
4019
4066
  "runtime_request_summary": (
4020
4067
  "Requests a sensitive native tool action: credential-looking output reached Codex."
4021
4068
  ),
@@ -4027,6 +4074,209 @@ def _codex_post_tool_output_artifact(
4027
4074
  )
4028
4075
 
4029
4076
 
4077
+ def _codex_command_references_sensitive_local_source(command_text: str, *, cwd: Path | None) -> bool:
4078
+ if _codex_text_contains_sensitive_path_token(command_text, cwd=cwd):
4079
+ return True
4080
+ try:
4081
+ parts = shlex.split(command_text)
4082
+ except ValueError:
4083
+ return False
4084
+ for part in parts:
4085
+ stripped = part.strip()
4086
+ if not stripped or stripped.startswith("-"):
4087
+ continue
4088
+ if _codex_token_is_url(stripped):
4089
+ continue
4090
+ if classify_secret_path(stripped, cwd=cwd) is not None:
4091
+ return True
4092
+ return False
4093
+
4094
+
4095
+ def _codex_token_is_url(token: str) -> bool:
4096
+ parsed = urllib.parse.urlparse(token)
4097
+ return bool(parsed.scheme and parsed.netloc)
4098
+
4099
+
4100
+ def _codex_text_contains_sensitive_path_token(text: str, *, cwd: Path | None) -> bool:
4101
+ for match in _PROMPT_PATH_TOKEN_PATTERN.finditer(text):
4102
+ if _codex_path_token_is_url_path(text, match.start()):
4103
+ continue
4104
+ if classify_secret_path(match.group(0), cwd=cwd) is not None:
4105
+ return True
4106
+ return False
4107
+
4108
+
4109
+ def _codex_path_token_is_url_path(text: str, start: int) -> bool:
4110
+ prefix = text[:start].lower()
4111
+ last_separator = max(prefix.rfind(separator) for separator in " \t\r\n'\"`<>|;(){}[]")
4112
+ token_prefix = prefix[last_separator + 1 :]
4113
+ if "://" in token_prefix:
4114
+ return True
4115
+ scheme = ""
4116
+ if token_prefix.endswith(":/"):
4117
+ scheme = token_prefix[:-2]
4118
+ elif token_prefix.endswith(":"):
4119
+ scheme = token_prefix[:-1]
4120
+ return _codex_token_prefix_is_url_scheme(scheme)
4121
+
4122
+
4123
+ def _codex_token_prefix_is_url_scheme(scheme: str) -> bool:
4124
+ return bool(scheme) and scheme[0].isalpha() and all(char.isalnum() or char in "+.-" for char in scheme)
4125
+
4126
+
4127
+ def _codex_command_may_read_local_content(command_text: str, *, cwd: Path | None) -> bool:
4128
+ if _codex_command_references_sensitive_local_source(command_text, cwd=cwd):
4129
+ return True
4130
+ if any(marker in command_text for marker in ("$(", "${", "`")):
4131
+ return True
4132
+ pipeline_segments = _split_codex_safe_read_only_pipeline(command_text)
4133
+ if pipeline_segments is not None:
4134
+ return any(
4135
+ _codex_pipeline_segment_may_read_local_content(segment, index=index, cwd=cwd)
4136
+ for index, segment in enumerate(pipeline_segments)
4137
+ )
4138
+ try:
4139
+ parts = _codex_shell_split(command_text)
4140
+ except ValueError:
4141
+ return True
4142
+ return _codex_command_parts_may_read_local_content(parts, cwd=cwd)
4143
+
4144
+
4145
+ def _codex_pipeline_segment_may_read_local_content(segment: str, *, index: int, cwd: Path | None) -> bool:
4146
+ try:
4147
+ parts = _codex_shell_split(segment)
4148
+ except ValueError:
4149
+ return True
4150
+ if not parts:
4151
+ return False
4152
+ if index == 0:
4153
+ return _codex_command_parts_may_read_local_content(parts, cwd=cwd)
4154
+ return _codex_command_is_read_only_source_search(segment, cwd=cwd) or _codex_command_is_read_only_source_view(
4155
+ segment, cwd=cwd
4156
+ )
4157
+
4158
+
4159
+ def _codex_command_parts_may_read_local_content(parts: list[str], *, cwd: Path | None) -> bool:
4160
+ for start in _codex_command_start_indexes(parts):
4161
+ previous_token = parts[start - 1] if start > 0 else None
4162
+ segment_parts = _codex_command_segment_parts(parts, start)
4163
+ if previous_token == "|":
4164
+ if _codex_command_sequence_is_read_only_source_inspection(segment_parts, cwd=cwd):
4165
+ return True
4166
+ continue
4167
+ if _codex_command_sequence_starts_with_local_reader(segment_parts, cwd=cwd):
4168
+ return True
4169
+ return False
4170
+
4171
+
4172
+ def _codex_command_start_indexes(parts: list[str]) -> list[int]:
4173
+ starts = [0] if parts else []
4174
+ for index, part in enumerate(parts[:-1]):
4175
+ if part in {"&&", "||", ";", "&", "|", "|&"}:
4176
+ starts.append(index + 1)
4177
+ return starts
4178
+
4179
+
4180
+ def _codex_command_segment_parts(parts: list[str], start: int) -> list[str]:
4181
+ end = start
4182
+ while end < len(parts) and parts[end] not in {"&&", "||", ";", "&", "|", "|&"}:
4183
+ end += 1
4184
+ return parts[start:end]
4185
+
4186
+
4187
+ def _codex_command_sequence_is_read_only_source_inspection(parts: list[str], *, cwd: Path | None) -> bool:
4188
+ command_parts = _codex_unwrapped_command_parts(parts)
4189
+ if not command_parts:
4190
+ return False
4191
+ segment = shlex.join(command_parts)
4192
+ return _codex_command_is_read_only_source_search(segment, cwd=cwd) or _codex_command_is_read_only_source_view(
4193
+ segment, cwd=cwd
4194
+ )
4195
+
4196
+
4197
+ def _codex_command_sequence_starts_with_local_reader(parts: list[str], *, cwd: Path | None) -> bool:
4198
+ command_parts = _codex_unwrapped_command_parts(parts)
4199
+ if not command_parts:
4200
+ return False
4201
+ if _codex_command_parts_are_git_grep(command_parts):
4202
+ return True
4203
+ return _codex_command_part_is_local_reader(command_parts, 0, cwd=cwd)
4204
+
4205
+
4206
+ def _codex_command_parts_are_git_grep(parts: list[str]) -> bool:
4207
+ return bool(parts) and Path(parts[0]).name.lower() == "git" and _git_grep_search_args(parts[1:]) is not None
4208
+
4209
+
4210
+ def _codex_unwrapped_command_parts(parts: list[str]) -> list[str]:
4211
+ remaining = parts
4212
+ while remaining:
4213
+ executable = Path(remaining[0]).name.lower()
4214
+ if executable == "command":
4215
+ remaining = _codex_strip_command_wrapper(remaining[1:])
4216
+ continue
4217
+ if executable == "env":
4218
+ remaining = _codex_strip_env_wrapper(remaining[1:])
4219
+ continue
4220
+ return remaining
4221
+ return []
4222
+
4223
+
4224
+ def _codex_strip_command_wrapper(parts: list[str]) -> list[str]:
4225
+ index = 0
4226
+ while index < len(parts) and parts[index] in {"-p", "-v", "-V"}:
4227
+ index += 1
4228
+ if index < len(parts) and parts[index] == "--":
4229
+ index += 1
4230
+ return parts[index:]
4231
+
4232
+
4233
+ def _codex_strip_env_wrapper(parts: list[str]) -> list[str]:
4234
+ index = 0
4235
+ while index < len(parts):
4236
+ part = parts[index]
4237
+ if part == "--":
4238
+ return parts[index + 1 :]
4239
+ if part in {"-i", "-0", "--ignore-environment", "--null"}:
4240
+ index += 1
4241
+ continue
4242
+ if part in {"-u", "--unset", "-C", "--chdir", "-S", "--split-string"}:
4243
+ index += 2
4244
+ continue
4245
+ if part.startswith(("--unset=", "--chdir=", "--split-string=")):
4246
+ index += 1
4247
+ continue
4248
+ if part.startswith("-"):
4249
+ index += 1
4250
+ continue
4251
+ if "=" in part and not part.startswith("="):
4252
+ index += 1
4253
+ continue
4254
+ return parts[index:]
4255
+ return []
4256
+
4257
+
4258
+ def _codex_shell_split(command_text: str) -> list[str]:
4259
+ lexer = shlex.shlex(command_text, posix=True, punctuation_chars=True)
4260
+ lexer.whitespace_split = True
4261
+ lexer.commenters = ""
4262
+ return list(lexer)
4263
+
4264
+
4265
+ def _codex_command_part_is_local_reader(parts: list[str], index: int, *, cwd: Path | None) -> bool:
4266
+ local_read_commands = {"cat", "grep", "head", "rg", "sed", "tail"}
4267
+ executable = Path(parts[index]).name.lower()
4268
+ if executable not in local_read_commands:
4269
+ return False
4270
+ if index == 0:
4271
+ return True
4272
+ if parts[index - 1] == "|":
4273
+ segment = shlex.join(parts[index:])
4274
+ return _codex_command_is_read_only_source_search(segment, cwd=cwd) or _codex_command_is_read_only_source_view(
4275
+ segment, cwd=cwd
4276
+ )
4277
+ return parts[index - 1] in {"&&", "||", ";", "&", "|&"}
4278
+
4279
+
4030
4280
  def _codex_post_tool_command_is_read_only_source_inspection(
4031
4281
  *,
4032
4282
  payload: dict[str, object],