plugin-scanner 2.0.70__tar.gz → 2.0.71__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.70 → plugin_scanner-2.0.71}/PKG-INFO +1 -1
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docs/guard/harness-support.md +14 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docs/guard/testing-matrix.md +4 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/pyproject.toml +1 -1
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/pyproject.toml.bak +1 -1
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/copilot.py +1 -1
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/cursor.py +7 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/gemini.py +5 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/opencode.py +5 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/commands.py +12 -26
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/runtime/runner.py +175 -30
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/version.py +1 -1
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_claude_adapter.py +8 -2
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_copilot_adapter.py +3 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_launch_env.py +193 -1
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_runtime.py +205 -6
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_surface_server.py +7 -2
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.clusterfuzzlite/Dockerfile +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.clusterfuzzlite/build.sh +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.clusterfuzzlite/project.yaml +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.clusterfuzzlite/requirements-atheris.txt +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.dockerignore +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/CODEOWNERS +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/dependabot.yml +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/workflows/ci.yml +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/workflows/codeql.yml +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/workflows/dependabot-uv-lock.yml +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/workflows/fuzz.yml +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/workflows/harness-smoke.yml +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/workflows/publish.yml +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.github/workflows/scorecard.yml +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.gitignore +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/.pre-commit-hooks.yaml +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/CONTRIBUTING.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/Dockerfile +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/LICENSE +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/README.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/SECURITY.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/index.html +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/package.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/pnpm-lock.yaml +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/public/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/public/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/public/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/public/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/public/favicon.ico +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/app.tsx +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/approval-center-layout.tsx +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/approval-center-primitives.tsx +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/approval-center-utils.ts +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/fleet-workspace.tsx +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/guard-api.ts +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/guard-demo.ts +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/guard-types.ts +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/main.tsx +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/receipts-workspace.tsx +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/runtime-overview.tsx +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/settings-workspace.tsx +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/styles.css +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/src/vite-env.d.ts +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/tsconfig.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/dashboard/vite.config.ts +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docker-requirements.txt +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docs/guard/approval-audit.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docs/guard/architecture.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docs/guard/get-started.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docs/guard/local-vs-cloud.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docs/trust/mcp-trust-draft.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docs/trust/plugin-trust-draft.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/docs/trust/skill-trust-local.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/fuzzers/manifest_fuzzer.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/requirements.txt +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/schemas/plugin-quality.v1.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/schemas/scan-result.v1.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/schemas/verify-result.v1.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/__init__.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/action_runner.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/argparse_utils.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/__init__.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/claude.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/gemini.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/manifest.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/opencode.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/security.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/cli.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/cli_ui.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/config.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/github_reporting.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/__init__.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/approvals.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/config.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/incident.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/launcher.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/models.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/protect.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/risk.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/shims.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/store.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/types.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/lint_fixes.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/marketplace_support.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/models.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/path_support.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/policy.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/quality_artifact.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/repo_detect.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/reporting.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/rules/__init__.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/rules/registry.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/rules/specs.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/scanner.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/submission.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/suppressions.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/trust_helpers.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/trust_models.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/trust_scoring.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/trust_specs.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/verification.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/__init__.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/conftest.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/__init__.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/bad-plugin/.mcp.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/bad-plugin/secrets.js +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/claude-plugin-good/README.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/code-quality-bad/evil.js +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/code-quality-bad/inject.js +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/gemini-extension-good/README.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/good-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/good-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/good-plugin/README.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/good-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/mcp-canary-server.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/mit-license/LICENSE +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/opencode-good/LICENSE +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/opencode-good/README.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/opencode-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/fixtures/with-marketplace/marketplace.json +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test-trust-scoring.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test-trust-specs.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_action_runner.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_best_practices.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_cisco_install_surfaces.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_cli.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_code_quality.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_config.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_coverage_remaining.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_ecosystems.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_edge_cases.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_final_coverage.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_approvals.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_bootstrap.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_capabilities.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_cli.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_codex_e2e.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_codex_install.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_codex_proxy.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_config_paths.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_connect_flow.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_consumer_mode.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_copilot_proxy.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_daemon_manager.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_event_schema_v1.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_events.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_opencode_proxy.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_product_flow.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_protect.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_render.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_risk.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_store_migrations.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_guard_verdicts.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_hermes_adapter.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_integration.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_lint_fixes.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_live_cisco_smoke.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_manifest.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_marketplace.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_mcp_security.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_operational_security.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_policy.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_quality_artifact.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_rule_registry.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_scanner.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_schema_contracts.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_security.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_security_ops.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_skill_security.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_submission.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_trust_scoring.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_trust_specs.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_verification.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/tests/test_versioning.py +0 -0
- {plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/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.71
|
|
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
|
|
@@ -8,11 +8,13 @@ Current Guard support in this repo:
|
|
|
8
8
|
- parses configured MCP servers
|
|
9
9
|
- installs Guard-owned Codex `PreToolUse` Bash hooks so native shell commands can be denied before execution even when Codex itself is running in YOLO mode
|
|
10
10
|
- supports wrapper-mode `guard run codex`
|
|
11
|
+
- wrapper prompt screening now suppresses copied debug and incident context while still escalating risky prompt intent
|
|
11
12
|
- uses same-chat MCP elicitation for live managed MCP tool approvals in the interactive CLI and Codex App
|
|
12
13
|
- falls back to the local approval center only for nonresponsive or headless Codex sessions such as `codex exec`
|
|
13
14
|
- `claude-code`
|
|
14
15
|
- detects global and project settings, hooks, `.mcp.json`, and workspace agents
|
|
15
16
|
- supports local hook install and uninstall in `.claude/settings.local.json`
|
|
17
|
+
- has native `UserPromptSubmit` and `PreToolUse` Guard hook coverage
|
|
16
18
|
- is the best current harness for graceful approval deferral
|
|
17
19
|
- `copilot`
|
|
18
20
|
- detects read-only user config in `~/.copilot/config.json` and `~/.copilot/mcp-config.json`
|
|
@@ -20,9 +22,11 @@ Current Guard support in this repo:
|
|
|
20
22
|
- detects repo-local Copilot CLI hooks from `.github/hooks/*.json`
|
|
21
23
|
- installs and removes Guard-owned repo hooks in `.github/hooks/hol-guard-copilot.json`
|
|
22
24
|
- supports wrapper-mode `guard run copilot`
|
|
25
|
+
- has native `userPromptSubmitted`, `preToolUse`, and `postToolUse` hook coverage normalized onto the shared Guard runtime
|
|
23
26
|
- `cursor`
|
|
24
27
|
- detects global and project `mcp.json`
|
|
25
28
|
- supports wrapper-mode management state
|
|
29
|
+
- wrapper prompt screening is covered for benign debug prompts and risky secret-read prompts
|
|
26
30
|
- leaves native Cursor tool approval in place and focuses Guard on artifact trust
|
|
27
31
|
- `antigravity`
|
|
28
32
|
- detects Antigravity user settings, installed extension profiles, and Antigravity-owned MCP and skill roots
|
|
@@ -31,6 +35,7 @@ Current Guard support in this repo:
|
|
|
31
35
|
- `gemini`
|
|
32
36
|
- detects `.gemini/settings.json`, local extension manifests, embedded MCP declarations, hooks, and Gemini skill directories
|
|
33
37
|
- supports wrapper-mode management state
|
|
38
|
+
- wrapper prompt screening is covered for benign debug prompts and risky secret-read prompts
|
|
34
39
|
- falls back to the local approval center when Guard blocks a launch
|
|
35
40
|
- `hermes`
|
|
36
41
|
- detects Hermes skills plus MCP servers from `~/.hermes/config.yaml` and `~/.hermes/mcp_servers.json`
|
|
@@ -42,6 +47,7 @@ Current Guard support in this repo:
|
|
|
42
47
|
plugin files, and OpenCode-compatible skill directories
|
|
43
48
|
- supports wrapper-mode management state plus a Guard-owned runtime overlay for native skill approval prompts
|
|
44
49
|
- supports wrapper-mode `guard run opencode`
|
|
50
|
+
- wrapper prompt screening is covered for benign debug prompts and risky secret-read prompts
|
|
45
51
|
- keeps managed MCP tools on OpenCode native ask so the user can allow once, allow for the session, or reject inline
|
|
46
52
|
- blocks newly introduced OpenCode MCP, plugin, and skill artifacts before launch when local Guard policy requires
|
|
47
53
|
approval
|
|
@@ -54,6 +60,14 @@ Approval tiers:
|
|
|
54
60
|
|
|
55
61
|
The harness adapters are designed to prefer discovery and reversible overlay behavior over invasive config mutation.
|
|
56
62
|
|
|
63
|
+
The Guard Surface Server now provides one shared runtime shape across harnesses:
|
|
64
|
+
|
|
65
|
+
- session attach
|
|
66
|
+
- operation start and status updates
|
|
67
|
+
- approval request items
|
|
68
|
+
- approval-center lease and heartbeat tracking
|
|
69
|
+
- resume or completion after approval
|
|
70
|
+
|
|
57
71
|
Runtime intent protections:
|
|
58
72
|
|
|
59
73
|
- Guard evaluates prompt and tool intent for secret-bearing files beyond `.env`, including SSH, AWS, kubeconfig, Docker, npm, and Python credential files.
|
|
@@ -4,6 +4,8 @@ Automated coverage in this phase includes:
|
|
|
4
4
|
|
|
5
5
|
- Guard CLI behavior tests for detect, scan, run, diff, receipts, install, uninstall, login, and sync
|
|
6
6
|
- Guard product-flow tests for `hol-guard start`, `hol-guard status`, and launcher shim creation
|
|
7
|
+
- prompt-risk regressions for Codex, Cursor, Gemini, and OpenCode wrapper launches
|
|
8
|
+
- native prompt-hook regressions for Claude Code and Copilot hook events
|
|
7
9
|
- SQLite persistence through real command execution in temporary homes and workspaces
|
|
8
10
|
- consumer-mode JSON contract generation against scanner fixtures
|
|
9
11
|
- local HTTP sync against a live in-process server instead of mocked transport
|
|
@@ -20,6 +22,8 @@ Manual verification should include:
|
|
|
20
22
|
- `hol-guard detect opencode --json`
|
|
21
23
|
- `hol-guard install opencode --json`
|
|
22
24
|
- `hol-guard update --dry-run --json`
|
|
25
|
+
- `hol-guard run cursor --dry-run --default-action allow --json`
|
|
26
|
+
- `hol-guard run gemini --dry-run --default-action allow --json`
|
|
23
27
|
- `hol-guard run opencode --dry-run --default-action allow --json`
|
|
24
28
|
- `hol-guard run opencode --default-action require-reapproval --json`
|
|
25
29
|
- `hol-guard approvals --json`
|
|
@@ -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.71"
|
|
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.
|
|
7
|
+
version = "2.0.71"
|
|
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"
|
{plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/copilot.py
RENAMED
|
@@ -25,7 +25,7 @@ from .mcp_servers import (
|
|
|
25
25
|
skipped_stdio_server_names,
|
|
26
26
|
)
|
|
27
27
|
|
|
28
|
-
_MANAGED_HOOK_EVENTS = ("preToolUse", "postToolUse", "permissionRequest")
|
|
28
|
+
_MANAGED_HOOK_EVENTS = ("userPromptSubmitted", "preToolUse", "postToolUse", "permissionRequest")
|
|
29
29
|
_DETECTABLE_HOOK_EVENTS = (
|
|
30
30
|
"sessionStart",
|
|
31
31
|
"sessionEnd",
|
{plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/cursor.py
RENAMED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
5
7
|
from ..models import GuardArtifact, HarnessDetection
|
|
6
8
|
from .base import HarnessAdapter, HarnessContext, _command_available, _json_payload, _run_command_probe
|
|
7
9
|
|
|
@@ -25,6 +27,11 @@ class CursorHarnessAdapter(HarnessAdapter):
|
|
|
25
27
|
return "project"
|
|
26
28
|
return "global"
|
|
27
29
|
|
|
30
|
+
def policy_path(self, context: HarnessContext) -> Path:
|
|
31
|
+
if context.workspace_dir is not None:
|
|
32
|
+
return context.workspace_dir / ".cursor" / "mcp.json"
|
|
33
|
+
return context.home_dir / ".cursor" / "mcp.json"
|
|
34
|
+
|
|
28
35
|
def detect(self, context: HarnessContext) -> HarnessDetection:
|
|
29
36
|
config_paths = [context.home_dir / ".cursor" / "mcp.json"]
|
|
30
37
|
if context.workspace_dir is not None:
|
{plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/gemini.py
RENAMED
|
@@ -39,6 +39,11 @@ class GeminiHarnessAdapter(HarnessAdapter):
|
|
|
39
39
|
return ()
|
|
40
40
|
return tuple(str(value) for value in raw_args if isinstance(value, str))
|
|
41
41
|
|
|
42
|
+
def policy_path(self, context: HarnessContext) -> Path:
|
|
43
|
+
if context.workspace_dir is not None:
|
|
44
|
+
return context.workspace_dir / ".gemini" / "settings.json"
|
|
45
|
+
return context.home_dir / ".gemini" / "settings.json"
|
|
46
|
+
|
|
42
47
|
def detect(self, context: HarnessContext) -> HarnessDetection:
|
|
43
48
|
artifacts: list[GuardArtifact] = []
|
|
44
49
|
found_paths: list[str] = []
|
{plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/adapters/opencode.py
RENAMED
|
@@ -97,6 +97,11 @@ class OpenCodeHarnessAdapter(HarnessAdapter):
|
|
|
97
97
|
return "project"
|
|
98
98
|
return "global"
|
|
99
99
|
|
|
100
|
+
def policy_path(self, context: HarnessContext) -> Path:
|
|
101
|
+
if context.workspace_dir is not None:
|
|
102
|
+
return context.workspace_dir / "opencode.json"
|
|
103
|
+
return context.home_dir / ".config" / "opencode" / "opencode.json"
|
|
104
|
+
|
|
100
105
|
def detect(self, context: HarnessContext) -> HarnessDetection:
|
|
101
106
|
artifacts = []
|
|
102
107
|
found_paths: list[str] = []
|
{plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/cli/commands.py
RENAMED
|
@@ -1484,14 +1484,6 @@ def run_guard_command(
|
|
|
1484
1484
|
artifact=runtime_artifact,
|
|
1485
1485
|
artifact_hash=runtime_artifact_hash,
|
|
1486
1486
|
)
|
|
1487
|
-
if _should_allow_claude_user_prompt_submit_without_output(
|
|
1488
|
-
args,
|
|
1489
|
-
event_name=event_name,
|
|
1490
|
-
policy_action=policy_action,
|
|
1491
|
-
artifact=runtime_artifact,
|
|
1492
|
-
output_stream=output_stream,
|
|
1493
|
-
):
|
|
1494
|
-
return 0
|
|
1495
1487
|
if _should_emit_copilot_hook_response(args):
|
|
1496
1488
|
_emit_copilot_hook_response(
|
|
1497
1489
|
policy_action=policy_action,
|
|
@@ -1866,23 +1858,6 @@ def _should_emit_prequeue_native_hook_response(
|
|
|
1866
1858
|
return output_stream is not None
|
|
1867
1859
|
|
|
1868
1860
|
|
|
1869
|
-
def _should_allow_claude_user_prompt_submit_without_output(
|
|
1870
|
-
args: argparse.Namespace,
|
|
1871
|
-
*,
|
|
1872
|
-
event_name: str,
|
|
1873
|
-
policy_action: str,
|
|
1874
|
-
artifact: GuardArtifact,
|
|
1875
|
-
output_stream: TextIO | None,
|
|
1876
|
-
) -> bool:
|
|
1877
|
-
return (
|
|
1878
|
-
_canonical_harness_name(args.harness) == "claude-code"
|
|
1879
|
-
and event_name == "UserPromptSubmit"
|
|
1880
|
-
and policy_action == "require-reapproval"
|
|
1881
|
-
and not _prompt_requires_hard_block(artifact)
|
|
1882
|
-
and (not getattr(args, "json", False) or output_stream is not None)
|
|
1883
|
-
)
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
1861
|
def _emit_claude_permission_request_passthrough(*, output_stream: TextIO | None = None) -> None:
|
|
1887
1862
|
if output_stream is not None:
|
|
1888
1863
|
output_stream.write("")
|
|
@@ -3070,6 +3045,8 @@ def _emit_native_hook_response(
|
|
|
3070
3045
|
"hookEventName": event_name,
|
|
3071
3046
|
"additionalContext": additional_context,
|
|
3072
3047
|
}
|
|
3048
|
+
elif _canonical_harness_name(harness) in {"claude-code", "codex"}:
|
|
3049
|
+
payload["hookSpecificOutput"] = {"hookEventName": event_name}
|
|
3073
3050
|
if payload:
|
|
3074
3051
|
_write_json_line(payload, output_stream=output_stream)
|
|
3075
3052
|
return
|
|
@@ -3432,11 +3409,20 @@ def _optional_string(value: object | None) -> str | None:
|
|
|
3432
3409
|
return None
|
|
3433
3410
|
|
|
3434
3411
|
|
|
3412
|
+
_HOOK_EVENT_NAME_MAP = {
|
|
3413
|
+
"userpromptsubmitted": "UserPromptSubmit",
|
|
3414
|
+
"pretooluse": "PreToolUse",
|
|
3415
|
+
"posttooluse": "PostToolUse",
|
|
3416
|
+
"permissionrequest": "PermissionRequest",
|
|
3417
|
+
}
|
|
3418
|
+
|
|
3419
|
+
|
|
3435
3420
|
def _hook_event_name(payload: dict[str, object]) -> str | None:
|
|
3436
3421
|
for key in ("event", "hook_event_name", "hookEventName", "hook_name"):
|
|
3437
3422
|
value = payload.get(key)
|
|
3438
3423
|
if isinstance(value, str) and value.strip():
|
|
3439
|
-
|
|
3424
|
+
normalized = value.strip()
|
|
3425
|
+
return _HOOK_EVENT_NAME_MAP.get(normalized.lower(), normalized)
|
|
3440
3426
|
return None
|
|
3441
3427
|
|
|
3442
3428
|
|
{plugin_scanner-2.0.70 → plugin_scanner-2.0.71}/src/codex_plugin_scanner/guard/runtime/runner.py
RENAMED
|
@@ -58,22 +58,87 @@ _SECRET_ABSOLUTE_HINTS: tuple[tuple[str, str], ...] = (
|
|
|
58
58
|
("/.kube/config", "kubeconfig"),
|
|
59
59
|
("/.docker/config.json", "Docker credentials"),
|
|
60
60
|
)
|
|
61
|
-
|
|
62
|
-
r"\b(
|
|
61
|
+
_SECRET_READ_INTENT_PATTERN = re.compile(
|
|
62
|
+
r"\b("
|
|
63
|
+
r"read|open|print|show|dump|cat|head|tail|less|copy|cp|scp|reveal|display|summari[sz]e|inspect|extract|"
|
|
64
|
+
r"contain(?:s)?|contents?\s+of|what(?:'s| is)\s+in"
|
|
65
|
+
r")\b",
|
|
63
66
|
re.IGNORECASE,
|
|
64
67
|
)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
_EXFIL_PROMPT_PATTERNS: tuple[re.Pattern[str], ...] = (
|
|
69
|
+
re.compile(
|
|
70
|
+
r"\b(?:upload|exfiltrate|transfer|paste|gist|webhook)\b.{0,80}\b"
|
|
71
|
+
r"(?:file|contents?|data|payload|secret|token|key|credential|credentials|config|output)\b",
|
|
72
|
+
re.IGNORECASE,
|
|
73
|
+
),
|
|
74
|
+
re.compile(
|
|
75
|
+
r"\b(?:send|post|upload|transfer|paste|sync)\b.{0,80}\b"
|
|
76
|
+
r"(?:contents?|data|payload|file|secret|token|key|credential|credentials|config|output)\b"
|
|
77
|
+
r"(?:.{0,40}\b(?:to|into|onto|via|through)\b)?",
|
|
78
|
+
re.IGNORECASE,
|
|
79
|
+
),
|
|
80
|
+
re.compile(
|
|
81
|
+
r"\b(?:send|post|upload|transfer|paste|sync)\b.{0,80}\b"
|
|
82
|
+
r"(?:to|into|onto|via|through)\b.{0,40}\b"
|
|
83
|
+
r"(?:webhook|gist|pastebin|slack|discord|telegram|server|endpoint|url)\b",
|
|
84
|
+
re.IGNORECASE,
|
|
85
|
+
),
|
|
86
|
+
re.compile(
|
|
87
|
+
r"\b(?:send|post|upload|transfer|paste|sync)\b.{0,120}"
|
|
88
|
+
r"(?:"
|
|
89
|
+
r"(?<![\w-])\.env(?:\.[\w.-]+)?\b|"
|
|
90
|
+
r"(?:^|[\s'\"`])~?/.ssh(?:/|\b)|"
|
|
91
|
+
r"(?:^|[\s'\"`])~?/.aws/(?:credentials|config)\b|"
|
|
92
|
+
r"(?:^|[\s'\"`])~?/.kube/config\b|"
|
|
93
|
+
r"(?:^|[\s'\"`])~?/.docker/config\.json\b|"
|
|
94
|
+
r"(?<![\w-])\.npmrc\b|"
|
|
95
|
+
r"(?<![\w-])\.pypirc\b|"
|
|
96
|
+
r"(?<![\w-])\.git-credentials\b|"
|
|
97
|
+
r"/.ssh/|"
|
|
98
|
+
r"/.aws/credentials|"
|
|
99
|
+
r"/.aws/config|"
|
|
100
|
+
r"/.kube/config|"
|
|
101
|
+
r"/.docker/config\.json"
|
|
102
|
+
r")"
|
|
103
|
+
r".{0,80}\b(?:to|into|onto|via|through)\b.{0,80}"
|
|
104
|
+
r"(?:[a-z][a-z0-9+.-]*://|webhook|gist|pastebin|slack|discord|telegram|server|endpoint|url)\b",
|
|
105
|
+
re.IGNORECASE,
|
|
106
|
+
),
|
|
68
107
|
)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
108
|
+
_DESTRUCTIVE_PROMPT_PATTERNS: tuple[re.Pattern[str], ...] = (
|
|
109
|
+
re.compile(
|
|
110
|
+
r"\b(?:run|execute|use|call|invoke)\b.{0,40}\b(?:rm\s+-rf|rm\s+|del\s+|truncate\s+|chmod\s+|chown\s+|mv\s+)",
|
|
111
|
+
re.IGNORECASE,
|
|
112
|
+
),
|
|
113
|
+
re.compile(
|
|
114
|
+
r"(?:^|[\s'\"`(])(?:rm\s+-rf|rm\s+\S|del\s+\S|truncate\s+\S|chmod\s+\S|chown\s+\S|mv\s+\S)",
|
|
115
|
+
re.IGNORECASE,
|
|
116
|
+
),
|
|
117
|
+
re.compile(
|
|
118
|
+
r"\b(?:delete|remove|overwrite|truncate)\b.{0,60}\b(?:file|directory|repo|workspace|contents?)\b",
|
|
119
|
+
re.IGNORECASE,
|
|
120
|
+
),
|
|
121
|
+
)
|
|
122
|
+
_SUBPROCESS_PROMPT_PATTERNS: tuple[re.Pattern[str], ...] = (
|
|
123
|
+
re.compile(
|
|
124
|
+
r"\b(?:run|execute|use|call|invoke|launch|spawn)\b.{0,60}\b"
|
|
125
|
+
r"(?:bash\s+-c|sh\s+-c|zsh\s+-c|powershell|cmd\s+/c|subprocess|exec\(|spawn\()",
|
|
126
|
+
re.IGNORECASE,
|
|
127
|
+
),
|
|
128
|
+
re.compile(
|
|
129
|
+
r"(?:^|[\s'\"`(])(?:bash\s+-c\b|sh\s+-c\b|zsh\s+-c\b|powershell(?:\.exe)?(?:\s|$)|cmd\s+/c(?:\s|$)|subprocess\.(?:run|Popen|call|check_call|check_output)\b|exec\(|spawn\()",
|
|
130
|
+
re.IGNORECASE,
|
|
131
|
+
),
|
|
132
|
+
re.compile(
|
|
133
|
+
r"\b(?:use|call|invoke)\b.{0,40}\bsubprocess\b",
|
|
134
|
+
re.IGNORECASE,
|
|
135
|
+
),
|
|
72
136
|
)
|
|
73
137
|
_GUARD_BYPASS_PROMPT_PATTERN = re.compile(
|
|
74
138
|
r"\b(hol-guard\s+(?:disable|off|uninstall)|disable\s+hol-guard|approval_policy\s*=\s*\"never\"|guard[_-]?bypass)\b",
|
|
75
139
|
re.IGNORECASE,
|
|
76
140
|
)
|
|
141
|
+
_PROMPT_SENTENCE_BOUNDARY_PATTERN = re.compile(r"[!?;]|[.](?=\s|$)")
|
|
77
142
|
_GUARD_SYNC_USER_AGENT = f"hol-guard/{__version__}"
|
|
78
143
|
_SYNC_HTTP_TIMEOUT_SECONDS = 20
|
|
79
144
|
_SYNC_HTTP_RETRY_TIMEOUT_SECONDS = 120
|
|
@@ -91,6 +156,55 @@ class GuardSyncNotAvailableError(RuntimeError):
|
|
|
91
156
|
"""Raised when the sync endpoint returns 403 (free-plan restriction)."""
|
|
92
157
|
|
|
93
158
|
|
|
159
|
+
def _prompt_sentence_start(text: str, index: int) -> int:
|
|
160
|
+
matches = list(_PROMPT_SENTENCE_BOUNDARY_PATTERN.finditer(text, 0, index))
|
|
161
|
+
return matches[-1].end() if matches else 0
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _prompt_sentence_end(text: str, index: int) -> int:
|
|
165
|
+
match = _PROMPT_SENTENCE_BOUNDARY_PATTERN.search(text, index)
|
|
166
|
+
return match.end() if match is not None else len(text)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _prompt_secret_intent_region(text: str, *, start: int, end: int) -> str:
|
|
170
|
+
current_sentence_start = _prompt_sentence_start(text, start)
|
|
171
|
+
region_start = _prompt_sentence_start(text, max(0, current_sentence_start - 1))
|
|
172
|
+
first_sentence_end = _prompt_sentence_end(text, end)
|
|
173
|
+
second_sentence_end = (
|
|
174
|
+
_prompt_sentence_end(text, first_sentence_end) if first_sentence_end < len(text) else first_sentence_end
|
|
175
|
+
)
|
|
176
|
+
return text[region_start:second_sentence_end]
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _prompt_has_secret_read_intent(prompt_text: str, *, start: int, end: int) -> bool:
|
|
180
|
+
return (
|
|
181
|
+
_SECRET_READ_INTENT_PATTERN.search(
|
|
182
|
+
_prompt_secret_intent_region(prompt_text, start=start, end=end),
|
|
183
|
+
)
|
|
184
|
+
is not None
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _first_match(patterns: tuple[re.Pattern[str], ...], text: str) -> re.Match[str] | None:
|
|
189
|
+
for pattern in patterns:
|
|
190
|
+
match = pattern.search(text)
|
|
191
|
+
if match is not None:
|
|
192
|
+
return match
|
|
193
|
+
return None
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _iter_hint_occurrences(text: str, hint: str) -> list[tuple[int, int]]:
|
|
197
|
+
occurrences: list[tuple[int, int]] = []
|
|
198
|
+
current_pos = 0
|
|
199
|
+
while True:
|
|
200
|
+
start = text.find(hint, current_pos)
|
|
201
|
+
if start == -1:
|
|
202
|
+
return occurrences
|
|
203
|
+
end = start + len(hint)
|
|
204
|
+
occurrences.append((start, end))
|
|
205
|
+
current_pos = start + 1
|
|
206
|
+
|
|
207
|
+
|
|
94
208
|
def guard_run(
|
|
95
209
|
harness: str,
|
|
96
210
|
context: HarnessContext,
|
|
@@ -122,6 +236,12 @@ def guard_run(
|
|
|
122
236
|
if key in pending_evaluation:
|
|
123
237
|
reevaluated[key] = pending_evaluation[key]
|
|
124
238
|
evaluation = reevaluated
|
|
239
|
+
if "config_paths" not in evaluation:
|
|
240
|
+
evaluation["config_paths"] = list(detection.config_paths) or _guard_run_config_paths(
|
|
241
|
+
detection=detection,
|
|
242
|
+
context=context,
|
|
243
|
+
passthrough_args=passthrough_args,
|
|
244
|
+
)
|
|
125
245
|
if evaluation["blocked"] or dry_run:
|
|
126
246
|
evaluation["launched"] = False
|
|
127
247
|
evaluation["launch_command"] = []
|
|
@@ -147,6 +267,20 @@ def guard_run(
|
|
|
147
267
|
return evaluation
|
|
148
268
|
|
|
149
269
|
|
|
270
|
+
def _guard_run_config_paths(
|
|
271
|
+
*,
|
|
272
|
+
detection: HarnessDetection,
|
|
273
|
+
context: HarnessContext,
|
|
274
|
+
passthrough_args: list[str],
|
|
275
|
+
) -> list[str]:
|
|
276
|
+
if detection.config_paths:
|
|
277
|
+
return list(detection.config_paths)
|
|
278
|
+
prompt_text = " ".join(value.strip() for value in passthrough_args if value.strip())
|
|
279
|
+
if prompt_text:
|
|
280
|
+
return [str(_prompt_policy_path(detection, context))]
|
|
281
|
+
return []
|
|
282
|
+
|
|
283
|
+
|
|
150
284
|
def _detection_with_prompt_artifacts(
|
|
151
285
|
detection: HarnessDetection,
|
|
152
286
|
context: HarnessContext,
|
|
@@ -210,20 +344,25 @@ def extract_prompt_requests(prompt_text: str) -> list[PromptRequest]:
|
|
|
210
344
|
)
|
|
211
345
|
|
|
212
346
|
for pattern, label in _SECRET_REQUEST_PATTERNS:
|
|
213
|
-
match
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
347
|
+
for match in pattern.finditer(normalized_prompt):
|
|
348
|
+
if not _prompt_has_secret_read_intent(normalized_prompt, start=match.start(), end=match.end()):
|
|
349
|
+
continue
|
|
350
|
+
add_secret_request(label=label, matched=match.group(0).strip())
|
|
351
|
+
break
|
|
217
352
|
for hint, label in _SECRET_ABSOLUTE_HINTS:
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
353
|
+
for start, end in _iter_hint_occurrences(lowered, hint):
|
|
354
|
+
if _prompt_has_secret_read_intent(normalized_prompt, start=start, end=end):
|
|
355
|
+
add_secret_request(label=label, matched=hint)
|
|
356
|
+
break
|
|
357
|
+
exfil_match = _first_match(_EXFIL_PROMPT_PATTERNS, normalized_prompt)
|
|
358
|
+
if exfil_match is not None:
|
|
359
|
+
matched_text = exfil_match.group(0).strip()
|
|
221
360
|
requests.append(
|
|
222
361
|
PromptRequest(
|
|
223
|
-
request_id=_prompt_request_id("exfil_intent",
|
|
362
|
+
request_id=_prompt_request_id("exfil_intent", matched_text, lowered),
|
|
224
363
|
request_class="exfil_intent",
|
|
225
364
|
summary="Prompt includes exfiltration-oriented transfer intent.",
|
|
226
|
-
matched_text=
|
|
365
|
+
matched_text=matched_text,
|
|
227
366
|
severity=8,
|
|
228
367
|
confidence=0.84,
|
|
229
368
|
remediation=(
|
|
@@ -236,13 +375,19 @@ def extract_prompt_requests(prompt_text: str) -> list[PromptRequest]:
|
|
|
236
375
|
),
|
|
237
376
|
)
|
|
238
377
|
)
|
|
239
|
-
|
|
378
|
+
destructive_match = _first_match(_DESTRUCTIVE_PROMPT_PATTERNS, normalized_prompt)
|
|
379
|
+
if destructive_match is not None:
|
|
380
|
+
matched_text = destructive_match.group(0).strip()
|
|
240
381
|
requests.append(
|
|
241
382
|
PromptRequest(
|
|
242
|
-
request_id=_prompt_request_id(
|
|
383
|
+
request_id=_prompt_request_id(
|
|
384
|
+
"destructive_intent",
|
|
385
|
+
matched_text,
|
|
386
|
+
lowered,
|
|
387
|
+
),
|
|
243
388
|
request_class="destructive_intent",
|
|
244
389
|
summary="Prompt includes destructive filesystem mutation intent.",
|
|
245
|
-
matched_text=
|
|
390
|
+
matched_text=matched_text,
|
|
246
391
|
severity=8,
|
|
247
392
|
confidence=0.87,
|
|
248
393
|
remediation=(
|
|
@@ -259,13 +404,19 @@ def extract_prompt_requests(prompt_text: str) -> list[PromptRequest]:
|
|
|
259
404
|
),
|
|
260
405
|
)
|
|
261
406
|
)
|
|
262
|
-
|
|
407
|
+
subprocess_match = _first_match(_SUBPROCESS_PROMPT_PATTERNS, normalized_prompt)
|
|
408
|
+
if subprocess_match is not None:
|
|
409
|
+
matched_text = subprocess_match.group(0).strip()
|
|
263
410
|
requests.append(
|
|
264
411
|
PromptRequest(
|
|
265
|
-
request_id=_prompt_request_id(
|
|
412
|
+
request_id=_prompt_request_id(
|
|
413
|
+
"subprocess_intent",
|
|
414
|
+
matched_text,
|
|
415
|
+
lowered,
|
|
416
|
+
),
|
|
266
417
|
request_class="subprocess_intent",
|
|
267
418
|
summary="Prompt asks for subprocess or shell-wrapper execution.",
|
|
268
|
-
matched_text=
|
|
419
|
+
matched_text=matched_text,
|
|
269
420
|
severity=7,
|
|
270
421
|
confidence=0.8,
|
|
271
422
|
remediation=(
|
|
@@ -377,13 +528,7 @@ def _prompt_policy_path(detection: HarnessDetection, context: HarnessContext) ->
|
|
|
377
528
|
return candidate
|
|
378
529
|
if config_candidates:
|
|
379
530
|
return Path(config_candidates[0])
|
|
380
|
-
|
|
381
|
-
if context.workspace_dir is not None:
|
|
382
|
-
return context.workspace_dir / "opencode.json"
|
|
383
|
-
return context.home_dir / ".config" / "opencode" / "opencode.json"
|
|
384
|
-
if context.workspace_dir is not None:
|
|
385
|
-
return context.workspace_dir / ".codex" / "config.toml"
|
|
386
|
-
return context.home_dir / ".codex" / "config.toml"
|
|
531
|
+
return get_adapter(detection.harness).policy_path(context)
|
|
387
532
|
|
|
388
533
|
|
|
389
534
|
def _prompt_config_candidates(detection: HarnessDetection, context: HarnessContext) -> tuple[str, ...]:
|
|
@@ -371,7 +371,7 @@ def test_claude_daemon_hook_command_survives_shell_execution(tmp_path):
|
|
|
371
371
|
|
|
372
372
|
assert result.returncode == 0
|
|
373
373
|
assert result.stderr == ""
|
|
374
|
-
assert result.stdout == ""
|
|
374
|
+
assert json.loads(result.stdout) == {"hookSpecificOutput": {"hookEventName": "UserPromptSubmit"}}
|
|
375
375
|
|
|
376
376
|
|
|
377
377
|
def test_claude_daemon_hook_command_falls_back_without_blocking_prompt_on_daemon_miss(tmp_path):
|
|
@@ -394,7 +394,13 @@ def test_claude_daemon_hook_command_falls_back_without_blocking_prompt_on_daemon
|
|
|
394
394
|
)
|
|
395
395
|
assert result.returncode == 0
|
|
396
396
|
assert result.stderr == ""
|
|
397
|
-
|
|
397
|
+
payload = json.loads(result.stdout)
|
|
398
|
+
assert payload["systemMessage"].startswith("HOL Guard intercepted this prompt")
|
|
399
|
+
assert payload["hookSpecificOutput"]["hookEventName"] == "UserPromptSubmit"
|
|
400
|
+
assert (
|
|
401
|
+
"HOL Guard will intercept Claude's next attempt to access local secrets"
|
|
402
|
+
in (payload["hookSpecificOutput"]["additionalContext"])
|
|
403
|
+
)
|
|
398
404
|
|
|
399
405
|
|
|
400
406
|
def test_claude_daemon_hook_command_falls_back_to_native_ask_on_daemon_miss(tmp_path):
|
|
@@ -219,6 +219,7 @@ def test_copilot_install_and_uninstall_manage_inline_config_hooks_idempotently(t
|
|
|
219
219
|
assert first_install["active"] is True
|
|
220
220
|
assert second_install["active"] is True
|
|
221
221
|
assert first_install["config_path"] == str(config_path)
|
|
222
|
+
assert len(managed_hooks["userPromptSubmitted"]) == 1
|
|
222
223
|
assert len(managed_hooks["preToolUse"]) == 1
|
|
223
224
|
assert len(managed_hooks["postToolUse"]) == 1
|
|
224
225
|
assert len(managed_hooks["permissionRequest"]) == 1
|
|
@@ -230,8 +231,10 @@ def test_copilot_install_and_uninstall_manage_inline_config_hooks_idempotently(t
|
|
|
230
231
|
assert "copilot" in managed_hooks["preToolUse"][0]["bash"]
|
|
231
232
|
assert "--workspace" not in managed_hooks["preToolUse"][0]["bash"]
|
|
232
233
|
assert "from codex_plugin_scanner.cli import main" in managed_hooks["preToolUse"][0]["powershell"]
|
|
234
|
+
assert "from codex_plugin_scanner.cli import main" in managed_hooks["userPromptSubmitted"][0]["bash"]
|
|
233
235
|
assert managed_hooks["postToolUse"][0]["type"] == "command"
|
|
234
236
|
assert "from codex_plugin_scanner.cli import main" in managed_hooks["postToolUse"][0]["bash"]
|
|
237
|
+
assert len(managed_workspace_hooks["userPromptSubmitted"]) == 1
|
|
235
238
|
assert len(managed_workspace_hooks["preToolUse"]) == 1
|
|
236
239
|
assert len(managed_workspace_hooks["postToolUse"]) == 1
|
|
237
240
|
assert len(managed_workspace_hooks["permissionRequest"]) == 1
|