plugin-scanner 2.0.110__tar.gz → 2.0.111__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.110 → plugin_scanner-2.0.111}/PKG-INFO +1 -1
  2. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/pyproject.toml +1 -1
  3. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/pyproject.toml.bak +1 -1
  4. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/cli/commands.py +152 -32
  5. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/cli/render.py +3 -0
  6. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/version.py +1 -1
  7. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_render.py +23 -5
  8. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_runtime.py +126 -0
  9. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.clusterfuzzlite/Dockerfile +0 -0
  10. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.clusterfuzzlite/build.sh +0 -0
  11. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.clusterfuzzlite/project.yaml +0 -0
  12. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.clusterfuzzlite/requirements-atheris.txt +0 -0
  13. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.dockerignore +0 -0
  14. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.github/CODEOWNERS +0 -0
  15. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  16. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  17. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  18. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.github/dependabot.yml +0 -0
  19. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.github/workflows/ci.yml +0 -0
  20. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.github/workflows/codeql.yml +0 -0
  21. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.github/workflows/dependabot-uv-lock.yml +0 -0
  22. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.github/workflows/fuzz.yml +0 -0
  23. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.github/workflows/harness-smoke.yml +0 -0
  24. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.github/workflows/publish.yml +0 -0
  25. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.github/workflows/scorecard.yml +0 -0
  26. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.gitignore +0 -0
  27. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/.pre-commit-hooks.yaml +0 -0
  28. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/CONTRIBUTING.md +0 -0
  29. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/Dockerfile +0 -0
  30. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/LICENSE +0 -0
  31. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/README.md +0 -0
  32. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/SECURITY.md +0 -0
  33. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/index.html +0 -0
  34. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/package.json +0 -0
  35. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/pnpm-lock.yaml +0 -0
  36. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/public/apple-touch-icon.png +0 -0
  37. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
  38. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/public/brand/Logo_Whole.png +0 -0
  39. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/public/favicon-16x16.png +0 -0
  40. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/public/favicon-32x32.png +0 -0
  41. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/public/favicon.ico +0 -0
  42. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/src/app.tsx +0 -0
  43. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/src/approval-center-layout.tsx +0 -0
  44. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/src/approval-center-primitives.tsx +0 -0
  45. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/src/approval-center-utils.ts +0 -0
  46. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/src/fleet-workspace.tsx +0 -0
  47. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/src/guard-api.test.ts +0 -0
  48. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/src/guard-api.ts +0 -0
  49. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/src/guard-demo.ts +0 -0
  50. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/src/guard-types.ts +0 -0
  51. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/src/main.tsx +0 -0
  52. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/src/receipts-workspace.tsx +0 -0
  53. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/src/runtime-overview.tsx +0 -0
  54. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/src/settings-workspace.tsx +0 -0
  55. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/src/styles.css +0 -0
  56. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/src/vite-env.d.ts +0 -0
  57. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/tsconfig.json +0 -0
  58. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/dashboard/vite.config.ts +0 -0
  59. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/docker-requirements.txt +0 -0
  60. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/docs/guard/approval-audit.md +0 -0
  61. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/docs/guard/architecture.md +0 -0
  62. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/docs/guard/get-started.md +0 -0
  63. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/docs/guard/harness-support.md +0 -0
  64. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/docs/guard/local-vs-cloud.md +0 -0
  65. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/docs/guard/testing-matrix.md +0 -0
  66. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/docs/trust/mcp-trust-draft.md +0 -0
  67. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/docs/trust/plugin-trust-draft.md +0 -0
  68. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/docs/trust/skill-trust-local.md +0 -0
  69. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/fuzzers/manifest_fuzzer.py +0 -0
  70. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/requirements.txt +0 -0
  71. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/schemas/plugin-quality.v1.json +0 -0
  72. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/schemas/scan-result.v1.json +0 -0
  73. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/schemas/verify-result.v1.json +0 -0
  74. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/__init__.py +0 -0
  75. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/action_runner.py +0 -0
  76. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/argparse_utils.py +0 -0
  77. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/checks/__init__.py +0 -0
  78. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
  79. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/checks/claude.py +0 -0
  80. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
  81. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
  82. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/checks/gemini.py +0 -0
  83. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/checks/manifest.py +0 -0
  84. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
  85. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
  86. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
  87. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/checks/opencode.py +0 -0
  88. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
  89. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/checks/security.py +0 -0
  90. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
  91. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/cli.py +0 -0
  92. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/cli_ui.py +0 -0
  93. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/config.py +0 -0
  94. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
  95. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
  96. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
  97. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
  98. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
  99. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
  100. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
  101. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
  102. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
  103. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/github_reporting.py +0 -0
  104. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/__init__.py +0 -0
  105. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
  106. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
  107. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
  108. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
  109. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +0 -0
  110. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
  111. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
  112. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
  113. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
  114. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
  115. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
  116. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
  117. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
  118. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
  119. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
  120. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
  121. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
  122. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/approvals.py +0 -0
  123. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
  124. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
  125. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
  126. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
  127. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
  128. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
  129. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
  130. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
  131. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
  132. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
  133. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
  134. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/config.py +0 -0
  135. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
  136. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
  137. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
  138. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
  139. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
  140. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
  141. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
  142. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
  143. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
  144. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
  145. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
  146. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
  147. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
  148. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
  149. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
  150. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
  151. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/incident.py +0 -0
  152. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/launcher.py +0 -0
  153. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
  154. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/models.py +0 -0
  155. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
  156. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
  157. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/protect.py +0 -0
  158. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
  159. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
  160. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
  161. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
  162. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
  163. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
  164. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/redaction.py +0 -0
  165. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/risk.py +0 -0
  166. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
  167. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
  168. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
  169. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/runtime/detectors.py +0 -0
  170. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
  171. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
  172. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/runtime/secret_sensitivity.py +0 -0
  173. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
  174. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
  175. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
  176. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
  177. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
  178. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
  179. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/shims.py +0 -0
  180. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/store.py +0 -0
  181. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
  182. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
  183. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/guard/types.py +0 -0
  184. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
  185. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
  186. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
  187. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/lint_fixes.py +0 -0
  188. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/marketplace_support.py +0 -0
  189. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/models.py +0 -0
  190. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/path_support.py +0 -0
  191. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/policy.py +0 -0
  192. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/quality_artifact.py +0 -0
  193. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/repo_detect.py +0 -0
  194. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/reporting.py +0 -0
  195. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/rules/__init__.py +0 -0
  196. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/rules/registry.py +0 -0
  197. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/rules/specs.py +0 -0
  198. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/scanner.py +0 -0
  199. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/submission.py +0 -0
  200. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/suppressions.py +0 -0
  201. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
  202. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/trust_helpers.py +0 -0
  203. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
  204. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/trust_models.py +0 -0
  205. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
  206. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/trust_scoring.py +0 -0
  207. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
  208. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/trust_specs.py +0 -0
  209. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/src/codex_plugin_scanner/verification.py +0 -0
  210. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/__init__.py +0 -0
  211. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/conftest.py +0 -0
  212. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/__init__.py +0 -0
  213. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
  214. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/bad-plugin/.mcp.json +0 -0
  215. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/bad-plugin/secrets.js +0 -0
  216. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
  217. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
  218. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/claude-plugin-good/README.md +0 -0
  219. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
  220. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
  221. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
  222. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/code-quality-bad/evil.js +0 -0
  223. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/code-quality-bad/inject.js +0 -0
  224. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
  225. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
  226. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/gemini-extension-good/README.md +0 -0
  227. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
  228. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
  229. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
  230. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
  231. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/good-plugin/.codexignore +0 -0
  232. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/good-plugin/LICENSE +0 -0
  233. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/good-plugin/README.md +0 -0
  234. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/good-plugin/SECURITY.md +0 -0
  235. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
  236. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
  237. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
  238. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
  239. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
  240. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
  241. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
  242. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
  243. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
  244. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
  245. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
  246. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
  247. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
  248. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
  249. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
  250. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
  251. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
  252. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
  253. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
  254. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/mcp-canary-server.py +0 -0
  255. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
  256. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
  257. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/mit-license/LICENSE +0 -0
  258. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
  259. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
  260. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
  261. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
  262. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
  263. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
  264. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
  265. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
  266. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
  267. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
  268. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
  269. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
  270. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
  271. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
  272. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
  273. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
  274. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
  275. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
  276. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/opencode-good/LICENSE +0 -0
  277. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/opencode-good/README.md +0 -0
  278. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/opencode-good/SECURITY.md +0 -0
  279. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
  280. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
  281. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
  282. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
  283. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
  284. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
  285. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/fixtures/with-marketplace/marketplace.json +0 -0
  286. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test-trust-scoring.py +0 -0
  287. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test-trust-specs.py +0 -0
  288. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_action_runner.py +0 -0
  289. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_best_practices.py +0 -0
  290. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_cisco_install_surfaces.py +0 -0
  291. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_cli.py +0 -0
  292. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_code_quality.py +0 -0
  293. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_config.py +0 -0
  294. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_coverage_remaining.py +0 -0
  295. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_ecosystems.py +0 -0
  296. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_edge_cases.py +0 -0
  297. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_final_coverage.py +0 -0
  298. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_access_graph.py +0 -0
  299. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_approvals.py +0 -0
  300. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_bootstrap.py +0 -0
  301. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_capabilities.py +0 -0
  302. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_claude_adapter.py +0 -0
  303. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_cli.py +0 -0
  304. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_codex_e2e.py +0 -0
  305. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_codex_install.py +0 -0
  306. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_codex_proxy.py +0 -0
  307. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_config_paths.py +0 -0
  308. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_connect_flow.py +0 -0
  309. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_consumer_mode.py +0 -0
  310. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_copilot_adapter.py +0 -0
  311. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_copilot_proxy.py +0 -0
  312. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_daemon_manager.py +0 -0
  313. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_event_schema_v1.py +0 -0
  314. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_events.py +0 -0
  315. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_launch_env.py +0 -0
  316. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_opencode_proxy.py +0 -0
  317. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_product_flow.py +0 -0
  318. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_protect.py +0 -0
  319. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_risk.py +0 -0
  320. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_runtime_action_harnesses.py +0 -0
  321. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_runtime_actions.py +0 -0
  322. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_runtime_decisions.py +0 -0
  323. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_runtime_detectors.py +0 -0
  324. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_runtime_signals.py +0 -0
  325. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_store_migrations.py +0 -0
  326. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_surface_server.py +0 -0
  327. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_guard_verdicts.py +0 -0
  328. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_hermes_adapter.py +0 -0
  329. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_integration.py +0 -0
  330. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_lint_fixes.py +0 -0
  331. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_live_cisco_smoke.py +0 -0
  332. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_manifest.py +0 -0
  333. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_marketplace.py +0 -0
  334. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_mcp_security.py +0 -0
  335. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_openclaw_adapter.py +0 -0
  336. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_operational_security.py +0 -0
  337. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_policy.py +0 -0
  338. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_quality_artifact.py +0 -0
  339. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_rule_registry.py +0 -0
  340. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_scanner.py +0 -0
  341. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_schema_contracts.py +0 -0
  342. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_security.py +0 -0
  343. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_security_ops.py +0 -0
  344. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_skill_security.py +0 -0
  345. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_submission.py +0 -0
  346. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_trust_scoring.py +0 -0
  347. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_trust_specs.py +0 -0
  348. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_verification.py +0 -0
  349. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/tests/test_versioning.py +0 -0
  350. {plugin_scanner-2.0.110 → plugin_scanner-2.0.111}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 2.0.110
