plugin-scanner 2.0.105__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.105 → plugin_scanner-2.0.107}/PKG-INFO +1 -1
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/pyproject.toml +1 -1
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/pyproject.toml.bak +1 -1
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +85 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/capabilities.py +19 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/commands.py +17 -4
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +93 -15
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +11 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/risk.py +2 -6
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/actions.py +32 -2
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/detectors.py +43 -1
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +3 -45
- plugin_scanner-2.0.107/src/codex_plugin_scanner/guard/runtime/secret_sensitivity.py +217 -0
- {plugin_scanner-2.0.105 → 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.105 → plugin_scanner-2.0.107}/tests/test_guard_cli.py +37 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_risk.py +60 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_runtime.py +48 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_runtime_actions.py +45 -1
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_runtime_detectors.py +156 -3
- plugin_scanner-2.0.105/tests/conftest.py +0 -9
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.clusterfuzzlite/Dockerfile +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.clusterfuzzlite/build.sh +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.clusterfuzzlite/project.yaml +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.clusterfuzzlite/requirements-atheris.txt +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.dockerignore +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.github/CODEOWNERS +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.github/dependabot.yml +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.github/workflows/ci.yml +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.github/workflows/codeql.yml +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.github/workflows/dependabot-uv-lock.yml +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.github/workflows/fuzz.yml +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.github/workflows/harness-smoke.yml +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.github/workflows/publish.yml +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.github/workflows/scorecard.yml +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.gitignore +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/.pre-commit-hooks.yaml +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/CONTRIBUTING.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/Dockerfile +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/LICENSE +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/README.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/SECURITY.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/index.html +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/package.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/pnpm-lock.yaml +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/public/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/public/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/public/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/public/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/public/favicon.ico +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/src/app.tsx +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/src/approval-center-layout.tsx +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/src/approval-center-primitives.tsx +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/src/approval-center-utils.ts +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/src/fleet-workspace.tsx +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/src/guard-api.test.ts +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/src/guard-api.ts +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/src/guard-demo.ts +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/src/guard-types.ts +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/src/main.tsx +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/src/receipts-workspace.tsx +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/src/runtime-overview.tsx +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/src/settings-workspace.tsx +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/src/styles.css +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/src/vite-env.d.ts +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/tsconfig.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/dashboard/vite.config.ts +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/docker-requirements.txt +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/docs/guard/approval-audit.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/docs/guard/architecture.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/docs/guard/get-started.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/docs/guard/harness-support.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/docs/guard/local-vs-cloud.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/docs/guard/testing-matrix.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/docs/trust/mcp-trust-draft.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/docs/trust/plugin-trust-draft.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/docs/trust/skill-trust-local.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/fuzzers/manifest_fuzzer.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/requirements.txt +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/schemas/plugin-quality.v1.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/schemas/scan-result.v1.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/schemas/verify-result.v1.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/__init__.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/action_runner.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/argparse_utils.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/__init__.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/claude.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/gemini.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/manifest.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/opencode.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/security.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/cli.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/cli_ui.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/config.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/github_reporting.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/__init__.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/approvals.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/config.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/incident.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/launcher.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/models.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/protect.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/redaction.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/shims.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/store.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/types.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/lint_fixes.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/marketplace_support.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/models.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/path_support.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/policy.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/quality_artifact.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/repo_detect.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/reporting.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/rules/__init__.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/rules/registry.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/rules/specs.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/scanner.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/submission.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/suppressions.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_helpers.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_models.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_scoring.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/trust_specs.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/verification.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/__init__.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/__init__.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/bad-plugin/.mcp.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/bad-plugin/secrets.js +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/claude-plugin-good/README.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/code-quality-bad/evil.js +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/code-quality-bad/inject.js +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/gemini-extension-good/README.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/README.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/mcp-canary-server.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/mit-license/LICENSE +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/opencode-good/LICENSE +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/opencode-good/README.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/opencode-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/fixtures/with-marketplace/marketplace.json +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test-trust-scoring.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test-trust-specs.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_action_runner.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_best_practices.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_cisco_install_surfaces.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_cli.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_code_quality.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_config.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_coverage_remaining.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_ecosystems.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_edge_cases.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_final_coverage.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_approvals.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_bootstrap.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_capabilities.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_claude_adapter.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_codex_e2e.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_codex_install.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_codex_proxy.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_config_paths.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_connect_flow.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_consumer_mode.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_copilot_adapter.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_copilot_proxy.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_daemon_manager.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_event_schema_v1.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_events.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_launch_env.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_opencode_proxy.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_product_flow.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_protect.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_render.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_runtime_action_harnesses.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_runtime_decisions.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_runtime_signals.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_store_migrations.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_surface_server.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_guard_verdicts.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_hermes_adapter.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_integration.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_lint_fixes.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_live_cisco_smoke.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_manifest.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_marketplace.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_mcp_security.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_openclaw_adapter.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_operational_security.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_policy.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_quality_artifact.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_rule_registry.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_scanner.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_schema_contracts.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_security.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_security_ops.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_skill_security.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_submission.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_trust_scoring.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_trust_specs.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_verification.py +0 -0
- {plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/tests/test_versioning.py +0 -0
- {plugin_scanner-2.0.105 → 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.105 → 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.105 → 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.105 → 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(
|
|
@@ -8,6 +8,7 @@ from pathlib import PurePath
|
|
|
8
8
|
from urllib.parse import urlsplit
|
|
9
9
|
|
|
10
10
|
from .models import GuardArtifact
|
|
11
|
+
from .runtime.secret_sensitivity import classify_legacy_secret_path_families
|
|
11
12
|
from .runtime.signals import RiskSignalV2
|
|
12
13
|
from .types import GuardSignal
|
|
13
14
|
|
|
@@ -305,12 +306,7 @@ def extract_network_hosts(text: str) -> set[str]:
|
|
|
305
306
|
def classify_secret_paths(text: str) -> set[str]:
|
|
306
307
|
"""Classify secret-bearing file families referenced in text."""
|
|
307
308
|
|
|
308
|
-
|
|
309
|
-
classes: set[str] = set()
|
|
310
|
-
for pattern, label in _SECRET_PATH_LABELS:
|
|
311
|
-
if pattern in lowered:
|
|
312
|
-
classes.add(label)
|
|
313
|
-
return classes
|
|
309
|
+
return classify_legacy_secret_path_families(text)
|
|
314
310
|
|
|
315
311
|
|
|
316
312
|
def detect_encoded_command(text: str) -> list[GuardSignal]:
|
{plugin_scanner-2.0.105 → plugin_scanner-2.0.107}/src/codex_plugin_scanner/guard/runtime/actions.py
RENAMED
|
@@ -11,6 +11,7 @@ from pathlib import Path, PureWindowsPath
|
|
|
11
11
|
from typing import Literal
|
|
12
12
|
|
|
13
13
|
from ..redaction import redact_text
|
|
14
|
+
from .secret_sensitivity import redacted_secret_path_context
|
|
14
15
|
|
|
15
16
|
GuardActionType = Literal[
|
|
16
17
|
"prompt",
|
|
@@ -43,7 +44,23 @@ _SCHEMA_VERSION = 1
|
|
|
43
44
|
_SHELL_TOOL_NAMES = frozenset({"bash", "shell", "sh", "zsh", "terminal", "run_command", "run_terminal_command"})
|
|
44
45
|
_FILE_READ_TOOL_NAMES = frozenset({"read", "read_file", "open_file", "view", "view_file", "cat_file"})
|
|
45
46
|
_FILE_WRITE_TOOL_NAMES = frozenset({"write", "edit", "multiedit", "write_file", "edit_file"})
|
|
46
|
-
_PATH_KEYS = (
|
|
47
|
+
_PATH_KEYS = (
|
|
48
|
+
"path",
|
|
49
|
+
"paths",
|
|
50
|
+
"file_path",
|
|
51
|
+
"file_paths",
|
|
52
|
+
"filePath",
|
|
53
|
+
"filePaths",
|
|
54
|
+
"filepath",
|
|
55
|
+
"file",
|
|
56
|
+
"files",
|
|
57
|
+
"filename",
|
|
58
|
+
"filenames",
|
|
59
|
+
"target_path",
|
|
60
|
+
"target_paths",
|
|
61
|
+
"targetPath",
|
|
62
|
+
"targetPaths",
|
|
63
|
+
)
|
|
47
64
|
_COMMAND_KEYS = ("command", "cmd", "shell_command", "shellCommand")
|
|
48
65
|
_SENSITIVE_RAW_KEYS = frozenset(
|
|
49
66
|
{
|
|
@@ -652,6 +669,8 @@ def _target_paths(
|
|
|
652
669
|
value = tool_input.get(key)
|
|
653
670
|
if isinstance(value, str) and value.strip():
|
|
654
671
|
paths.append(value.strip())
|
|
672
|
+
elif isinstance(value, list):
|
|
673
|
+
paths.extend(item.strip() for item in value if isinstance(item, str) and item.strip())
|
|
655
674
|
for text in (command, prompt_text):
|
|
656
675
|
if text is not None:
|
|
657
676
|
paths.extend(match.group("path") for match in _PROMPT_PATH_PATTERN.finditer(text))
|
|
@@ -687,14 +706,25 @@ def _redacted_target_path(path: str, *, home_dir: Path | str | None) -> str | No
|
|
|
687
706
|
if stripped == "~" or stripped.startswith("~/"):
|
|
688
707
|
return redact_text(stripped).text
|
|
689
708
|
if stripped.startswith("~"):
|
|
709
|
+
secret_context = redacted_secret_path_context(stripped)
|
|
710
|
+
if secret_context is not None:
|
|
711
|
+
return secret_context
|
|
690
712
|
target_name = Path(stripped).name or "path"
|
|
691
713
|
return f".../{target_name}"
|
|
692
714
|
windows_path = PureWindowsPath(stripped)
|
|
693
715
|
if windows_path.is_absolute():
|
|
716
|
+
secret_context = redacted_secret_path_context(stripped)
|
|
717
|
+
if secret_context is not None:
|
|
718
|
+
return secret_context
|
|
694
719
|
target_name = windows_path.name or "path"
|
|
695
720
|
return f".../{target_name}"
|
|
696
721
|
if _is_absolute_target_path(stripped):
|
|
697
|
-
|
|
722
|
+
redacted_path = redacted_workspace_label(stripped, home_dir=home_dir)
|
|
723
|
+
if redacted_path.startswith(".../"):
|
|
724
|
+
secret_context = redacted_secret_path_context(stripped)
|
|
725
|
+
if secret_context is not None:
|
|
726
|
+
return secret_context
|
|
727
|
+
return redacted_path
|
|
698
728
|
return redact_text(stripped).text
|
|
699
729
|
|
|
700
730
|
|