plugin-scanner 2.0.106__tar.gz → 2.0.107__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.106 → plugin_scanner-2.0.107}/PKG-INFO +1 -1
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/pyproject.toml +1 -1
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/pyproject.toml.bak +1 -1
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +85 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/capabilities.py +19 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/commands.py +17 -4
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +93 -15
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +11 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/version.py +1 -1
- plugin_scanner-2.0.107/tests/conftest.py +15 -0
- plugin_scanner-2.0.107/tests/test_guard_access_graph.py +395 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_cli.py +37 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_runtime.py +2 -0
- plugin_scanner-2.0.106/tests/conftest.py +0 -9
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.clusterfuzzlite/Dockerfile +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.clusterfuzzlite/build.sh +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.clusterfuzzlite/project.yaml +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.clusterfuzzlite/requirements-atheris.txt +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.dockerignore +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/CODEOWNERS +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/dependabot.yml +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/workflows/ci.yml +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/workflows/codeql.yml +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/workflows/dependabot-uv-lock.yml +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/workflows/fuzz.yml +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/workflows/harness-smoke.yml +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/workflows/publish.yml +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.github/workflows/scorecard.yml +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.gitignore +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/.pre-commit-hooks.yaml +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/CONTRIBUTING.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/Dockerfile +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/LICENSE +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/README.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/SECURITY.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/index.html +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/package.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/pnpm-lock.yaml +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/public/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/public/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/public/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/public/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/public/favicon.ico +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/app.tsx +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/approval-center-layout.tsx +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/approval-center-primitives.tsx +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/approval-center-utils.ts +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/fleet-workspace.tsx +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/guard-api.test.ts +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/guard-api.ts +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/guard-demo.ts +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/guard-types.ts +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/main.tsx +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/receipts-workspace.tsx +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/runtime-overview.tsx +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/settings-workspace.tsx +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/styles.css +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/src/vite-env.d.ts +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/tsconfig.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/dashboard/vite.config.ts +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docker-requirements.txt +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docs/guard/approval-audit.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docs/guard/architecture.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docs/guard/get-started.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docs/guard/harness-support.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docs/guard/local-vs-cloud.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docs/guard/testing-matrix.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docs/trust/mcp-trust-draft.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docs/trust/plugin-trust-draft.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/docs/trust/skill-trust-local.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/fuzzers/manifest_fuzzer.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/requirements.txt +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/schemas/plugin-quality.v1.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/schemas/scan-result.v1.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/schemas/verify-result.v1.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/__init__.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/action_runner.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/argparse_utils.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/__init__.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/claude.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/gemini.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/manifest.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/opencode.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/security.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/cli.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/cli_ui.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/config.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/github_reporting.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/__init__.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/approvals.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/config.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/incident.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/launcher.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/models.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/protect.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/redaction.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/risk.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/detectors.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/secret_sensitivity.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/shims.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/store.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/types.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/lint_fixes.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/marketplace_support.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/models.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/path_support.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/policy.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/quality_artifact.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/repo_detect.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/reporting.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/rules/__init__.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/rules/registry.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/rules/specs.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/scanner.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/submission.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/suppressions.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_helpers.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_models.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_scoring.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_specs.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/verification.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/__init__.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/__init__.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/bad-plugin/.mcp.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/bad-plugin/secrets.js +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/claude-plugin-good/README.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/code-quality-bad/evil.js +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/code-quality-bad/inject.js +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/gemini-extension-good/README.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/README.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/mcp-canary-server.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/mit-license/LICENSE +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/opencode-good/LICENSE +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/opencode-good/README.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/opencode-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/fixtures/with-marketplace/marketplace.json +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test-trust-scoring.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test-trust-specs.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_action_runner.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_best_practices.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_cisco_install_surfaces.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_cli.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_code_quality.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_config.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_coverage_remaining.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_ecosystems.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_edge_cases.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_final_coverage.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_approvals.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_bootstrap.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_capabilities.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_claude_adapter.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_codex_e2e.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_codex_install.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_codex_proxy.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_config_paths.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_connect_flow.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_consumer_mode.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_copilot_adapter.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_copilot_proxy.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_daemon_manager.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_event_schema_v1.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_events.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_launch_env.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_opencode_proxy.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_product_flow.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_protect.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_render.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_risk.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_runtime_action_harnesses.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_runtime_actions.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_runtime_decisions.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_runtime_detectors.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_runtime_signals.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_store_migrations.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_surface_server.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_guard_verdicts.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_hermes_adapter.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_integration.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_lint_fixes.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_live_cisco_smoke.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_manifest.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_marketplace.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_mcp_security.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_openclaw_adapter.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_operational_security.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_policy.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_quality_artifact.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_rule_registry.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_scanner.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_schema_contracts.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_security.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_security_ops.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_skill_security.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_submission.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_trust_scoring.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_trust_specs.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_verification.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/tests/test_versioning.py +0 -0
- {plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/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.107
|
|
4
4
|
Summary: Lint, verify, and gate plugin ecosystems for maintainers, CI, and publish workflows.
|
|
5
5
|
Project-URL: Homepage, https://github.com/hashgraph-online/ai-plugin-scanner
|
|
6
6
|
Project-URL: Repository, https://github.com/hashgraph-online/ai-plugin-scanner
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "plugin-scanner"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.107"
|
|
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.107"
|
|
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"
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import json
|
|
5
6
|
from dataclasses import dataclass
|
|
7
|
+
from hashlib import sha256
|
|
8
|
+
from pathlib import PurePath
|
|
6
9
|
|
|
7
10
|
from ..models import GuardArtifact, HarnessDetection
|
|
8
11
|
|
|
@@ -31,6 +34,23 @@ _GUARD_PROXY_COMMANDS = frozenset(
|
|
|
31
34
|
}
|
|
32
35
|
)
|
|
33
36
|
|
|
37
|
+
_STABLE_SLASH_FLAG_TOKENS = frozenset(
|
|
38
|
+
{
|
|
39
|
+
"/?",
|
|
40
|
+
"/debug",
|
|
41
|
+
"/dry-run",
|
|
42
|
+
"/h",
|
|
43
|
+
"/help",
|
|
44
|
+
"/quiet",
|
|
45
|
+
"/read-only",
|
|
46
|
+
"/readonly",
|
|
47
|
+
"/ro",
|
|
48
|
+
"/safe",
|
|
49
|
+
"/trace",
|
|
50
|
+
"/verbose",
|
|
51
|
+
}
|
|
52
|
+
)
|
|
53
|
+
|
|
34
54
|
|
|
35
55
|
def managed_stdio_servers(detection: HarnessDetection) -> tuple[ManagedMcpServer, ...]:
|
|
36
56
|
"""Extract local stdio MCP servers from a harness detection payload."""
|
|
@@ -76,6 +96,8 @@ def proxy_cli_args(
|
|
|
76
96
|
guard_home,
|
|
77
97
|
"--server-name",
|
|
78
98
|
server.name,
|
|
99
|
+
"--server-id",
|
|
100
|
+
stable_mcp_server_identifier(server),
|
|
79
101
|
"--source-scope",
|
|
80
102
|
server.source_scope,
|
|
81
103
|
"--config-path",
|
|
@@ -94,6 +116,24 @@ def proxy_cli_args(
|
|
|
94
116
|
return args
|
|
95
117
|
|
|
96
118
|
|
|
119
|
+
def stable_mcp_server_identifier(server: ManagedMcpServer) -> str:
|
|
120
|
+
"""Build a Cloud-stable MCP server ID without local config path material."""
|
|
121
|
+
|
|
122
|
+
harness = server.harness.strip().lower()
|
|
123
|
+
source_scope = server.source_scope.strip().lower()
|
|
124
|
+
server_name = _stable_server_name(server.name)
|
|
125
|
+
payload = {
|
|
126
|
+
"harness": harness,
|
|
127
|
+
"source_scope": source_scope,
|
|
128
|
+
"name": server_name,
|
|
129
|
+
"command": _stable_command_name(server.command),
|
|
130
|
+
"args": [_stable_arg_token(value) for value in server.args],
|
|
131
|
+
"transport": server.transport,
|
|
132
|
+
}
|
|
133
|
+
digest = sha256(json.dumps(payload, sort_keys=True).encode("utf-8")).hexdigest()[:20]
|
|
134
|
+
return f"mcp_server:{harness}:{source_scope}:{server_name}:{digest}"
|
|
135
|
+
|
|
136
|
+
|
|
97
137
|
def _managed_stdio_server(artifact: GuardArtifact) -> ManagedMcpServer | None:
|
|
98
138
|
if artifact.artifact_type != "mcp_server":
|
|
99
139
|
return None
|
|
@@ -119,6 +159,50 @@ def _managed_stdio_server(artifact: GuardArtifact) -> ManagedMcpServer | None:
|
|
|
119
159
|
)
|
|
120
160
|
|
|
121
161
|
|
|
162
|
+
def _stable_arg_token(value: str) -> str:
|
|
163
|
+
key, separator, item = value.partition("=")
|
|
164
|
+
if separator and (_looks_like_path_assignment(key, item) or _looks_like_path_token(item)):
|
|
165
|
+
return f"{key}=<path>"
|
|
166
|
+
if _looks_like_path_token(value):
|
|
167
|
+
return "<path>"
|
|
168
|
+
return value
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _stable_server_name(value: str) -> str:
|
|
172
|
+
return value.strip().lower() or "unnamed"
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _stable_command_name(value: str) -> str:
|
|
176
|
+
return PurePath(value.replace("\\", "/")).name.lower()
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _looks_like_path_assignment(key: str, value: str) -> bool:
|
|
180
|
+
normalized_key = key.strip().lstrip("-/").lower().replace("_", "-")
|
|
181
|
+
path_keys = {
|
|
182
|
+
"cache",
|
|
183
|
+
"config",
|
|
184
|
+
"cwd",
|
|
185
|
+
"dir",
|
|
186
|
+
"directory",
|
|
187
|
+
"file",
|
|
188
|
+
"folder",
|
|
189
|
+
"path",
|
|
190
|
+
"root",
|
|
191
|
+
"workspace",
|
|
192
|
+
"workdir",
|
|
193
|
+
}
|
|
194
|
+
return normalized_key in path_keys and value.strip().replace("\\", "/").startswith("/")
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _looks_like_path_token(value: str) -> bool:
|
|
198
|
+
normalized = value.strip().replace("\\", "/")
|
|
199
|
+
if normalized.startswith(("~/", "./", "../")):
|
|
200
|
+
return True
|
|
201
|
+
if normalized.startswith("/"):
|
|
202
|
+
return "/" in normalized[1:] or normalized.lower() not in _STABLE_SLASH_FLAG_TOKENS
|
|
203
|
+
return len(normalized) >= 3 and normalized[0].isalpha() and normalized[1:3] == ":/"
|
|
204
|
+
|
|
205
|
+
|
|
122
206
|
def _string_env(value: object) -> dict[str, str]:
|
|
123
207
|
if not isinstance(value, dict):
|
|
124
208
|
return {}
|
|
@@ -149,4 +233,5 @@ __all__ = [
|
|
|
149
233
|
"managed_stdio_servers",
|
|
150
234
|
"proxy_cli_args",
|
|
151
235
|
"skipped_stdio_server_names",
|
|
236
|
+
"stable_mcp_server_identifier",
|
|
152
237
|
]
|
{plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/capabilities.py
RENAMED
|
@@ -196,6 +196,25 @@ def severity_from_deltas(deltas: tuple[CapabilityDelta, ...]) -> int:
|
|
|
196
196
|
return max(delta.severity for delta in deltas)
|
|
197
197
|
|
|
198
198
|
|
|
199
|
+
def normalized_capability_categories(capabilities: CapabilitySet) -> tuple[str, ...]:
|
|
200
|
+
"""Return broad Cloud access graph categories for skills and MCP tools."""
|
|
201
|
+
|
|
202
|
+
categories: set[str] = set()
|
|
203
|
+
if capabilities.network_hosts or capabilities.network_schemes:
|
|
204
|
+
categories.add("network")
|
|
205
|
+
if capabilities.filesystem_paths:
|
|
206
|
+
categories.add("filesystem")
|
|
207
|
+
if capabilities.secret_classes:
|
|
208
|
+
categories.add("secret")
|
|
209
|
+
if capabilities.subprocess_invocation or capabilities.interpreters or capabilities.shell_wrappers:
|
|
210
|
+
categories.add("execution")
|
|
211
|
+
if capabilities.publisher:
|
|
212
|
+
categories.add("publisher")
|
|
213
|
+
if capabilities.transport != "local":
|
|
214
|
+
categories.add("transport")
|
|
215
|
+
return tuple(sorted(categories))
|
|
216
|
+
|
|
217
|
+
|
|
199
218
|
def _first_seen_deltas(after: CapabilitySet) -> list[CapabilityDelta]:
|
|
200
219
|
deltas: list[CapabilityDelta] = []
|
|
201
220
|
if after.network_hosts:
|
{plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/commands.py
RENAMED
|
@@ -539,6 +539,7 @@ def _configure_guard_parser(guard_parser: argparse.ArgumentParser) -> None:
|
|
|
539
539
|
codex_proxy_parser = guard_subparsers.add_parser("codex-mcp-proxy", help=argparse.SUPPRESS)
|
|
540
540
|
_add_guard_common_args(codex_proxy_parser)
|
|
541
541
|
codex_proxy_parser.add_argument("--server-name", required=True)
|
|
542
|
+
codex_proxy_parser.add_argument("--server-id")
|
|
542
543
|
codex_proxy_parser.add_argument("--source-scope", default="project")
|
|
543
544
|
codex_proxy_parser.add_argument("--config-path", required=True)
|
|
544
545
|
codex_proxy_parser.add_argument("--transport", default="stdio")
|
|
@@ -548,6 +549,7 @@ def _configure_guard_parser(guard_parser: argparse.ArgumentParser) -> None:
|
|
|
548
549
|
opencode_proxy_parser = guard_subparsers.add_parser("opencode-mcp-proxy", help=argparse.SUPPRESS)
|
|
549
550
|
_add_guard_common_args(opencode_proxy_parser)
|
|
550
551
|
opencode_proxy_parser.add_argument("--server-name", required=True)
|
|
552
|
+
opencode_proxy_parser.add_argument("--server-id")
|
|
551
553
|
opencode_proxy_parser.add_argument("--source-scope", default="project")
|
|
552
554
|
opencode_proxy_parser.add_argument("--config-path", required=True)
|
|
553
555
|
opencode_proxy_parser.add_argument("--transport", default="local")
|
|
@@ -557,6 +559,7 @@ def _configure_guard_parser(guard_parser: argparse.ArgumentParser) -> None:
|
|
|
557
559
|
copilot_proxy_parser = guard_subparsers.add_parser("copilot-mcp-proxy", help=argparse.SUPPRESS)
|
|
558
560
|
_add_guard_common_args(copilot_proxy_parser)
|
|
559
561
|
copilot_proxy_parser.add_argument("--server-name", required=True)
|
|
562
|
+
copilot_proxy_parser.add_argument("--server-id")
|
|
560
563
|
copilot_proxy_parser.add_argument("--source-scope", default="project")
|
|
561
564
|
copilot_proxy_parser.add_argument("--config-path", required=True)
|
|
562
565
|
copilot_proxy_parser.add_argument("--transport", default="stdio")
|
|
@@ -807,6 +810,7 @@ def run_guard_command(
|
|
|
807
810
|
source_scope=args.source_scope,
|
|
808
811
|
config_path=args.config_path,
|
|
809
812
|
transport=args.transport,
|
|
813
|
+
server_id=args.server_id,
|
|
810
814
|
)
|
|
811
815
|
return proxy.serve()
|
|
812
816
|
|
|
@@ -820,6 +824,7 @@ def run_guard_command(
|
|
|
820
824
|
source_scope=args.source_scope,
|
|
821
825
|
config_path=args.config_path,
|
|
822
826
|
transport=args.transport,
|
|
827
|
+
server_id=args.server_id,
|
|
823
828
|
)
|
|
824
829
|
return proxy.serve()
|
|
825
830
|
|
|
@@ -833,6 +838,7 @@ def run_guard_command(
|
|
|
833
838
|
source_scope=args.source_scope,
|
|
834
839
|
config_path=args.config_path,
|
|
835
840
|
transport=args.transport,
|
|
841
|
+
server_id=args.server_id,
|
|
836
842
|
)
|
|
837
843
|
return proxy.serve()
|
|
838
844
|
|
|
@@ -1253,6 +1259,7 @@ def run_guard_command(
|
|
|
1253
1259
|
decision_source="pre-tool-hook",
|
|
1254
1260
|
now=now,
|
|
1255
1261
|
signals=decision.signals,
|
|
1262
|
+
risk_categories=decision.risk_categories,
|
|
1256
1263
|
remember=False,
|
|
1257
1264
|
)
|
|
1258
1265
|
if _should_emit_copilot_hook_response(args):
|
|
@@ -1267,6 +1274,7 @@ def run_guard_command(
|
|
|
1267
1274
|
decision_source="pre-tool-hook",
|
|
1268
1275
|
now=now,
|
|
1269
1276
|
signals=decision.signals,
|
|
1277
|
+
risk_categories=decision.risk_categories,
|
|
1270
1278
|
)
|
|
1271
1279
|
if _should_emit_copilot_hook_response(args):
|
|
1272
1280
|
_emit_copilot_hook_response(
|
|
@@ -1345,6 +1353,7 @@ def run_guard_command(
|
|
|
1345
1353
|
decision_source=decision.source,
|
|
1346
1354
|
now=now,
|
|
1347
1355
|
signals=decision.signals,
|
|
1356
|
+
risk_categories=decision.risk_categories,
|
|
1348
1357
|
remember=False,
|
|
1349
1358
|
)
|
|
1350
1359
|
if _should_emit_copilot_hook_response(args):
|
|
@@ -1359,6 +1368,7 @@ def run_guard_command(
|
|
|
1359
1368
|
decision_source="permission-request-hook",
|
|
1360
1369
|
now=now,
|
|
1361
1370
|
signals=decision.signals,
|
|
1371
|
+
risk_categories=decision.risk_categories,
|
|
1362
1372
|
)
|
|
1363
1373
|
approval_center_url = ensure_guard_daemon(guard_home)
|
|
1364
1374
|
approval_flow = get_adapter(args.harness).approval_flow(managed_install=managed_install)
|
|
@@ -2010,18 +2020,19 @@ def _should_emit_native_hook_json_response(
|
|
|
2010
2020
|
|
|
2011
2021
|
|
|
2012
2022
|
def _should_emit_native_hook_exit_block(args: argparse.Namespace, *, event_name: str, policy_action: str) -> bool:
|
|
2013
|
-
codex_runtime_marker = (
|
|
2014
|
-
os.environ.get("CODEX_HOME", "").strip() or os.environ.get("CODEX_MANAGED_BY_BUN", "").strip()
|
|
2015
|
-
)
|
|
2016
2023
|
return (
|
|
2017
2024
|
args.harness == "codex"
|
|
2018
2025
|
and event_name == "PreToolUse"
|
|
2019
2026
|
and policy_action in {"block", "sandbox-required", "require-reapproval"}
|
|
2020
2027
|
and not getattr(args, "json", False)
|
|
2021
|
-
and
|
|
2028
|
+
and _is_codex_native_runtime()
|
|
2022
2029
|
)
|
|
2023
2030
|
|
|
2024
2031
|
|
|
2032
|
+
def _is_codex_native_runtime() -> bool:
|
|
2033
|
+
return bool(os.environ.get("CODEX_HOME", "").strip() or os.environ.get("CODEX_MANAGED_BY_BUN", "").strip())
|
|
2034
|
+
|
|
2035
|
+
|
|
2025
2036
|
def _codex_browser_approval_decision(
|
|
2026
2037
|
*,
|
|
2027
2038
|
args: argparse.Namespace,
|
|
@@ -2040,6 +2051,8 @@ def _codex_browser_approval_decision(
|
|
|
2040
2051
|
return None
|
|
2041
2052
|
if policy_action not in {"block", "sandbox-required", "require-reapproval"}:
|
|
2042
2053
|
return None
|
|
2054
|
+
if event_name == "PreToolUse" and not _is_codex_native_runtime():
|
|
2055
|
+
return None
|
|
2043
2056
|
approval_requests = response_payload.get("approval_requests")
|
|
2044
2057
|
if not isinstance(approval_requests, list):
|
|
2045
2058
|
return None
|
{plugin_scanner-2.0.106 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/mcp_tool_calls.py
RENAMED
|
@@ -22,6 +22,7 @@ class ToolCallDecision:
|
|
|
22
22
|
source: str
|
|
23
23
|
signals: tuple[str, ...]
|
|
24
24
|
summary: str
|
|
25
|
+
risk_categories: tuple[str, ...] = ()
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
def build_tool_call_artifact(
|
|
@@ -32,9 +33,12 @@ def build_tool_call_artifact(
|
|
|
32
33
|
source_scope: str,
|
|
33
34
|
config_path: str,
|
|
34
35
|
transport: str,
|
|
36
|
+
server_id: str | None = None,
|
|
35
37
|
server_fingerprint: object | None = None,
|
|
36
38
|
) -> GuardArtifact:
|
|
37
39
|
metadata = {"server_name": server_name}
|
|
40
|
+
if server_id is not None:
|
|
41
|
+
metadata["server_id"] = server_id
|
|
38
42
|
if server_fingerprint is not None:
|
|
39
43
|
metadata["server_fingerprint"] = server_fingerprint
|
|
40
44
|
return GuardArtifact(
|
|
@@ -82,20 +86,24 @@ def evaluate_tool_call(
|
|
|
82
86
|
override = config.resolve_action_override(artifact.harness, artifact.artifact_id, artifact.publisher)
|
|
83
87
|
action = _coerce_guard_action(override) if isinstance(override, str) else None
|
|
84
88
|
if action is not None:
|
|
89
|
+
risk_categories = tool_call_risk_categories(artifact, arguments)
|
|
85
90
|
return ToolCallDecision(
|
|
86
91
|
action=action,
|
|
87
92
|
source="policy",
|
|
88
93
|
signals=tool_call_risk_signals(artifact, arguments),
|
|
89
94
|
summary="Local Guard policy matched this exact tool call.",
|
|
95
|
+
risk_categories=risk_categories,
|
|
90
96
|
)
|
|
91
97
|
|
|
92
98
|
signals = tool_call_risk_signals(artifact, arguments)
|
|
99
|
+
risk_categories = tool_call_risk_categories(artifact, arguments)
|
|
93
100
|
if len(signals) == 0:
|
|
94
101
|
return ToolCallDecision(
|
|
95
102
|
action="allow",
|
|
96
103
|
source="heuristic",
|
|
97
104
|
signals=(),
|
|
98
105
|
summary="Guard did not detect a high-risk signal in this tool call.",
|
|
106
|
+
risk_categories=(),
|
|
99
107
|
)
|
|
100
108
|
if config.mode == "prompt":
|
|
101
109
|
return ToolCallDecision(
|
|
@@ -103,37 +111,95 @@ def evaluate_tool_call(
|
|
|
103
111
|
source="heuristic",
|
|
104
112
|
signals=signals,
|
|
105
113
|
summary=tool_call_risk_summary(artifact, arguments),
|
|
114
|
+
risk_categories=risk_categories,
|
|
106
115
|
)
|
|
107
116
|
return ToolCallDecision(
|
|
108
117
|
action="block",
|
|
109
118
|
source="heuristic",
|
|
110
119
|
signals=signals,
|
|
111
120
|
summary=tool_call_risk_summary(artifact, arguments),
|
|
121
|
+
risk_categories=risk_categories,
|
|
112
122
|
)
|
|
113
123
|
|
|
114
124
|
|
|
115
125
|
def tool_call_risk_signals(artifact: GuardArtifact, arguments: object) -> tuple[str, ...]:
|
|
126
|
+
signals_by_category = {
|
|
127
|
+
"destructive_mutation": "tool name implies destructive file or system changes",
|
|
128
|
+
"command_execution": "tool name implies shell or command execution",
|
|
129
|
+
"outbound_network": "call arguments imply outbound network activity",
|
|
130
|
+
"secret_access": "call arguments mention sensitive local files or secrets",
|
|
131
|
+
"privileged_system_mutation": "call arguments imply privileged system mutation",
|
|
132
|
+
}
|
|
133
|
+
return tuple(signals_by_category[category] for category in tool_call_risk_categories(artifact, arguments))
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def tool_call_risk_categories(artifact: GuardArtifact, arguments: object) -> tuple[str, ...]:
|
|
137
|
+
"""Return normalized Cloud risk categories for one MCP tool call."""
|
|
138
|
+
|
|
139
|
+
categories = _tool_call_risk_category_set(artifact, arguments)
|
|
140
|
+
order = (
|
|
141
|
+
"command_execution",
|
|
142
|
+
"destructive_mutation",
|
|
143
|
+
"outbound_network",
|
|
144
|
+
"privileged_system_mutation",
|
|
145
|
+
"secret_access",
|
|
146
|
+
)
|
|
147
|
+
return tuple(category for category in order if category in categories)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _tool_call_risk_category_set(artifact: GuardArtifact, arguments: object) -> set[str]:
|
|
116
151
|
tool_name = PurePath(artifact.command or artifact.name).name
|
|
117
|
-
serialized_arguments =
|
|
118
|
-
combined = f"{artifact.name
|
|
152
|
+
serialized_arguments = _serialized_tool_arguments(arguments)
|
|
153
|
+
combined = _risk_match_text(f"{artifact.name} {serialized_arguments}")
|
|
119
154
|
tool_name_tokens = set(_tool_name_tokens(tool_name))
|
|
120
|
-
|
|
155
|
+
categories: set[str] = set()
|
|
121
156
|
|
|
122
157
|
if len(tool_name_tokens.intersection({"delete", "remove", "rm", "destroy", "erase"})) > 0:
|
|
123
|
-
|
|
158
|
+
categories.add("destructive_mutation")
|
|
124
159
|
if len(tool_name_tokens.intersection({"shell", "bash", "exec", "execute", "command", "powershell"})) > 0:
|
|
125
|
-
|
|
126
|
-
if
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
160
|
+
categories.add("command_execution")
|
|
161
|
+
if _matches_any(
|
|
162
|
+
combined,
|
|
163
|
+
(
|
|
164
|
+
r"https?://",
|
|
165
|
+
_token_pattern("curl", "wget", "fetch", "axios", "requests"),
|
|
166
|
+
),
|
|
167
|
+
):
|
|
168
|
+
categories.add("outbound_network")
|
|
169
|
+
if _matches_any(
|
|
170
|
+
combined,
|
|
171
|
+
(
|
|
172
|
+
r"(?<![a-z0-9_-])\.env(?![a-z0-9_-])",
|
|
173
|
+
r"(?<![a-z0-9_-])\.ssh(?![a-z0-9_-])",
|
|
174
|
+
r"(?<![a-z0-9])(id[_-]?rsa|credentials|token|secret|passwd)(?![a-z0-9])",
|
|
175
|
+
r"(?<![a-z0-9_-])\.(npmrc|pypirc)(?![a-z0-9_-])",
|
|
176
|
+
),
|
|
131
177
|
):
|
|
132
|
-
|
|
133
|
-
if
|
|
134
|
-
|
|
178
|
+
categories.add("secret_access")
|
|
179
|
+
if _matches_any(
|
|
180
|
+
combined,
|
|
181
|
+
(_token_pattern("sudo", "chmod", "chown", "launchctl", "systemctl"),),
|
|
182
|
+
):
|
|
183
|
+
categories.add("privileged_system_mutation")
|
|
184
|
+
return categories
|
|
185
|
+
|
|
135
186
|
|
|
136
|
-
|
|
187
|
+
def _serialized_tool_arguments(arguments: object) -> str:
|
|
188
|
+
if arguments is None:
|
|
189
|
+
return ""
|
|
190
|
+
try:
|
|
191
|
+
return json.dumps(arguments, sort_keys=True, default=str)
|
|
192
|
+
except (TypeError, ValueError):
|
|
193
|
+
return str(arguments)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _matches_any(value: str, patterns: tuple[str, ...]) -> bool:
|
|
197
|
+
return any(re.search(pattern, value) is not None for pattern in patterns)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _token_pattern(*tokens: str) -> str:
|
|
201
|
+
alternatives = "|".join(re.escape(token) for token in tokens)
|
|
202
|
+
return rf"(?<![a-z0-9])({alternatives})(?![a-z0-9])"
|
|
137
203
|
|
|
138
204
|
|
|
139
205
|
def tool_call_risk_summary(artifact: GuardArtifact, arguments: object) -> str:
|
|
@@ -154,6 +220,7 @@ def allow_tool_call(
|
|
|
154
220
|
now: str,
|
|
155
221
|
signals: tuple[str, ...],
|
|
156
222
|
remember: bool,
|
|
223
|
+
risk_categories: tuple[str, ...] = (),
|
|
157
224
|
) -> GuardReceipt:
|
|
158
225
|
if remember:
|
|
159
226
|
store.upsert_policy(
|
|
@@ -196,6 +263,7 @@ def allow_tool_call(
|
|
|
196
263
|
"artifact_id": artifact.artifact_id,
|
|
197
264
|
"artifact_hash": artifact_hash,
|
|
198
265
|
"decision_source": decision_source,
|
|
266
|
+
"risk_categories": list(risk_categories),
|
|
199
267
|
"signals": list(signals),
|
|
200
268
|
},
|
|
201
269
|
now,
|
|
@@ -211,6 +279,7 @@ def block_tool_call(
|
|
|
211
279
|
decision_source: str,
|
|
212
280
|
now: str,
|
|
213
281
|
signals: tuple[str, ...],
|
|
282
|
+
risk_categories: tuple[str, ...] = (),
|
|
214
283
|
) -> GuardReceipt:
|
|
215
284
|
store.record_inventory_artifact(
|
|
216
285
|
artifact=artifact,
|
|
@@ -239,6 +308,7 @@ def block_tool_call(
|
|
|
239
308
|
"artifact_id": artifact.artifact_id,
|
|
240
309
|
"artifact_hash": artifact_hash,
|
|
241
310
|
"decision_source": decision_source,
|
|
311
|
+
"risk_categories": list(risk_categories),
|
|
242
312
|
"signals": list(signals),
|
|
243
313
|
},
|
|
244
314
|
now,
|
|
@@ -258,10 +328,18 @@ def _dedupe(values: list[str]) -> list[str]:
|
|
|
258
328
|
|
|
259
329
|
|
|
260
330
|
def _tool_name_tokens(tool_name: str) -> tuple[str, ...]:
|
|
261
|
-
camel_normalized =
|
|
331
|
+
camel_normalized = _camel_token_normalized(tool_name)
|
|
262
332
|
return tuple(token for token in re.findall(r"[a-z0-9]+", camel_normalized.lower()) if token)
|
|
263
333
|
|
|
264
334
|
|
|
335
|
+
def _risk_match_text(value: str) -> str:
|
|
336
|
+
return _camel_token_normalized(value).lower()
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def _camel_token_normalized(value: str) -> str:
|
|
340
|
+
return re.sub(r"([a-z0-9])([A-Z])", r"\1 \2", value)
|
|
341
|
+
|
|
342
|
+
|
|
265
343
|
def _coerce_guard_action(value: str) -> GuardAction | None:
|
|
266
344
|
for action in GUARD_ACTION_VALUES:
|
|
267
345
|
if value == action:
|
|
@@ -18,6 +18,7 @@ from ..mcp_tool_calls import (
|
|
|
18
18
|
build_tool_call_artifact,
|
|
19
19
|
build_tool_call_hash,
|
|
20
20
|
evaluate_tool_call,
|
|
21
|
+
tool_call_risk_categories,
|
|
21
22
|
tool_call_risk_summary,
|
|
22
23
|
)
|
|
23
24
|
from ..models import HarnessDetection
|
|
@@ -40,6 +41,7 @@ class RuntimeMcpGuardProxy:
|
|
|
40
41
|
source_scope: str,
|
|
41
42
|
config_path: str,
|
|
42
43
|
transport: str = "stdio",
|
|
44
|
+
server_id: str | None = None,
|
|
43
45
|
) -> None:
|
|
44
46
|
self.harness = harness
|
|
45
47
|
self.server_name = server_name
|
|
@@ -50,6 +52,7 @@ class RuntimeMcpGuardProxy:
|
|
|
50
52
|
self.source_scope = source_scope
|
|
51
53
|
self.config_path = config_path
|
|
52
54
|
self.transport = transport
|
|
55
|
+
self.server_id = server_id
|
|
53
56
|
self._inline_prompt_available = False
|
|
54
57
|
self._inline_prompt_counter = 0
|
|
55
58
|
self._buffered_child_responses: dict[str, list[dict[str, Any]]] = {}
|
|
@@ -185,6 +188,7 @@ class RuntimeMcpGuardProxy:
|
|
|
185
188
|
source_scope=self.source_scope,
|
|
186
189
|
config_path=self.config_path,
|
|
187
190
|
transport=self.transport,
|
|
191
|
+
server_id=self.server_id,
|
|
188
192
|
server_fingerprint={
|
|
189
193
|
"command": self.command,
|
|
190
194
|
"transport": self.transport,
|
|
@@ -209,6 +213,7 @@ class RuntimeMcpGuardProxy:
|
|
|
209
213
|
artifact_hash=artifact_hash,
|
|
210
214
|
decision_source=_decision_source(decision.action, decision.source),
|
|
211
215
|
signals=decision.signals,
|
|
216
|
+
risk_categories=decision.risk_categories,
|
|
212
217
|
params=params,
|
|
213
218
|
)
|
|
214
219
|
if self._allow_after_native_prompt(decision):
|
|
@@ -222,6 +227,7 @@ class RuntimeMcpGuardProxy:
|
|
|
222
227
|
artifact_hash=artifact_hash,
|
|
223
228
|
decision_source="native-approved",
|
|
224
229
|
signals=decision.signals,
|
|
230
|
+
risk_categories=decision.risk_categories,
|
|
225
231
|
params=params,
|
|
226
232
|
)
|
|
227
233
|
if self._inline_prompt_available and approval_callback is not None:
|
|
@@ -237,6 +243,7 @@ class RuntimeMcpGuardProxy:
|
|
|
237
243
|
artifact_hash=artifact_hash,
|
|
238
244
|
decision_source="inline-approved",
|
|
239
245
|
signals=decision.signals,
|
|
246
|
+
risk_categories=decision.risk_categories,
|
|
240
247
|
params=params,
|
|
241
248
|
remember=True,
|
|
242
249
|
)
|
|
@@ -248,6 +255,7 @@ class RuntimeMcpGuardProxy:
|
|
|
248
255
|
decision_source="inline-denied",
|
|
249
256
|
now=_now(),
|
|
250
257
|
signals=decision.signals,
|
|
258
|
+
risk_categories=decision.risk_categories,
|
|
251
259
|
)
|
|
252
260
|
return _blocked_tool_response(
|
|
253
261
|
message.get("id"),
|
|
@@ -289,6 +297,7 @@ class RuntimeMcpGuardProxy:
|
|
|
289
297
|
artifact_hash: str,
|
|
290
298
|
decision_source: str,
|
|
291
299
|
signals: tuple[str, ...],
|
|
300
|
+
risk_categories: tuple[str, ...],
|
|
292
301
|
params: dict[str, Any],
|
|
293
302
|
remember: bool = False,
|
|
294
303
|
) -> tuple[dict[str, Any], dict[str, Any]]:
|
|
@@ -299,6 +308,7 @@ class RuntimeMcpGuardProxy:
|
|
|
299
308
|
decision_source=decision_source,
|
|
300
309
|
now=_now(),
|
|
301
310
|
signals=signals,
|
|
311
|
+
risk_categories=risk_categories,
|
|
302
312
|
remember=remember,
|
|
303
313
|
)
|
|
304
314
|
response = self._forward_message(
|
|
@@ -537,6 +547,7 @@ class RuntimeMcpGuardProxy:
|
|
|
537
547
|
decision_source="approval-center-pending",
|
|
538
548
|
now=_now(),
|
|
539
549
|
signals=signals,
|
|
550
|
+
risk_categories=tool_call_risk_categories(artifact, params.get("arguments")),
|
|
540
551
|
)
|
|
541
552
|
request_id = str(queued[0]["request_id"]) if queued else "unknown"
|
|
542
553
|
return _blocked_tool_response(
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
SRC_PATH = Path(__file__).resolve().parents[1] / "src"
|
|
8
|
+
|
|
9
|
+
if str(SRC_PATH) not in sys.path:
|
|
10
|
+
sys.path.insert(0, str(SRC_PATH))
|
|
11
|
+
|
|
12
|
+
existing_pythonpath = os.environ.get("PYTHONPATH", "")
|
|
13
|
+
pythonpath_entries = [entry for entry in existing_pythonpath.split(os.pathsep) if entry]
|
|
14
|
+
if str(SRC_PATH) not in pythonpath_entries:
|
|
15
|
+
os.environ["PYTHONPATH"] = os.pathsep.join([str(SRC_PATH), *pythonpath_entries])
|