3
+ Version: 2.0.111
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.110"
7
+ version = "2.0.111"
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.110"
7
+ version = "2.0.111"
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,12 @@ 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, classify_secret_path
100
+ from ..runtime.secret_sensitivity import (
101
+ SecretContentMatch,
102
+ SecretPathMatch,
103
+ classify_secret_content,
104
+ classify_secret_path,
105
+ )
101
106
  from ..runtime.surface_server import GuardSurfaceRuntime
102
107
  from ..store import GuardStore
103
108
  from .approval_commands import add_approval_parser, run_approval_command
@@ -3236,6 +3241,12 @@ def _runtime_artifact_native_reason(artifact: GuardArtifact, response_payload: d
3236
3241
  trimmed_summary = risk_summary.strip()
3237
3242
  if len(trimmed_summary) > 180:
3238
3243
  trimmed_summary = f"{trimmed_summary[:177].rstrip()}..."
3244
+ action_class = artifact.metadata.get("action_class")
3245
+ if (
3246
+ action_class == "credential exfiltration shell command"
3247
+ and "credential-looking output" not in trimmed_summary.lower()
3248
+ ):
3249
+ trimmed_summary = f"{trimmed_summary} Guard also detected credential-looking output."
3239
3250
  return f"HOL Guard flagged this request: {trimmed_summary}"
3240
3251
  return "HOL Guard flagged this request for review."
3241
3252
 
@@ -4020,7 +4031,10 @@ def _codex_post_tool_output_artifact(
4020
4031
  command_text = _codex_post_tool_command_text(payload)
4021
4032
  if not command_text:
4022
4033
  command_text = tool_name
4023
- references_local_content = _codex_command_may_read_local_content(command_text, cwd=cwd)
4034
+ local_source_matches = _codex_sensitive_local_source_matches(command_text, cwd=cwd)
4035
+ references_local_content = bool(local_source_matches) or _codex_command_may_read_local_content(
4036
+ command_text, cwd=cwd
4037
+ )
4024
4038
  content_matches = classify_secret_content(response_text)
4025
4039
  if not content_matches and references_local_content:
4026
4040
  content_matches = classify_secret_content(response_text, suppress_samples=False)
@@ -4043,10 +4057,38 @@ def _codex_post_tool_output_artifact(
4043
4057
  sort_keys=True,
4044
4058
  ).encode("utf-8")
4045
4059
  ).hexdigest()
4060
+ local_secret_source = _codex_local_secret_source_label(
4061
+ local_source_matches,
4062
+ command_text=command_text,
4063
+ )
4046
4064
  runtime_default_action = "require-reapproval" if references_local_content else "warn"
4047
4065
  runtime_request_signals = ["tool output contains credential-looking material"]
4048
4066
  if references_local_content:
4049
- runtime_request_signals.append("command references a sensitive local source")
4067
+ source_signal = "command references local secrets"
4068
+ if local_secret_source is not None:
4069
+ source_signal = f"command references local secrets from {local_secret_source}"
4070
+ runtime_request_signals.append(source_signal)
4071
+ request_summary = _codex_tool_output_request_summary(
4072
+ tool_name=tool_name,
4073
+ command_text=command_text,
4074
+ local_secret_source=local_secret_source,
4075
+ )
4076
+ runtime_request_summary = _codex_tool_output_runtime_summary(local_secret_source)
4077
+ metadata: dict[str, object] = {
4078
+ "tool_name": tool_name,
4079
+ "command_text": command_text,
4080
+ "action_class": "credential exfiltration shell command",
4081
+ "guard_default_action": runtime_default_action,
4082
+ "request_summary": request_summary,
4083
+ "runtime_request_signals": runtime_request_signals,
4084
+ "runtime_request_summary": runtime_request_summary,
4085
+ "runtime_request_reason": (
4086
+ "Guard inspects supported Codex tool output before Codex uses it, so accidental secret reads can be "
4087
+ "stopped even when the filename was not obviously sensitive."
4088
+ ),
4089
+ }
4090
+ if local_secret_source is not None:
4091
+ metadata["secret_source_family"] = local_secret_source
4050
4092
  return GuardArtifact(
4051
4093
  artifact_id=f"codex:{source_scope}:tool-output:{fingerprint}",
4052
4094
  name=f"{tool_name} credential-looking output",
@@ -4054,42 +4096,40 @@ def _codex_post_tool_output_artifact(
4054
4096
  artifact_type="tool_action_request",
4055
4097
  source_scope=source_scope,
4056
4098
  config_path=config_path,
4057
- metadata={
4058
- "tool_name": tool_name,
4059
- "command_text": command_text,
4060
- "action_class": "credential exfiltration shell command",
4061
- "guard_default_action": runtime_default_action,
4062
- "request_summary": (
4063
- f"Codex tool `{tool_name}` produced credential-looking output while running `{command_text}`."
4064
- ),
4065
- "runtime_request_signals": runtime_request_signals,
4066
- "runtime_request_summary": (
4067
- "Requests a sensitive native tool action: credential-looking output reached Codex."
4068
- ),
4069
- "runtime_request_reason": (
4070
- "Guard inspects supported Codex tool output before Codex uses it, so accidental secret reads can be "
4071
- "stopped even when the filename was not obviously sensitive."
4072
- ),
4073
- },
4099
+ metadata=metadata,
4074
4100
  )
4075
4101
 
4076
4102
 
4077
4103
  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
4104
+ return bool(_codex_sensitive_local_source_matches(command_text, cwd=cwd))
4105
+
4106
+
4107
+ def _codex_sensitive_local_source_matches(command_text: str, *, cwd: Path | None) -> list[SecretPathMatch]:
4108
+ matches = _codex_sensitive_path_matches_in_text(command_text, cwd=cwd)
4080
4109
  try:
4081
4110
  parts = shlex.split(command_text)
4082
4111
  except ValueError:
4083
- return False
4112
+ return matches
4084
4113
  for part in parts:
4085
4114
  stripped = part.strip()
4086
- if not stripped or stripped.startswith("-"):
4115
+ if not stripped or stripped.startswith("-") or _codex_token_is_url(stripped):
4087
4116
  continue
4088
- if _codex_token_is_url(stripped):
4117
+ path_match = classify_secret_path(stripped, cwd=cwd)
4118
+ if path_match is not None:
4119
+ matches.append(path_match)
4120
+ return _dedupe_codex_secret_path_matches(matches)
4121
+
4122
+
4123
+ def _dedupe_codex_secret_path_matches(matches: list[SecretPathMatch]) -> list[SecretPathMatch]:
4124
+ deduped: list[SecretPathMatch] = []
4125
+ seen: set[tuple[str, str]] = set()
4126
+ for match in matches:
4127
+ key = (match.family, match.requested_path or match.path)
4128
+ if key in seen:
4089
4129
  continue
4090
- if classify_secret_path(stripped, cwd=cwd) is not None:
4091
- return True
4092
- return False
4130
+ seen.add(key)
4131
+ deduped.append(match)
4132
+ return deduped
4093
4133
 
4094
4134
 
4095
4135
  def _codex_token_is_url(token: str) -> bool:
@@ -4098,12 +4138,18 @@ def _codex_token_is_url(token: str) -> bool:
4098
4138
 
4099
4139
 
4100
4140
  def _codex_text_contains_sensitive_path_token(text: str, *, cwd: Path | None) -> bool:
4141
+ return bool(_codex_sensitive_path_matches_in_text(text, cwd=cwd))
4142
+
4143
+
4144
+ def _codex_sensitive_path_matches_in_text(text: str, *, cwd: Path | None) -> list[SecretPathMatch]:
4145
+ matches: list[SecretPathMatch] = []
4101
4146
  for match in _PROMPT_PATH_TOKEN_PATTERN.finditer(text):
4102
4147
  if _codex_path_token_is_url_path(text, match.start()):
4103
4148
  continue
4104
- if classify_secret_path(match.group(0), cwd=cwd) is not None:
4105
- return True
4106
- return False
4149
+ path_match = classify_secret_path(match.group(0), cwd=cwd)
4150
+ if path_match is not None:
4151
+ matches.append(path_match)
4152
+ return matches
4107
4153
 
4108
4154
 
4109
4155
  def _codex_path_token_is_url_path(text: str, start: int) -> bool:
@@ -4150,7 +4196,10 @@ def _codex_pipeline_segment_may_read_local_content(segment: str, *, index: int,
4150
4196
  if not parts:
4151
4197
  return False
4152
4198
  if index == 0:
4153
- return _codex_command_parts_may_read_local_content(parts, cwd=cwd)
4199
+ return _codex_command_parts_are_environment_dump(parts) or _codex_command_parts_may_read_local_content(
4200
+ parts,
4201
+ cwd=cwd,
4202
+ )
4154
4203
  return _codex_command_is_read_only_source_search(segment, cwd=cwd) or _codex_command_is_read_only_source_view(
4155
4204
  segment, cwd=cwd
4156
4205
  )
@@ -4207,6 +4256,65 @@ def _codex_command_parts_are_git_grep(parts: list[str]) -> bool:
4207
4256
  return bool(parts) and Path(parts[0]).name.lower() == "git" and _git_grep_search_args(parts[1:]) is not None
4208
4257
 
4209
4258
 
4259
+ def _codex_command_reads_environment_pipeline(command_text: str) -> bool:
4260
+ pipeline_segments = _split_codex_safe_read_only_pipeline(command_text)
4261
+ if pipeline_segments is None:
4262
+ return False
4263
+ try:
4264
+ first_parts = _codex_shell_split(pipeline_segments[0])
4265
+ except ValueError:
4266
+ return False
4267
+ return _codex_command_parts_are_environment_dump(first_parts)
4268
+
4269
+
4270
+ def _codex_command_parts_are_environment_dump(parts: list[str]) -> bool:
4271
+ if not parts:
4272
+ return False
4273
+ executable = Path(parts[0]).name.lower()
4274
+ if executable == "printenv":
4275
+ return True
4276
+ if executable != "env":
4277
+ return False
4278
+ if _codex_env_args_clear_environment(parts[1:]):
4279
+ return False
4280
+ return not _codex_strip_env_wrapper(parts[1:])
4281
+
4282
+
4283
+ def _codex_local_secret_source_label(
4284
+ matches: list[SecretPathMatch],
4285
+ *,
4286
+ command_text: str,
4287
+ ) -> str | None:
4288
+ families: list[str] = []
4289
+ for match in matches:
4290
+ if match.family not in families:
4291
+ families.append(match.family)
4292
+ if families:
4293
+ if len(families) == 1:
4294
+ return families[0]
4295
+ return f"{families[0]} and other local secret files"
4296
+ if _codex_command_reads_environment_pipeline(command_text):
4297
+ return "environment variables"
4298
+ return None
4299
+
4300
+
4301
+ def _codex_tool_output_request_summary(
4302
+ *,
4303
+ tool_name: str,
4304
+ command_text: str,
4305
+ local_secret_source: str | None,
4306
+ ) -> str:
4307
+ if local_secret_source is not None:
4308
+ return f"Codex tool `{tool_name}` read local secrets from {local_secret_source} while running `{command_text}`."
4309
+ return f"Codex tool `{tool_name}` produced credential-looking output while running `{command_text}`."
4310
+
4311
+
4312
+ def _codex_tool_output_runtime_summary(local_secret_source: str | None) -> str:
4313
+ if local_secret_source is not None:
4314
+ return f"Local secrets from {local_secret_source} reached Codex tool output."
4315
+ return "Requests a sensitive native tool action: credential-looking output reached Codex."
4316
+
4317
+
4210
4318
  def _codex_unwrapped_command_parts(parts: list[str]) -> list[str]:
4211
4319
  remaining = parts
4212
4320
  while remaining:
@@ -4255,6 +4363,18 @@ def _codex_strip_env_wrapper(parts: list[str]) -> list[str]:
4255
4363
  return []
4256
4364
 
4257
4365
 
4366
+ def _codex_env_args_clear_environment(parts: list[str]) -> bool:
4367
+ for part in parts:
4368
+ if part == "--":
4369
+ return False
4370
+ if part in {"-i", "--ignore-environment"}:
4371
+ return True
4372
+ if part.startswith("-") or ("=" in part and not part.startswith("=")):
4373
+ continue
4374
+ return False
4375
+ return False
4376
+
4377
+
4258
4378
  def _codex_shell_split(command_text: str) -> list[str]:
4259
4379
  lexer = shlex.shlex(command_text, posix=True, punctuation_chars=True)
4260
4380
  lexer.whitespace_split = True
@@ -50,6 +50,7 @@ _SENSITIVE_STRING_PATTERNS: tuple[tuple[re.Pattern[str], str], ...] = (
50
50
  ),
51
51
  (re.compile(r"(?i)(authorization:\s*)(bearer\s+)?[^\s,;]+"), r"\1*****"),
52
52
  (re.compile(r"(?i)(api[-_ ]?key:\s*)[^\s,;]+"), r"\1*****"),
53
+ (re.compile(r"\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}\b"), "*****"),
53
54
  (re.compile(r"(?i)(bearer\s+)[^\s,;]+"), r"\1*****"),
54
55
  (re.compile(r"(?im)\b(?:_authToken|npm[_ -]?token)\s*[:=]\s*[^\s]+"), "npm token redacted"),
55
56
  (re.compile(r"\b(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqp)://[^\s]+", re.IGNORECASE), "*****"),
@@ -963,6 +964,8 @@ def _render_hook(console: Console, payload: dict[str, object]) -> None:
963
964
  body.add_row("Recorded", _bool_label(bool(payload.get("recorded"))))
964
965
  body.add_row("Artifact", str(payload.get("artifact_name") or payload.get("artifact_id") or "unknown"))
965
966
  body.add_row("Decision", _action_text(str(payload.get("policy_action", "warn"))))
967
+ if payload.get("risk_summary"):
968
+ body.add_row("Why", str(payload.get("risk_summary")))
966
969
  if payload.get("path_summary"):
967
970
  body.add_row("Path", str(payload.get("path_summary")))
968
971
  if payload.get("approval_center_url"):
@@ -1,3 +1,3 @@
1
1
  """Single source of truth for tool version."""
2
2
 
3
- __version__ = "2.0.110"
3
+ __version__ = "2.0.111"
@@ -79,11 +79,7 @@ def test_guard_json_render_redacts_after_command_specific_payload_shape(capsys)
79
79
 
80
80
 
81
81
  def test_guard_json_render_redacts_private_key_without_breaking_json(capsys) -> None:
82
- private_key = (
83
- "-----BEGIN PRIVATE KEY-----\n"
84
- "super-secret-material\n"
85
- "-----END PRIVATE KEY-----"
86
- )
82
+ private_key = "-----BEGIN PRIVATE KEY-----\nsuper-secret-material\n-----END PRIVATE KEY-----"
87
83
 
88
84
  emit_guard_payload("status", {"details": private_key}, True)
89
85
 
@@ -159,6 +155,28 @@ def test_guard_settings_json_omits_billing_flag(capsys) -> None:
159
155
  assert "billing" not in output["settings"]
160
156
 
161
157
 
158
+ def test_guard_hook_render_shows_local_secrets_without_internal_jargon(capsys) -> None:
159
+ raw_secret = "sk-" + "A" * 32
160
+
161
+ emit_guard_payload(
162
+ "hook",
163
+ {
164
+ "recorded": True,
165
+ "artifact_name": "Bash local secret output",
166
+ "policy_action": "require-reapproval",
167
+ "risk_summary": f"Local secrets from local .env file. {raw_secret}",
168
+ "path_summary": ".env",
169
+ },
170
+ False,
171
+ )
172
+
173
+ output = _normalize_render_output(capsys.readouterr().out)
174
+ assert "local secrets" in output.lower()
175
+ assert ".env file" in output
176
+ assert raw_secret not in output
177
+ assert "credential-looking output" not in output.lower()
178
+
179
+
162
180
  def test_guard_connect_render_defaults_sync_not_available_to_upgrade_guidance(capsys) -> None:
163
181
  emit_guard_payload(
164
182
  "connect",
@@ -1226,6 +1226,50 @@ clearer UX and an implementation plan with technical references.
1226
1226
  assert output["continue"] is False
1227
1227
  assert "credential-looking output" in output["stopReason"]
1228
1228
 
1229
+ def test_codex_post_tool_use_queues_secret_family_copy_for_local_secret_output(
1230
+ self,
1231
+ monkeypatch,
1232
+ tmp_path,
1233
+ capsys,
1234
+ ) -> None:
1235
+ home_dir = tmp_path / "home"
1236
+ workspace_dir = tmp_path / "workspace"
1237
+ _build_guard_fixture(home_dir, workspace_dir)
1238
+ raw_secret = "sk-" + "A" * 32
1239
+ event = {
1240
+ "event": "PostToolUse",
1241
+ "tool_name": "Bash",
1242
+ "tool_input": {"command": "cat .env"},
1243
+ "tool_response": {"stdout": f"OPENAI_API_KEY={raw_secret}\n"},
1244
+ "source_scope": "project",
1245
+ }
1246
+ monkeypatch.setenv("CODEX_HOME", str(home_dir / ".codex"))
1247
+ monkeypatch.setattr(guard_commands_module, "ensure_guard_daemon", lambda _guard_home: "http://127.0.0.1:4455")
1248
+ monkeypatch.setattr(sys, "stdin", io.StringIO(json.dumps(event)))
1249
+
1250
+ rc = main(
1251
+ [
1252
+ "guard",
1253
+ "hook",
1254
+ "--home",
1255
+ str(home_dir),
1256
+ "--workspace",
1257
+ str(workspace_dir),
1258
+ "--harness",
1259
+ "codex",
1260
+ "--json",
1261
+ ]
1262
+ )
1263
+ output = json.loads(capsys.readouterr().out)
1264
+ rendered = json.dumps(output)
1265
+ approval = output["approval_requests"][0]
1266
+
1267
+ assert rc == 1
1268
+ assert "local secrets" in approval["risk_summary"].lower()
1269
+ assert ".env file" in approval["risk_summary"]
1270
+ assert raw_secret not in rendered
1271
+ assert "credential-looking output" not in approval["risk_summary"].lower()
1272
+
1229
1273
  @pytest.mark.parametrize(
1230
1274
  "command",
1231
1275
  [
@@ -1678,6 +1722,88 @@ clearer UX and an implementation plan with technical references.
1678
1722
  assert output["artifact_type"] == "tool_action_request"
1679
1723
  assert output["approval_requests"]
1680
1724
 
1725
+ def test_codex_post_tool_use_asks_for_env_pipe_token_output_in_balanced(
1726
+ self,
1727
+ monkeypatch,
1728
+ tmp_path,
1729
+ capsys,
1730
+ ) -> None:
1731
+ home_dir = tmp_path / "home"
1732
+ workspace_dir = tmp_path / "workspace"
1733
+ _build_guard_fixture(home_dir, workspace_dir)
1734
+ event = {
1735
+ "event": "PostToolUse",
1736
+ "tool_name": "Bash",
1737
+ "tool_input": {"command": "env | grep TOKEN"},
1738
+ "tool_response": {
1739
+ "stdout": "OPENAI_API_KEY=sk-" + "A" * 32,
1740
+ },
1741
+ "source_scope": "project",
1742
+ }
1743
+ monkeypatch.setattr(sys, "stdin", io.StringIO(json.dumps(event)))
1744
+ monkeypatch.setattr(guard_commands_module, "ensure_guard_daemon", lambda _guard_home: "http://127.0.0.1:4455")
1745
+
1746
+ rc = main(
1747
+ [
1748
+ "guard",
1749
+ "hook",
1750
+ "--home",
1751
+ str(home_dir),
1752
+ "--workspace",
1753
+ str(workspace_dir),
1754
+ "--harness",
1755
+ "codex",
1756
+ "--json",
1757
+ ]
1758
+ )
1759
+ output = json.loads(capsys.readouterr().out)
1760
+
1761
+ assert rc == 1
1762
+ assert output["artifact_type"] == "tool_action_request"
1763
+ assert output["approval_requests"]
1764
+ assert "environment variables" in output["risk_summary"].lower()
1765
+
1766
+ @pytest.mark.parametrize("command", ["env -i | grep TOKEN", "env --ignore-environment | grep TOKEN"])
1767
+ def test_codex_post_tool_use_warns_for_cleared_env_pipe_token_output(
1768
+ self,
1769
+ monkeypatch,
1770
+ tmp_path,
1771
+ capsys,
1772
+ command,
1773
+ ) -> None:
1774
+ home_dir = tmp_path / "home"
1775
+ workspace_dir = tmp_path / "workspace"
1776
+ _build_guard_fixture(home_dir, workspace_dir)
1777
+ event = {
1778
+ "event": "PostToolUse",
1779
+ "tool_name": "Bash",
1780
+ "tool_input": {"command": command},
1781
+ "tool_response": {
1782
+ "stdout": "OPENAI_API_KEY=sk-" + "A" * 32,
1783
+ },
1784
+ "source_scope": "project",
1785
+ }
1786
+ monkeypatch.setattr(sys, "stdin", io.StringIO(json.dumps(event)))
1787
+
1788
+ rc = main(
1789
+ [
1790
+ "guard",
1791
+ "hook",
1792
+ "--home",
1793
+ str(home_dir),
1794
+ "--workspace",
1795
+ str(workspace_dir),
1796
+ "--harness",
1797
+ "codex",
1798
+ "--json",
1799
+ ]
1800
+ )
1801
+ output = json.loads(capsys.readouterr().out)
1802
+
1803
+ assert rc == 0
1804
+ assert output["policy_action"] == "warn"
1805
+ assert "approval_requests" not in output
1806
+
1681
1807
  @pytest.mark.parametrize(
1682
1808
  "command",
1683
1809
  [