plugin-scanner 2.0.135__tar.gz → 2.0.137__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.
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/PKG-INFO +1 -1
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/docs/guard/get-started.md +33 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/pyproject.toml +5 -1
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/pyproject.toml.bak +5 -1
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/cli/approval_commands.py +59 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/cli/commands.py +15 -1
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/cli/render.py +16 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/daemon/__init__.py +8 -1
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/daemon/manager.py +30 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/daemon/server.py +30 -1
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/version.py +1 -1
- plugin_scanner-2.0.137/tests/test_guard_approval_copy_commands.py +203 -0
- plugin_scanner-2.0.137/tests/test_guard_daemon_repair_perf.py +226 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_render.py +31 -0
- plugin_scanner-2.0.137/tests/test_guard_resolution_copy.py +146 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.clusterfuzzlite/Dockerfile +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.clusterfuzzlite/build.sh +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.clusterfuzzlite/project.yaml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.clusterfuzzlite/requirements-atheris.txt +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.dockerignore +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.github/CODEOWNERS +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.github/dependabot.yml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.github/workflows/ci.yml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.github/workflows/codeql.yml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.github/workflows/dependabot-uv-lock.yml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.github/workflows/fuzz.yml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.github/workflows/harness-smoke.yml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.github/workflows/publish.yml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.github/workflows/scorecard.yml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.gitignore +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/.pre-commit-hooks.yaml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/CONTRIBUTING.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/Dockerfile +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/LICENSE +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/README.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/SECURITY.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/index.html +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/package.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/pnpm-lock.yaml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/public/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/public/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/public/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/public/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/public/favicon.ico +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/app.tsx +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/approval-center-layout.test.ts +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/approval-center-layout.tsx +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/approval-center-primitives.tsx +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/approval-center-review-cards.tsx +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/approval-center-utils.ts +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/data-flow-evidence-card.tsx +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/fleet-workspace.tsx +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/guard-api.test.ts +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/guard-api.ts +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/guard-demo.ts +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/guard-types.ts +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/main.tsx +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/receipts-workspace.test.ts +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/receipts-workspace.tsx +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/runtime-overview.test.ts +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/runtime-overview.tsx +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/settings-workspace.test.ts +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/settings-workspace.tsx +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/styles.css +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/src/vite-env.d.ts +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/tsconfig.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/dashboard/vite.config.ts +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/docker-requirements.txt +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/docs/guard/approval-audit.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/docs/guard/architecture.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/docs/guard/harness-support.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/docs/guard/local-vs-cloud.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/docs/guard/release-checklist.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/docs/guard/smoke-tests.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/docs/guard/testing-matrix.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/docs/trust/mcp-trust-draft.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/docs/trust/plugin-trust-draft.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/docs/trust/skill-trust-local.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/fuzzers/manifest_fuzzer.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/requirements.txt +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/schemas/plugin-quality.v1.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/schemas/scan-result.v1.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/schemas/verify-result.v1.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/__init__.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/action_runner.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/argparse_utils.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/checks/__init__.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/checks/claude.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/checks/gemini.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/checks/manifest.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/checks/opencode.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/checks/security.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/cli.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/cli_ui.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/config.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/github_reporting.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/__init__.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/access_graph_events.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/adapters/contracts.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/approvals.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/config.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/incident.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/launcher.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/models.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/protect.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/redaction.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/risk.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/action_identity.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/advisory_escalation.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/advisory_matchers.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/data_flow.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/data_flow_rules.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/data_flow_variables.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/detectors.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/mcp_protection.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/prompt_injection.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/safe_decode.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/sandbox.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/secret_sensitivity.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/secret_sources.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/shell_commands.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/skill_protection.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/supply_chain.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/temp_files.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/runtime/threat_intel.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/shims.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/store.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/store_evidence.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/store_threat_intel.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/types.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/lint_fixes.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/marketplace_support.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/models.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/path_support.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/policy.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/quality_artifact.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/repo_detect.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/reporting.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/rules/__init__.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/rules/registry.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/rules/specs.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/scanner.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/submission.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/suppressions.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/trust_helpers.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/trust_models.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/trust_scoring.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/trust_specs.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/verification.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/__init__.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/conftest.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/__init__.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/bad-plugin/.mcp.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/bad-plugin/secrets.js +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/claude-plugin-good/README.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/code-quality-bad/evil.js +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/code-quality-bad/inject.js +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/gemini-extension-good/README.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/good-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/good-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/good-plugin/README.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/good-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/README.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/benign-docs-fake-token.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/benign-health-endpoint.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/benign-nvmrc-fake-creds.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/benign-source-search.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/canary-exfil-encoded.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/canary-exfil.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/expected-decisions.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/malicious-dockerfile.txt +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/malicious-encoded-shell-exfil.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/malicious-github-action.yml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/malicious-mcp-delete.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/malicious-mcp-secret-read.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/malicious-mcp-skill-exfil.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/malicious-npm-postinstall.js +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/malicious-prompt-env-read.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/malicious-prompt-guard-bypass.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/malicious-prompt-npmrc-read.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/malicious-python-setup.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/guard-red-team/smoke-evidence-template.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/mcp-canary-server.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/mit-license/LICENSE +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/opencode-good/LICENSE +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/opencode-good/README.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/opencode-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/supply-chain/benign-npm-package.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/supply-chain/benign-pnpm-package.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/supply-chain/benign-pyproject.toml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/supply-chain/malicious-Dockerfile +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/supply-chain/malicious-action.yml +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/supply-chain/malicious-npm-package.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/supply-chain/malicious-setup.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/fixtures/with-marketplace/marketplace.json +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test-trust-scoring.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test-trust-specs.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_action_runner.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_best_practices.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_cisco_install_surfaces.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_cli.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_code_quality.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_config.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_coverage_remaining.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_ecosystems.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_edge_cases.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_final_coverage.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_access_graph.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_action_identity.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_advisory_escalation.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_approval_continuity.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_approval_store_dedup.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_approval_store_scale.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_approvals.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_bootstrap.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_canary_fixtures.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_capabilities.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_claude_adapter.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_cli.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_cloud_local_sync.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_codex_e2e.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_codex_install.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_codex_proxy.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_config_paths.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_connect_flow.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_consumer_mode.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_copilot_adapter.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_copilot_proxy.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_daemon_manager.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_daemon_perf.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_data_flow.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_decision_propagation.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_event_schema_v1.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_events.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_evidence_store.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_harness_contracts.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_launch_env.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_mcp_protection.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_opencode_proxy.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_policy_dedup.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_product_flow.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_prompt_injection.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_protect.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_red_team.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_risk.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_runtime.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_runtime_action_harnesses.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_runtime_actions.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_runtime_decisions.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_runtime_detectors.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_runtime_signals.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_safe_decode.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_sandbox.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_skill_protection.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_store_migrations.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_supply_chain.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_surface_server.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_threat_intel.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_verdicts.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_guard_web_recovery.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_hermes_adapter.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_integration.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_lint_fixes.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_live_cisco_smoke.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_manifest.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_marketplace.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_mcp_security.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_openclaw_adapter.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_operational_security.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_policy.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_quality_artifact.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_rule_registry.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_scanner.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_schema_contracts.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_security.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_security_ops.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_skill_security.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_submission.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_trust_scoring.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_trust_specs.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_verification.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/tests/test_versioning.py +0 -0
- {plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: plugin-scanner
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.137
|
|
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
|
|
@@ -270,3 +270,36 @@ That means the user should never get a silent pass-through on a risky Codex acti
|
|
|
270
270
|
- native Bash deny plus HOL Guard approval-center recovery for sensitive shell actions
|
|
271
271
|
- same-chat approve or deny when Codex can render the inline MCP prompt
|
|
272
272
|
- explicit approval-center recovery when the session cannot
|
|
273
|
+
|
|
274
|
+
## Seamless approvals
|
|
275
|
+
|
|
276
|
+
When Guard blocks a launch, it opens a persistent approval link in the terminal rather than pausing the session. You can resolve requests without leaving your harness:
|
|
277
|
+
|
|
278
|
+
1. Guard returns the approval URL in the block output and queues the request locally.
|
|
279
|
+
2. Open the approval center at the URL or in your browser.
|
|
280
|
+
3. Approve or deny the request from the approval center UI or the CLI:
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
hol-guard approvals approve <request-id>
|
|
284
|
+
hol-guard approvals deny <request-id>
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
4. After you resolve the request, Guard emits copy telling you to return to your AI assistant and retry. No page reload or session restart is needed.
|
|
288
|
+
|
|
289
|
+
To inspect a pending request's details or get the approval URL, pass the request-id to the `approve` command with `--dry-run`, or visit the approval center URL shown in the block message directly.
|
|
290
|
+
|
|
291
|
+
## Troubleshooting
|
|
292
|
+
|
|
293
|
+
### Approval link says API error
|
|
294
|
+
|
|
295
|
+
If the approval center URL in a block message returns an API error, the local approval center locator may be stale.
|
|
296
|
+
Use the **Repair approval center** action in the Guard dashboard Settings tab, or call the repair endpoint directly when the daemon is running. The port shown in Guard's status output or the dashboard URL is your daemon port:
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
GUARD_PORT=$(hol-guard status --json 2>/dev/null | python3 -c "import json,sys; d=json.load(sys.stdin); print((d.get('runtime_state') or {}).get('daemon_port', d.get('daemon_port', 4781)))" 2>/dev/null || echo 4781)
|
|
300
|
+
curl -s -X POST "http://127.0.0.1:${GUARD_PORT}/v1/daemon/repair" \
|
|
301
|
+
-H "X-Guard-Token: $(cat ~/.hol-guard/daemon-auth-token)"
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
After repair, restart Guard, then retry the block message URL or relaunch your harness through Guard. Pending approval requests are preserved across repairs.
|
|
305
|
+
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "plugin-scanner"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.137"
|
|
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"
|
|
@@ -98,3 +98,7 @@ select = ["E", "F", "W", "I", "N", "UP", "B", "A", "SIM", "RUF"]
|
|
|
98
98
|
[tool.pytest.ini_options]
|
|
99
99
|
testpaths = ["tests"]
|
|
100
100
|
python_files = ["test_*.py"]
|
|
101
|
+
addopts = ["-m", "not slow"]
|
|
102
|
+
markers = [
|
|
103
|
+
"slow: marks tests as slow (deselected by default; run with -m slow to include)",
|
|
104
|
+
]
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "hol-guard"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.137"
|
|
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"
|
|
@@ -100,3 +100,7 @@ select = ["E", "F", "W", "I", "N", "UP", "B", "A", "SIM", "RUF"]
|
|
|
100
100
|
[tool.pytest.ini_options]
|
|
101
101
|
testpaths = ["tests"]
|
|
102
102
|
python_files = ["test_*.py"]
|
|
103
|
+
addopts = ["-m", "not slow"]
|
|
104
|
+
markers = [
|
|
105
|
+
"slow: marks tests as slow (deselected by default; run with -m slow to include)",
|
|
106
|
+
]
|
|
@@ -10,6 +10,19 @@ from ..approvals import apply_approval_resolution, build_runtime_snapshot
|
|
|
10
10
|
from ..daemon import load_guard_daemon_url
|
|
11
11
|
from ..store import GuardStore
|
|
12
12
|
|
|
13
|
+
_HARNESS_RETRY_COPY: dict[str, str] = {
|
|
14
|
+
"codex": "Return to Codex and retry",
|
|
15
|
+
"claude-code": "Return to Claude and retry",
|
|
16
|
+
"opencode": "Return to OpenCode and retry",
|
|
17
|
+
"copilot": "Return to Copilot and retry",
|
|
18
|
+
}
|
|
19
|
+
_DEFAULT_RETRY_COPY = "Return to your AI assistant and retry"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _build_retry_hint(action: str, harness: str) -> dict[str, str]:
|
|
23
|
+
title = "Approved. Retry in chat." if action == "allow" else "Blocked. Guard will remember this decision."
|
|
24
|
+
return {"title": title, "body": _HARNESS_RETRY_COPY.get(harness, _DEFAULT_RETRY_COPY)}
|
|
25
|
+
|
|
13
26
|
|
|
14
27
|
def add_approval_parser(
|
|
15
28
|
guard_subparsers: argparse._SubParsersAction[argparse.ArgumentParser],
|
|
@@ -57,6 +70,22 @@ def add_approval_parser(
|
|
|
57
70
|
add_common_args(clear_history_parser)
|
|
58
71
|
clear_history_parser.add_argument("--json", action="store_true")
|
|
59
72
|
|
|
73
|
+
open_parser = approvals_subparsers.add_parser(
|
|
74
|
+
"open",
|
|
75
|
+
help="Show the approval URL for a pending request",
|
|
76
|
+
)
|
|
77
|
+
open_parser.add_argument("request_id", help="The approval request ID to open")
|
|
78
|
+
add_common_args(open_parser)
|
|
79
|
+
open_parser.add_argument("--json", action="store_true")
|
|
80
|
+
|
|
81
|
+
retry_hint_parser = approvals_subparsers.add_parser(
|
|
82
|
+
"retry-hint",
|
|
83
|
+
help="Print the retry hint for a resolved approval request",
|
|
84
|
+
)
|
|
85
|
+
retry_hint_parser.add_argument("request_id", help="The approval request ID to get the retry hint for")
|
|
86
|
+
add_common_args(retry_hint_parser)
|
|
87
|
+
retry_hint_parser.add_argument("--json", action="store_true")
|
|
88
|
+
|
|
60
89
|
|
|
61
90
|
def run_approval_command(
|
|
62
91
|
args: argparse.Namespace,
|
|
@@ -115,5 +144,35 @@ def run_approval_command(
|
|
|
115
144
|
return {"resolved": True, "item": item}
|
|
116
145
|
|
|
117
146
|
|
|
147
|
+
def run_approval_open_command(
|
|
148
|
+
args: argparse.Namespace,
|
|
149
|
+
*,
|
|
150
|
+
store: GuardStore,
|
|
151
|
+
) -> tuple[dict[str, object], int]:
|
|
152
|
+
request_id = args.request_id
|
|
153
|
+
item = store.get_approval_request(request_id)
|
|
154
|
+
if item is None:
|
|
155
|
+
return {"error": "not_found", "request_id": request_id}, 1
|
|
156
|
+
return {"request_id": request_id, "approval_url": str(item.get("approval_url", ""))}, 0
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def run_approval_retry_hint_command(
|
|
160
|
+
args: argparse.Namespace,
|
|
161
|
+
*,
|
|
162
|
+
store: GuardStore,
|
|
163
|
+
) -> tuple[dict[str, object], int]:
|
|
164
|
+
request_id = args.request_id
|
|
165
|
+
item = store.get_approval_request(request_id)
|
|
166
|
+
if item is None:
|
|
167
|
+
return {"error": "not_found", "request_id": request_id}, 1
|
|
168
|
+
status = str(item.get("status", ""))
|
|
169
|
+
if status != "resolved":
|
|
170
|
+
return {"error": "not_resolved", "status": status, "request_id": request_id}, 1
|
|
171
|
+
resolution_action = str(item.get("resolution_action", ""))
|
|
172
|
+
harness = str(item.get("harness", ""))
|
|
173
|
+
hint: dict[str, object] = dict(_build_retry_hint(resolution_action, harness))
|
|
174
|
+
return hint, 0
|
|
175
|
+
|
|
176
|
+
|
|
118
177
|
def _now() -> str:
|
|
119
178
|
return datetime.now(timezone.utc).isoformat()
|
{plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/cli/commands.py
RENAMED
|
@@ -109,7 +109,12 @@ from ..runtime.secret_sensitivity import (
|
|
|
109
109
|
from ..runtime.signals import RiskSignalV2
|
|
110
110
|
from ..runtime.surface_server import GuardSurfaceRuntime
|
|
111
111
|
from ..store import GuardStore
|
|
112
|
-
from .approval_commands import
|
|
112
|
+
from .approval_commands import (
|
|
113
|
+
add_approval_parser,
|
|
114
|
+
run_approval_command,
|
|
115
|
+
run_approval_open_command,
|
|
116
|
+
run_approval_retry_hint_command,
|
|
117
|
+
)
|
|
113
118
|
from .bootstrap import DEFAULT_ALIAS_NAME, build_guard_bootstrap_payload
|
|
114
119
|
from .connect_flow import (
|
|
115
120
|
DEFAULT_GUARD_CONNECT_URL,
|
|
@@ -1152,6 +1157,15 @@ def run_guard_command(
|
|
|
1152
1157
|
return 0
|
|
1153
1158
|
|
|
1154
1159
|
if args.guard_command == "approvals":
|
|
1160
|
+
approvals_command = getattr(args, "approvals_command", None)
|
|
1161
|
+
if approvals_command == "open":
|
|
1162
|
+
payload, exit_code = run_approval_open_command(args, store=store)
|
|
1163
|
+
_emit("approvals", payload, getattr(args, "json", False))
|
|
1164
|
+
return exit_code
|
|
1165
|
+
if approvals_command == "retry-hint":
|
|
1166
|
+
payload, exit_code = run_approval_retry_hint_command(args, store=store)
|
|
1167
|
+
_emit("approvals", payload, getattr(args, "json", False))
|
|
1168
|
+
return exit_code
|
|
1155
1169
|
payload = run_approval_command(args, store=store, workspace=workspace)
|
|
1156
1170
|
_emit("approvals", payload, getattr(args, "json", False))
|
|
1157
1171
|
return int(payload.get("exit_code", 0))
|
{plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/cli/render.py
RENAMED
|
@@ -566,6 +566,22 @@ def _render_events(console: Console, payload: dict[str, object]) -> None:
|
|
|
566
566
|
|
|
567
567
|
|
|
568
568
|
def _render_approvals(console: Console, payload: dict[str, object]) -> None:
|
|
569
|
+
approval_url = payload.get("approval_url")
|
|
570
|
+
if isinstance(approval_url, str) and approval_url:
|
|
571
|
+
body = Table.grid(padding=(0, 1))
|
|
572
|
+
body.add_row("Request", str(payload.get("request_id", "")))
|
|
573
|
+
body.add_row("URL", f"[bold]{approval_url}[/bold]")
|
|
574
|
+
console.print(Panel(body, title="Open approval", border_style="cyan"))
|
|
575
|
+
return
|
|
576
|
+
if "title" in payload and "body" in payload:
|
|
577
|
+
body = Table.grid(padding=(0, 1))
|
|
578
|
+
body.add_row("Status", str(payload["title"]))
|
|
579
|
+
body.add_row("Next step", str(payload["body"]))
|
|
580
|
+
console.print(Panel(body, title="Approval resolved", border_style="green"))
|
|
581
|
+
return
|
|
582
|
+
if payload.get("error"):
|
|
583
|
+
console.print(Panel(str(payload.get("error")), title="Approval error", border_style="red"))
|
|
584
|
+
return
|
|
569
585
|
if "history_cleared" in payload or "cleared_policies" in payload:
|
|
570
586
|
error = payload.get("error")
|
|
571
587
|
body = Table.grid(padding=(0, 1))
|
{plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/daemon/__init__.py
RENAMED
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from .manager import
|
|
5
|
+
from .manager import (
|
|
6
|
+
ensure_guard_daemon,
|
|
7
|
+
guard_daemon_url_for_home,
|
|
8
|
+
load_guard_daemon_auth_token,
|
|
9
|
+
load_guard_daemon_url,
|
|
10
|
+
repair_approval_center_locator,
|
|
11
|
+
)
|
|
6
12
|
|
|
7
13
|
__all__ = [
|
|
8
14
|
"GuardDaemonServer",
|
|
@@ -12,6 +18,7 @@ __all__ = [
|
|
|
12
18
|
"load_guard_daemon_auth_token",
|
|
13
19
|
"load_guard_daemon_url",
|
|
14
20
|
"load_guard_surface_daemon_client",
|
|
21
|
+
"repair_approval_center_locator",
|
|
15
22
|
]
|
|
16
23
|
|
|
17
24
|
|
{plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/daemon/manager.py
RENAMED
|
@@ -187,6 +187,36 @@ def clear_guard_daemon_state(guard_home: Path) -> None:
|
|
|
187
187
|
_write_private_text(state_path, "{}")
|
|
188
188
|
|
|
189
189
|
|
|
190
|
+
def repair_approval_center_locator(guard_home: Path) -> dict[str, object]:
|
|
191
|
+
"""Remove a stale approval center locator and optionally clear dead daemon state.
|
|
192
|
+
|
|
193
|
+
Only clears daemon-state.json when the recorded PID is no longer running,
|
|
194
|
+
so a live daemon's state is not disturbed. Raises OSError if a required
|
|
195
|
+
write fails so callers can detect incomplete repair.
|
|
196
|
+
|
|
197
|
+
Safe to call while the database is live. Returns a dict describing what was cleared.
|
|
198
|
+
"""
|
|
199
|
+
cleared: list[str] = []
|
|
200
|
+
locator = _locator_path(guard_home)
|
|
201
|
+
if locator.is_file():
|
|
202
|
+
locator.unlink()
|
|
203
|
+
cleared.append("locator")
|
|
204
|
+
state = _state_path(guard_home)
|
|
205
|
+
if state.is_file():
|
|
206
|
+
state_payload = _load_state(guard_home)
|
|
207
|
+
pid = state_payload.get("pid") if isinstance(state_payload, dict) else None
|
|
208
|
+
daemon_is_live = (
|
|
209
|
+
isinstance(pid, int)
|
|
210
|
+
and pid > 0
|
|
211
|
+
and _guard_daemon_pid_is_running(pid)
|
|
212
|
+
and _guard_daemon_pid_matches_command(pid, expected_guard_home=guard_home)
|
|
213
|
+
)
|
|
214
|
+
if not daemon_is_live:
|
|
215
|
+
_write_private_text(state, "{}")
|
|
216
|
+
cleared.append("daemon_state")
|
|
217
|
+
return {"repaired": True, "cleared": cleared}
|
|
218
|
+
|
|
219
|
+
|
|
190
220
|
def _locator_path(guard_home: Path) -> Path:
|
|
191
221
|
return guard_home / _APPROVAL_CENTER_LOCATOR_FILE
|
|
192
222
|
|
{plugin_scanner-2.0.135 → plugin_scanner-2.0.137}/src/codex_plugin_scanner/guard/daemon/server.py
RENAMED
|
@@ -38,6 +38,7 @@ from .manager import (
|
|
|
38
38
|
GUARD_DAEMON_COMPATIBILITY_VERSION,
|
|
39
39
|
clear_guard_daemon_state,
|
|
40
40
|
load_guard_daemon_auth_token,
|
|
41
|
+
repair_approval_center_locator,
|
|
41
42
|
write_guard_daemon_state,
|
|
42
43
|
)
|
|
43
44
|
|
|
@@ -401,6 +402,10 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
|
|
|
401
402
|
if parsed.path == "/v1/settings":
|
|
402
403
|
self._handle_settings_update(payload)
|
|
403
404
|
return
|
|
405
|
+
if parsed.path == "/v1/daemon/repair":
|
|
406
|
+
result = repair_approval_center_locator(self.server.store.guard_home) # type: ignore[attr-defined]
|
|
407
|
+
self._write_json(result)
|
|
408
|
+
return
|
|
404
409
|
request_id, action, matched = self._resolve_request_action(path_parts, payload)
|
|
405
410
|
if not matched:
|
|
406
411
|
self.send_response(404)
|
|
@@ -456,7 +461,15 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
|
|
|
456
461
|
except ValueError as error:
|
|
457
462
|
self._write_json({"resolved": False, "error": str(error)}, status=400)
|
|
458
463
|
return
|
|
459
|
-
|
|
464
|
+
normalized_scope = scope.strip()
|
|
465
|
+
harness_str = str(updated.get("harness", ""))
|
|
466
|
+
self.server.store.add_event( # type: ignore[attr-defined]
|
|
467
|
+
"approval_resolved",
|
|
468
|
+
{"request_id": request_id, "action": action, "scope": normalized_scope, "harness": harness_str},
|
|
469
|
+
_now(),
|
|
470
|
+
)
|
|
471
|
+
harness = str(updated.get("harness", ""))
|
|
472
|
+
self._write_json({"resolved": True, "item": updated, "copy": _build_resolution_copy(action, harness)})
|
|
460
473
|
|
|
461
474
|
def log_message(self, fmt: str, *args: Any) -> None:
|
|
462
475
|
return
|
|
@@ -988,6 +1001,7 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
|
|
|
988
1001
|
if path in {
|
|
989
1002
|
"/v1/inventory",
|
|
990
1003
|
"/v1/connect/state",
|
|
1004
|
+
"/v1/daemon/repair",
|
|
991
1005
|
"/v1/evidence",
|
|
992
1006
|
"/v1/evidence/export",
|
|
993
1007
|
"/v1/policy",
|
|
@@ -1159,6 +1173,7 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
|
|
|
1159
1173
|
"/v1/policy/decisions",
|
|
1160
1174
|
"/v1/policy/clear",
|
|
1161
1175
|
"/v1/settings",
|
|
1176
|
+
"/v1/daemon/repair",
|
|
1162
1177
|
}:
|
|
1163
1178
|
return True
|
|
1164
1179
|
if len(path_parts) == 4 and path_parts[:2] == ["v1", "operations"] and path_parts[3] in {"items", "status"}:
|
|
@@ -1388,6 +1403,20 @@ def _build_local_url(host: str, port: int, path: str) -> str:
|
|
|
1388
1403
|
return f"http://{host_part}:{port}{path}"
|
|
1389
1404
|
|
|
1390
1405
|
|
|
1406
|
+
_HARNESS_RETRY_COPY: dict[str, str] = {
|
|
1407
|
+
"codex": "Return to Codex and retry",
|
|
1408
|
+
"claude-code": "Return to Claude and retry",
|
|
1409
|
+
"opencode": "Return to OpenCode and retry",
|
|
1410
|
+
"copilot": "Return to Copilot and retry",
|
|
1411
|
+
}
|
|
1412
|
+
_DEFAULT_RETRY_COPY = "Return to your AI assistant and retry"
|
|
1413
|
+
|
|
1414
|
+
|
|
1415
|
+
def _build_resolution_copy(action: str, harness: str) -> dict[str, str]:
|
|
1416
|
+
title = "Approved. Retry in chat." if action == "allow" else "Blocked. Guard will remember this decision."
|
|
1417
|
+
return {"title": title, "body": _HARNESS_RETRY_COPY.get(harness, _DEFAULT_RETRY_COPY)}
|
|
1418
|
+
|
|
1419
|
+
|
|
1391
1420
|
def _now() -> str:
|
|
1392
1421
|
from datetime import datetime, timezone
|
|
1393
1422
|
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"""Tests for T732-T737: harness copy rule and approval CLI commands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from codex_plugin_scanner.cli import main
|
|
11
|
+
from codex_plugin_scanner.guard.adapters.base import HarnessContext
|
|
12
|
+
from codex_plugin_scanner.guard.approvals import approval_center_hint
|
|
13
|
+
from codex_plugin_scanner.guard.models import GuardApprovalRequest
|
|
14
|
+
from codex_plugin_scanner.guard.store import GuardStore
|
|
15
|
+
|
|
16
|
+
_KNOWN_HARNESSES = ["codex", "claude-code", "opencode", "copilot", "gemini"]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _make_queue_item(harness: str, request_id: str) -> dict:
|
|
20
|
+
return {
|
|
21
|
+
"request_id": request_id,
|
|
22
|
+
"harness": harness,
|
|
23
|
+
"artifact_id": f"{harness}:project:tool",
|
|
24
|
+
"artifact_name": "Test tool",
|
|
25
|
+
"policy_action": "block",
|
|
26
|
+
"recommended_scope": "artifact",
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _make_request(
|
|
31
|
+
*,
|
|
32
|
+
request_id: str,
|
|
33
|
+
harness: str = "codex",
|
|
34
|
+
status: str = "pending",
|
|
35
|
+
) -> GuardApprovalRequest:
|
|
36
|
+
return GuardApprovalRequest(
|
|
37
|
+
request_id=request_id,
|
|
38
|
+
harness=harness,
|
|
39
|
+
artifact_id=f"{harness}:project:tool",
|
|
40
|
+
artifact_name="Test tool",
|
|
41
|
+
artifact_hash="hash-abc",
|
|
42
|
+
policy_action="require-reapproval",
|
|
43
|
+
recommended_scope="artifact",
|
|
44
|
+
changed_fields=("tool_action_request",),
|
|
45
|
+
source_scope="project",
|
|
46
|
+
config_path="/tmp/config.toml",
|
|
47
|
+
review_command=f"hol-guard approvals approve {request_id}",
|
|
48
|
+
approval_url=f"http://127.0.0.1:5474/approvals/{request_id}",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class TestHarnessBlockMessageCopyRule:
|
|
53
|
+
"""T732: harness block messages must never tell users to run 'hol-guard dashboard' as primary path."""
|
|
54
|
+
|
|
55
|
+
@pytest.mark.parametrize("harness", _KNOWN_HARNESSES)
|
|
56
|
+
def test_approval_center_hint_does_not_require_manual_dashboard_launch(
|
|
57
|
+
self, tmp_path: Path, harness: str
|
|
58
|
+
) -> None:
|
|
59
|
+
"""T732: approval_center_hint must not instruct users to run 'hol-guard dashboard'."""
|
|
60
|
+
context = HarnessContext(
|
|
61
|
+
home_dir=tmp_path,
|
|
62
|
+
guard_home=tmp_path / ".hol-guard",
|
|
63
|
+
workspace_dir=tmp_path / "workspace",
|
|
64
|
+
)
|
|
65
|
+
queued = [_make_queue_item(harness, "req-rule-01")]
|
|
66
|
+
hint = approval_center_hint(
|
|
67
|
+
context=context,
|
|
68
|
+
harness=harness,
|
|
69
|
+
approval_center_url="http://127.0.0.1:5474",
|
|
70
|
+
queued=queued,
|
|
71
|
+
)
|
|
72
|
+
assert "hol-guard dashboard" not in hint, (
|
|
73
|
+
f"Harness hint for '{harness}' must not tell users to run 'hol-guard dashboard' as primary path. "
|
|
74
|
+
f"Got: {hint!r}"
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class TestBlockMessageNoDashboardLaunchRequired:
|
|
79
|
+
"""T733: CLI block message must not require manual dashboard launch."""
|
|
80
|
+
|
|
81
|
+
def test_block_approval_center_hint_no_manual_dashboard_command(self, tmp_path: Path) -> None:
|
|
82
|
+
"""T733: block flow copy does not contain 'hol-guard dashboard' for any harness."""
|
|
83
|
+
context = HarnessContext(
|
|
84
|
+
home_dir=tmp_path,
|
|
85
|
+
guard_home=tmp_path / ".hol-guard",
|
|
86
|
+
workspace_dir=tmp_path / "workspace",
|
|
87
|
+
)
|
|
88
|
+
for harness in _KNOWN_HARNESSES:
|
|
89
|
+
queued = [_make_queue_item(harness, f"req-t733-{harness}")]
|
|
90
|
+
hint = approval_center_hint(
|
|
91
|
+
context=context,
|
|
92
|
+
harness=harness,
|
|
93
|
+
approval_center_url="http://127.0.0.1:5474",
|
|
94
|
+
queued=queued,
|
|
95
|
+
)
|
|
96
|
+
assert "hol-guard dashboard" not in hint, (
|
|
97
|
+
f"CLI block message for '{harness}' must not say 'hol-guard dashboard'. Got: {hint!r}"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class TestApprovalsOpenCommand:
|
|
102
|
+
"""T734-T735: 'hol-guard approvals open <request_id>' command."""
|
|
103
|
+
|
|
104
|
+
def test_approvals_open_returns_approval_url_for_known_request(self, tmp_path: Path, capsys) -> None:
|
|
105
|
+
"""T734: approvals open prints the approval URL for an existing pending request."""
|
|
106
|
+
home_dir = tmp_path / "guard-home"
|
|
107
|
+
store = GuardStore(home_dir)
|
|
108
|
+
store.add_approval_request(_make_request(request_id="req-open-01"), "2026-01-01T00:00:00Z")
|
|
109
|
+
|
|
110
|
+
rc = main(["guard", "approvals", "open", "req-open-01", "--home", str(home_dir), "--json"])
|
|
111
|
+
output = json.loads(capsys.readouterr().out)
|
|
112
|
+
|
|
113
|
+
assert rc == 0
|
|
114
|
+
assert output["request_id"] == "req-open-01"
|
|
115
|
+
assert "approval_url" in output
|
|
116
|
+
|
|
117
|
+
def test_approvals_open_returns_error_for_missing_request(self, tmp_path: Path, capsys) -> None:
|
|
118
|
+
"""T735: approvals open with daemon stopped returns a clear error, not a crash."""
|
|
119
|
+
home_dir = tmp_path / "guard-home"
|
|
120
|
+
|
|
121
|
+
rc = main(["guard", "approvals", "open", "req-missing", "--home", str(home_dir), "--json"])
|
|
122
|
+
output = json.loads(capsys.readouterr().out)
|
|
123
|
+
|
|
124
|
+
assert rc != 0
|
|
125
|
+
assert "error" in output
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class TestApprovalsRetryHintCommand:
|
|
129
|
+
"""T736-T737: 'hol-guard approvals retry-hint <request_id>' command."""
|
|
130
|
+
|
|
131
|
+
def test_retry_hint_allow_resolution(self, tmp_path: Path, capsys) -> None:
|
|
132
|
+
"""T737: retry-hint returns allow copy after approval."""
|
|
133
|
+
home_dir = tmp_path / "guard-home"
|
|
134
|
+
store = GuardStore(home_dir)
|
|
135
|
+
store.add_approval_request(_make_request(request_id="req-hint-allow"), "2026-01-01T00:00:00Z")
|
|
136
|
+
main(
|
|
137
|
+
[
|
|
138
|
+
"guard",
|
|
139
|
+
"approvals",
|
|
140
|
+
"approve",
|
|
141
|
+
"req-hint-allow",
|
|
142
|
+
"--home",
|
|
143
|
+
str(home_dir),
|
|
144
|
+
"--scope",
|
|
145
|
+
"artifact",
|
|
146
|
+
"--json",
|
|
147
|
+
]
|
|
148
|
+
)
|
|
149
|
+
capsys.readouterr()
|
|
150
|
+
|
|
151
|
+
rc = main(["guard", "approvals", "retry-hint", "req-hint-allow", "--home", str(home_dir), "--json"])
|
|
152
|
+
output = json.loads(capsys.readouterr().out)
|
|
153
|
+
|
|
154
|
+
assert rc == 0
|
|
155
|
+
assert output["title"] == "Approved. Retry in chat."
|
|
156
|
+
|
|
157
|
+
def test_retry_hint_block_resolution(self, tmp_path: Path, capsys) -> None:
|
|
158
|
+
"""T737: retry-hint returns block copy after block decision."""
|
|
159
|
+
home_dir = tmp_path / "guard-home"
|
|
160
|
+
store = GuardStore(home_dir)
|
|
161
|
+
store.add_approval_request(_make_request(request_id="req-hint-block"), "2026-01-01T00:00:00Z")
|
|
162
|
+
main(
|
|
163
|
+
[
|
|
164
|
+
"guard",
|
|
165
|
+
"approvals",
|
|
166
|
+
"deny",
|
|
167
|
+
"req-hint-block",
|
|
168
|
+
"--home",
|
|
169
|
+
str(home_dir),
|
|
170
|
+
"--scope",
|
|
171
|
+
"artifact",
|
|
172
|
+
"--json",
|
|
173
|
+
]
|
|
174
|
+
)
|
|
175
|
+
capsys.readouterr()
|
|
176
|
+
|
|
177
|
+
rc = main(["guard", "approvals", "retry-hint", "req-hint-block", "--home", str(home_dir), "--json"])
|
|
178
|
+
output = json.loads(capsys.readouterr().out)
|
|
179
|
+
|
|
180
|
+
assert rc == 0
|
|
181
|
+
assert output["title"] == "Blocked. Guard will remember this decision."
|
|
182
|
+
|
|
183
|
+
def test_retry_hint_missing_request(self, tmp_path: Path, capsys) -> None:
|
|
184
|
+
"""T737: retry-hint with unknown request_id returns error."""
|
|
185
|
+
home_dir = tmp_path / "guard-home"
|
|
186
|
+
|
|
187
|
+
rc = main(["guard", "approvals", "retry-hint", "req-hint-missing", "--home", str(home_dir), "--json"])
|
|
188
|
+
output = json.loads(capsys.readouterr().out)
|
|
189
|
+
|
|
190
|
+
assert rc != 0
|
|
191
|
+
assert "error" in output
|
|
192
|
+
|
|
193
|
+
def test_retry_hint_pending_request(self, tmp_path: Path, capsys) -> None:
|
|
194
|
+
"""T737: retry-hint with still-pending request returns not_resolved status."""
|
|
195
|
+
home_dir = tmp_path / "guard-home"
|
|
196
|
+
store = GuardStore(home_dir)
|
|
197
|
+
store.add_approval_request(_make_request(request_id="req-hint-pending"), "2026-01-01T00:00:00Z")
|
|
198
|
+
|
|
199
|
+
rc = main(["guard", "approvals", "retry-hint", "req-hint-pending", "--home", str(home_dir), "--json"])
|
|
200
|
+
output = json.loads(capsys.readouterr().out)
|
|
201
|
+
|
|
202
|
+
assert rc != 0
|
|
203
|
+
assert output.get("status") == "pending" or "error" in output
|