plugin-scanner 2.0.151__tar.gz → 2.0.152__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.151 → plugin_scanner-2.0.152}/PKG-INFO +1 -1
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/pyproject.toml +1 -1
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/pyproject.toml.bak +1 -1
- plugin_scanner-2.0.152/src/codex_plugin_scanner/guard/runtime/composition_rules.py +143 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/detectors.py +101 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/runner.py +9 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/version.py +1 -1
- plugin_scanner-2.0.152/tests/test_guard_bypass_detector.py +219 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.clusterfuzzlite/Dockerfile +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.clusterfuzzlite/build.sh +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.clusterfuzzlite/project.yaml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.clusterfuzzlite/requirements-atheris.txt +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.dockerignore +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.github/CODEOWNERS +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.github/dependabot.yml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.github/workflows/ci.yml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.github/workflows/codeql.yml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.github/workflows/dependabot-uv-lock.yml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.github/workflows/fuzz.yml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.github/workflows/harness-smoke.yml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.github/workflows/publish.yml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.github/workflows/scorecard.yml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.gitignore +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.pre-commit-hooks.yaml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/CONTRIBUTING.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/Dockerfile +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/LICENSE +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/README.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/SECURITY.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/index.html +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/package.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/pnpm-lock.yaml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/public/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/public/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/public/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/public/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/public/favicon.ico +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/app.tsx +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/approval-center-layout.test.ts +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/approval-center-layout.tsx +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/approval-center-primitives.tsx +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/approval-center-review-cards.tsx +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/approval-center-utils.ts +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/data-flow-evidence-card.tsx +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/fleet-workspace.tsx +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/guard-api.test.ts +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/guard-api.ts +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/guard-demo.ts +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/guard-types.ts +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/home-dashboard.tsx +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/main.tsx +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/queue-chip-filter.tsx +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/queue-state.test.ts +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/queue-state.ts +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/receipts-workspace.test.ts +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/receipts-workspace.tsx +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/risk-signal-cards.test.ts +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/risk-signal-cards.tsx +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/runtime-overview.test.ts +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/runtime-overview.tsx +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/scanner-evidence-badge.tsx +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/settings-workspace.test.ts +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/settings-workspace.tsx +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/styles.css +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/vite-env.d.ts +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/watched-app-card.tsx +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/tsconfig.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/vite.config.ts +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/docker-requirements.txt +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/docs/guard/approval-audit.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/docs/guard/architecture.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/docs/guard/get-started.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/docs/guard/harness-support.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/docs/guard/local-vs-cloud.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/docs/guard/release-checklist.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/docs/guard/release-notes.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/docs/guard/smoke-tests.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/docs/guard/testing-matrix.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/docs/trust/mcp-trust-draft.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/docs/trust/plugin-trust-draft.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/docs/trust/skill-trust-local.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/fuzzers/manifest_fuzzer.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/requirements.txt +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/schemas/plugin-quality.v1.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/schemas/scan-result.v1.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/schemas/verify-result.v1.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/__init__.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/action_runner.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/argparse_utils.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/checks/__init__.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/checks/claude.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/checks/gemini.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/checks/manifest.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/checks/opencode.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/checks/security.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/cli.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/cli_ui.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/config.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/github_reporting.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/__init__.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/access_graph_events.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/adapters/contracts.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/approvals.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/cli/commands.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/config.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/incident.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/launcher.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/models.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/protect.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/redaction.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/risk.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/action_identity.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/advisory_escalation.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/advisory_matchers.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/cisco_evidence.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/cisco_preflight.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/data_flow.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/data_flow_rules.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/data_flow_variables.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/false_positive_rules.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/mcp_protection.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/persistence_rules.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/prompt_injection.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/safe_decode.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/sandbox.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/scanner_cache.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/secret_sensitivity.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/secret_sources.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/shell_commands.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/skill_protection.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/supply_chain.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/temp_files.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/threat_intel.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/shims.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/store.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/store_evidence.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/store_threat_intel.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/types.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/lint_fixes.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/marketplace_support.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/models.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/path_support.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/policy.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/quality_artifact.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/repo_detect.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/reporting.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/rules/__init__.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/rules/registry.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/rules/specs.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/scanner.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/submission.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/suppressions.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/trust_helpers.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/trust_models.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/trust_scoring.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/trust_specs.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/verification.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/__init__.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/conftest.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/__init__.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/bad-plugin/.mcp.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/bad-plugin/secrets.js +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/claude-plugin-good/README.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/code-quality-bad/evil.js +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/code-quality-bad/inject.js +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/gemini-extension-good/README.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/good-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/good-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/good-plugin/README.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/good-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/README.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/benign-docs-fake-token.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/benign-health-endpoint.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/benign-nvmrc-fake-creds.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/benign-source-search.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/canary-exfil-encoded.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/canary-exfil.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/expected-decisions.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/malicious-dockerfile.txt +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/malicious-encoded-shell-exfil.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/malicious-github-action.yml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/malicious-mcp-delete.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/malicious-mcp-secret-read.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/malicious-mcp-skill-exfil.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/malicious-npm-postinstall.js +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/malicious-prompt-env-read.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/malicious-prompt-guard-bypass.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/malicious-prompt-npmrc-read.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/malicious-python-setup.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/guard-red-team/smoke-evidence-template.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/mcp-canary-server.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/mit-license/LICENSE +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/opencode-good/LICENSE +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/opencode-good/README.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/opencode-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/supply-chain/benign-npm-package.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/supply-chain/benign-pnpm-package.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/supply-chain/benign-pyproject.toml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/supply-chain/malicious-Dockerfile +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/supply-chain/malicious-action.yml +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/supply-chain/malicious-npm-package.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/supply-chain/malicious-setup.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/fixtures/with-marketplace/marketplace.json +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test-trust-scoring.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test-trust-specs.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_action_runner.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_best_practices.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_cisco_install_surfaces.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_cli.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_code_quality.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_config.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_coverage_remaining.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_ecosystems.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_edge_cases.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_final_coverage.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_access_graph.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_action_identity.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_advisory_escalation.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_approval_continuity.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_approval_copy_commands.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_approval_store_dedup.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_approval_store_scale.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_approvals.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_bootstrap.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_canary_fixtures.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_capabilities.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_cisco_evidence.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_cisco_runtime_cli.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_claude_adapter.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_cli.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_cloud_local_sync.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_codex_e2e.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_codex_install.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_codex_proxy.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_config_paths.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_connect_flow.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_consumer_mode.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_copilot_adapter.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_copilot_proxy.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_daemon_manager.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_daemon_perf.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_daemon_repair_perf.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_data_flow.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_decision_propagation.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_detector_fp.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_event_schema_v1.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_events.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_evidence_store.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_harness_contracts.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_harness_setup.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_harness_smoke.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_launch_env.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_mcp_protection.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_opencode_proxy.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_policy_dedup.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_product_flow.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_prompt_injection.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_protect.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_queue_api_contract.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_queue_contract.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_red_team.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_render.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_resolution_copy.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_risk.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_runtime.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_runtime_action_harnesses.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_runtime_actions.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_runtime_decisions.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_runtime_detectors.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_runtime_signals.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_safe_decode.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_sandbox.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_skill_protection.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_store_migrations.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_supply_chain.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_surface_server.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_threat_intel.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_verdicts.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_guard_web_recovery.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_hermes_adapter.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_integration.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_lint_fixes.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_live_cisco_smoke.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_manifest.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_marketplace.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_mcp_security.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_openclaw_adapter.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_operational_security.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_policy.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_quality_artifact.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_rule_registry.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_scanner.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_schema_contracts.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_security.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_security_ops.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_skill_security.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_submission.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_trust_scoring.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_trust_specs.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_verification.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/tests/test_versioning.py +0 -0
- {plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/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.152
|
|
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.152"
|
|
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.152"
|
|
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"
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""Signal composition rules for Guard detector action decisions.
|
|
2
|
+
|
|
3
|
+
Combines false-positive advisory signals with risk signals to produce a
|
|
4
|
+
calibrated action recommendation: allow, warn, ask, or block.
|
|
5
|
+
|
|
6
|
+
The base policy action (from config/approval policy) is used as the starting
|
|
7
|
+
point. Composition rules may only *downgrade* (block → ask, ask → warn,
|
|
8
|
+
warn → allow) when strong false-positive evidence is present, and may only
|
|
9
|
+
*upgrade* (warn → ask, ask → block) when high-confidence risk signals demand it.
|
|
10
|
+
|
|
11
|
+
Composition rules never override an explicit user policy choice.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
from typing import Literal
|
|
18
|
+
|
|
19
|
+
from codex_plugin_scanner.guard.runtime.signals import RiskSignalV2
|
|
20
|
+
|
|
21
|
+
ComposedAction = Literal["allow", "warn", "ask", "block"]
|
|
22
|
+
|
|
23
|
+
_ACTION_RANK: dict[ComposedAction, int] = {
|
|
24
|
+
"allow": 0,
|
|
25
|
+
"warn": 1,
|
|
26
|
+
"ask": 2,
|
|
27
|
+
"block": 3,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
_RANK_ACTION: dict[int, ComposedAction] = {v: k for k, v in _ACTION_RANK.items()}
|
|
31
|
+
|
|
32
|
+
_DOWNGRADE_BLOCK_CATEGORIES = frozenset({"bypass", "persistence"})
|
|
33
|
+
_DOWNGRADE_PROTECTED_SEVERITIES = frozenset({"critical", "high"})
|
|
34
|
+
_FP_DOWNGRADE_MAX_SEVERITY = frozenset({"info", "low"})
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass(frozen=True, slots=True)
|
|
38
|
+
class CompositionResult:
|
|
39
|
+
"""Result of applying composition rules to a set of signals."""
|
|
40
|
+
|
|
41
|
+
action: ComposedAction
|
|
42
|
+
reason: str
|
|
43
|
+
downgraded: bool
|
|
44
|
+
upgraded: bool
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def compose_action_from_signals(
|
|
48
|
+
signals: tuple[RiskSignalV2, ...],
|
|
49
|
+
base_action: ComposedAction,
|
|
50
|
+
) -> CompositionResult:
|
|
51
|
+
"""Apply composition rules to signals and return a calibrated action.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
signals: All signals from the detector run (risk + advisory).
|
|
55
|
+
base_action: The starting action from config/policy evaluation.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
A ``CompositionResult`` with the final action and an explanation.
|
|
59
|
+
"""
|
|
60
|
+
risk_signals = tuple(s for s in signals if s.category != "false_positive")
|
|
61
|
+
fp_signals = tuple(s for s in signals if s.category == "false_positive")
|
|
62
|
+
|
|
63
|
+
if not signals:
|
|
64
|
+
return CompositionResult(
|
|
65
|
+
action=base_action,
|
|
66
|
+
reason="no detector signals; base policy action applies",
|
|
67
|
+
downgraded=False,
|
|
68
|
+
upgraded=False,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
current_rank = _ACTION_RANK[base_action]
|
|
72
|
+
upgrade_reason: str | None = None
|
|
73
|
+
downgrade_reason: str | None = None
|
|
74
|
+
|
|
75
|
+
for signal in risk_signals:
|
|
76
|
+
if signal.category == "bypass" and signal.confidence in ("likely", "strong"):
|
|
77
|
+
new_rank = max(current_rank, _ACTION_RANK["block"])
|
|
78
|
+
if new_rank > current_rank:
|
|
79
|
+
upgrade_reason = f"bypass signal '{signal.detector}' forces block"
|
|
80
|
+
current_rank = new_rank
|
|
81
|
+
|
|
82
|
+
if signal.category == "persistence" and signal.severity in ("high", "critical"):
|
|
83
|
+
new_rank = max(current_rank, _ACTION_RANK["ask"])
|
|
84
|
+
if new_rank > current_rank:
|
|
85
|
+
upgrade_reason = upgrade_reason or f"persistence signal '{signal.detector}' requires review"
|
|
86
|
+
current_rank = new_rank
|
|
87
|
+
|
|
88
|
+
if signal.severity == "critical" and signal.confidence in ("likely", "strong"):
|
|
89
|
+
new_rank = max(current_rank, _ACTION_RANK["block"])
|
|
90
|
+
if new_rank > current_rank:
|
|
91
|
+
upgrade_reason = upgrade_reason or f"critical signal '{signal.detector}' forces block"
|
|
92
|
+
current_rank = new_rank
|
|
93
|
+
|
|
94
|
+
final_rank = current_rank
|
|
95
|
+
|
|
96
|
+
if fp_signals and not upgrade_reason:
|
|
97
|
+
all_fp_strong = all(s.confidence == "strong" for s in fp_signals)
|
|
98
|
+
risk_severities = frozenset(s.severity for s in risk_signals)
|
|
99
|
+
only_low_risk = risk_severities.issubset(_FP_DOWNGRADE_MAX_SEVERITY)
|
|
100
|
+
risk_cats = frozenset(s.category for s in risk_signals)
|
|
101
|
+
no_protected_cats = not risk_cats.intersection(_DOWNGRADE_BLOCK_CATEGORIES)
|
|
102
|
+
|
|
103
|
+
if all_fp_strong and only_low_risk and no_protected_cats and base_action == "block":
|
|
104
|
+
final_rank = min(final_rank, _ACTION_RANK["ask"])
|
|
105
|
+
downgrade_reason = "strong false-positive signals with only low-severity risk; downgraded block → ask"
|
|
106
|
+
|
|
107
|
+
elif all_fp_strong and only_low_risk and no_protected_cats and base_action == "ask":
|
|
108
|
+
source_search_present = any(s.signal_id.startswith("fp:source-search:") for s in fp_signals)
|
|
109
|
+
if source_search_present and not risk_signals:
|
|
110
|
+
final_rank = min(final_rank, _ACTION_RANK["warn"])
|
|
111
|
+
downgrade_reason = "strong source-search false-positive with no risk signals; downgraded ask → warn"
|
|
112
|
+
|
|
113
|
+
if upgrade_reason:
|
|
114
|
+
return CompositionResult(
|
|
115
|
+
action=_RANK_ACTION[final_rank],
|
|
116
|
+
reason=upgrade_reason,
|
|
117
|
+
downgraded=False,
|
|
118
|
+
upgraded=final_rank > _ACTION_RANK[base_action],
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
if downgrade_reason:
|
|
122
|
+
return CompositionResult(
|
|
123
|
+
action=_RANK_ACTION[final_rank],
|
|
124
|
+
reason=downgrade_reason,
|
|
125
|
+
downgraded=True,
|
|
126
|
+
upgraded=False,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
if risk_signals:
|
|
130
|
+
top = max(risk_signals, key=lambda s: (_ACTION_RANK.get("ask", 2), s.severity))
|
|
131
|
+
return CompositionResult(
|
|
132
|
+
action=_RANK_ACTION[final_rank],
|
|
133
|
+
reason=f"risk signal '{top.detector}' ({top.severity}/{top.confidence}); base action applies",
|
|
134
|
+
downgraded=False,
|
|
135
|
+
upgraded=False,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
return CompositionResult(
|
|
139
|
+
action=_RANK_ACTION[final_rank],
|
|
140
|
+
reason="advisory false-positive signals only; base action applies",
|
|
141
|
+
downgraded=False,
|
|
142
|
+
upgraded=False,
|
|
143
|
+
)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import re
|
|
5
6
|
import time
|
|
6
7
|
from collections.abc import Callable, Iterable, Mapping, Sequence
|
|
7
8
|
from dataclasses import dataclass
|
|
@@ -451,6 +452,105 @@ class PersistenceDetector:
|
|
|
451
452
|
)
|
|
452
453
|
|
|
453
454
|
|
|
455
|
+
class GuardBypassDetector:
|
|
456
|
+
"""Detects shell commands that uninstall, disable, or circumvent HOL Guard."""
|
|
457
|
+
|
|
458
|
+
detector_id = "bypass.shell"
|
|
459
|
+
categories: tuple[RiskSignalCategory, ...] = ("bypass",)
|
|
460
|
+
|
|
461
|
+
_UNINSTALL_PATTERN = re.compile(
|
|
462
|
+
r"(?:^|[\s;&|])"
|
|
463
|
+
r"(?:"
|
|
464
|
+
r"pip(?:3)?\s+uninstall\s+(?:-y\s+)?(?:holguard|hol[_-]guard|codex[_-]plugin[_-]scanner)\b|"
|
|
465
|
+
r"brew\s+(?:uninstall|remove)\s+hol[_-]guard\b|"
|
|
466
|
+
r"npm\s+(?:uninstall|remove)\s+(?:-g\s+)?hol[_-]guard\b|"
|
|
467
|
+
r"apt(?:-get)?\s+(?:remove|purge)\s+hol[_-]guard\b"
|
|
468
|
+
r")",
|
|
469
|
+
re.IGNORECASE,
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
_CONFIG_DESTROY_PATTERN = re.compile(
|
|
473
|
+
r"(?:^|[\s;&|])"
|
|
474
|
+
r"(?:rm|rmdir)\b[^\r\n;&|]{0,100}"
|
|
475
|
+
r"(?:~?/?\.hol[_-]guard|guard[_-]home|(?<![a-zA-Z0-9_])guard\.db(?![a-zA-Z0-9_])|(?<![a-zA-Z0-9_])guard\.lock(?![a-zA-Z0-9_]))",
|
|
476
|
+
re.IGNORECASE,
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
_DAEMON_KILL_PATTERN = re.compile(
|
|
480
|
+
r"(?:^|[\s;&|])"
|
|
481
|
+
r"(?:"
|
|
482
|
+
r"kill\b[^\r\n;&|]{0,80}hol[_-]guard|"
|
|
483
|
+
r"pkill\b[^\r\n;&|]{0,40}(?<![a-zA-Z0-9_])hol[_-]guard(?![a-zA-Z0-9_])|"
|
|
484
|
+
r"launchctl\s+(?:unload|disable)\b[^\r\n;&|]{0,80}(?:hol[_-]guard|com\.hol\.guard)"
|
|
485
|
+
r")",
|
|
486
|
+
re.IGNORECASE,
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
def detect(self, action: GuardActionEnvelope, context: DetectorContext) -> tuple[RiskSignalV2, ...]:
|
|
490
|
+
del context
|
|
491
|
+
if action.action_type not in ("shell_command", "prompt") or action.command is None:
|
|
492
|
+
return ()
|
|
493
|
+
signals: list[RiskSignalV2] = []
|
|
494
|
+
if self._UNINSTALL_PATTERN.search(action.command):
|
|
495
|
+
signals.append(
|
|
496
|
+
RiskSignalV2(
|
|
497
|
+
signal_id="bypass:guard-uninstall",
|
|
498
|
+
category="bypass",
|
|
499
|
+
severity="critical",
|
|
500
|
+
confidence="strong",
|
|
501
|
+
detector=self.detector_id,
|
|
502
|
+
title="Command uninstalls HOL Guard",
|
|
503
|
+
plain_reason=("This command removes HOL Guard, which would disable all AI harness protection."),
|
|
504
|
+
technical_detail="matched guard uninstall pattern",
|
|
505
|
+
evidence_ref="command",
|
|
506
|
+
redaction_level="summary",
|
|
507
|
+
false_positive_hint=("Allow only if you intentionally want to remove Guard from this machine."),
|
|
508
|
+
advisory_id=None,
|
|
509
|
+
)
|
|
510
|
+
)
|
|
511
|
+
if self._CONFIG_DESTROY_PATTERN.search(action.command):
|
|
512
|
+
signals.append(
|
|
513
|
+
RiskSignalV2(
|
|
514
|
+
signal_id="bypass:guard-config-destroy",
|
|
515
|
+
category="bypass",
|
|
516
|
+
severity="critical",
|
|
517
|
+
confidence="strong",
|
|
518
|
+
detector=self.detector_id,
|
|
519
|
+
title="Command destroys Guard configuration or data",
|
|
520
|
+
plain_reason=(
|
|
521
|
+
"This command deletes HOL Guard configuration or state files,"
|
|
522
|
+
" which would reset all protection settings and history."
|
|
523
|
+
),
|
|
524
|
+
technical_detail="matched guard config/data deletion pattern",
|
|
525
|
+
evidence_ref="command",
|
|
526
|
+
redaction_level="summary",
|
|
527
|
+
false_positive_hint=("Allow only if you intend to fully reset Guard and are aware of data loss."),
|
|
528
|
+
advisory_id=None,
|
|
529
|
+
)
|
|
530
|
+
)
|
|
531
|
+
if self._DAEMON_KILL_PATTERN.search(action.command):
|
|
532
|
+
signals.append(
|
|
533
|
+
RiskSignalV2(
|
|
534
|
+
signal_id="bypass:guard-daemon-kill",
|
|
535
|
+
category="bypass",
|
|
536
|
+
severity="high",
|
|
537
|
+
confidence="strong",
|
|
538
|
+
detector=self.detector_id,
|
|
539
|
+
title="Command stops HOL Guard daemon",
|
|
540
|
+
plain_reason=(
|
|
541
|
+
"This command stops the HOL Guard background service,"
|
|
542
|
+
" which temporarily disables harness protection."
|
|
543
|
+
),
|
|
544
|
+
technical_detail="matched guard daemon kill/unload pattern",
|
|
545
|
+
evidence_ref="command",
|
|
546
|
+
redaction_level="summary",
|
|
547
|
+
false_positive_hint="Allow only if you intentionally want to pause Guard for maintenance.",
|
|
548
|
+
advisory_id=None,
|
|
549
|
+
)
|
|
550
|
+
)
|
|
551
|
+
return tuple(signals)
|
|
552
|
+
|
|
553
|
+
|
|
454
554
|
def register_default_detectors() -> tuple[GuardDetector, ...]:
|
|
455
555
|
"""Return the default ordered detector list.
|
|
456
556
|
|
|
@@ -468,6 +568,7 @@ def register_default_detectors() -> tuple[GuardDetector, ...]:
|
|
|
468
568
|
CiscoSkillPreflightDetector(),
|
|
469
569
|
FalsePositiveSuppressorDetector(),
|
|
470
570
|
DataFlowExfiltrationDetector(),
|
|
571
|
+
GuardBypassDetector(),
|
|
471
572
|
PersistenceDetector(),
|
|
472
573
|
PromptInjectionDetector(),
|
|
473
574
|
SafeDecodeDetector(),
|
{plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/src/codex_plugin_scanner/guard/runtime/runner.py
RENAMED
|
@@ -29,6 +29,7 @@ from ..redaction import redact_sensitive_text
|
|
|
29
29
|
from ..store import GuardStore
|
|
30
30
|
from ..types import PromptRequest, RemediationAction
|
|
31
31
|
from .actions import GuardActionEnvelope, redacted_workspace_label
|
|
32
|
+
from .composition_rules import compose_action_from_signals
|
|
32
33
|
from .detectors import DetectorContext, DetectorRegistry, DetectorRunResult, register_default_detectors
|
|
33
34
|
from .prompt_injection import detect_prompt_injection_requests
|
|
34
35
|
|
|
@@ -403,6 +404,14 @@ def _evaluation_with_detector_registry(
|
|
|
403
404
|
"runtime_detector_signals_v2": [signal.to_dict() for signal in result.signals],
|
|
404
405
|
"runtime_detector_telemetry": [item.to_dict() for item in result.telemetry],
|
|
405
406
|
}
|
|
407
|
+
base_action: str = "block" if evaluation.get("blocked") else "allow"
|
|
408
|
+
composition = compose_action_from_signals(result.signals, base_action) # type: ignore[arg-type]
|
|
409
|
+
next_evaluation["runtime_detector_composition"] = {
|
|
410
|
+
"action": composition.action,
|
|
411
|
+
"reason": composition.reason,
|
|
412
|
+
"downgraded": composition.downgraded,
|
|
413
|
+
"upgraded": composition.upgraded,
|
|
414
|
+
}
|
|
406
415
|
if trace_error is not None:
|
|
407
416
|
next_evaluation["runtime_detector_trace_error"] = trace_error
|
|
408
417
|
return next_evaluation
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"""Tests for GuardBypassDetector and composition_rules."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from codex_plugin_scanner.guard.config import GuardConfig
|
|
10
|
+
from codex_plugin_scanner.guard.runtime.actions import GuardActionEnvelope
|
|
11
|
+
from codex_plugin_scanner.guard.runtime.composition_rules import compose_action_from_signals
|
|
12
|
+
from codex_plugin_scanner.guard.runtime.detectors import DetectorContext, GuardBypassDetector
|
|
13
|
+
from codex_plugin_scanner.guard.runtime.signals import RiskSignalV2
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _make_signal(
|
|
17
|
+
signal_id: str = "test:signal",
|
|
18
|
+
category: str = "bypass",
|
|
19
|
+
severity: str = "high",
|
|
20
|
+
confidence: str = "strong",
|
|
21
|
+
detector: str = "test.detector",
|
|
22
|
+
) -> RiskSignalV2:
|
|
23
|
+
return RiskSignalV2(
|
|
24
|
+
signal_id=signal_id,
|
|
25
|
+
category=category,
|
|
26
|
+
severity=severity,
|
|
27
|
+
confidence=confidence,
|
|
28
|
+
detector=detector,
|
|
29
|
+
title="Test",
|
|
30
|
+
plain_reason="test reason",
|
|
31
|
+
technical_detail=None,
|
|
32
|
+
evidence_ref=None,
|
|
33
|
+
redaction_level="none",
|
|
34
|
+
false_positive_hint=None,
|
|
35
|
+
advisory_id=None,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _bypass_envelope(command: str) -> GuardActionEnvelope:
|
|
40
|
+
return GuardActionEnvelope(
|
|
41
|
+
schema_version=1,
|
|
42
|
+
action_id="",
|
|
43
|
+
harness="codex",
|
|
44
|
+
event_name="BashCommand",
|
|
45
|
+
action_type="shell_command",
|
|
46
|
+
workspace=None,
|
|
47
|
+
workspace_hash=None,
|
|
48
|
+
tool_name="bash",
|
|
49
|
+
command=command,
|
|
50
|
+
prompt_excerpt=None,
|
|
51
|
+
prompt_text=None,
|
|
52
|
+
target_paths=(),
|
|
53
|
+
network_hosts=(),
|
|
54
|
+
mcp_server=None,
|
|
55
|
+
mcp_tool=None,
|
|
56
|
+
package_manager=None,
|
|
57
|
+
package_name=None,
|
|
58
|
+
script_name=None,
|
|
59
|
+
raw_payload_redacted={},
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _detector_context(tmp_path: Path) -> DetectorContext:
|
|
64
|
+
return DetectorContext(
|
|
65
|
+
config=GuardConfig(guard_home=tmp_path / "guard-home", workspace=tmp_path / "workspace"),
|
|
66
|
+
workspace=tmp_path / "workspace",
|
|
67
|
+
prior_decisions={},
|
|
68
|
+
threat_intel={},
|
|
69
|
+
redaction_settings={},
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class TestGuardBypassDetector:
|
|
74
|
+
detector = GuardBypassDetector()
|
|
75
|
+
|
|
76
|
+
def _detect(self, command: str, tmp_path: Path) -> tuple:
|
|
77
|
+
ctx = _detector_context(tmp_path)
|
|
78
|
+
env = _bypass_envelope(command)
|
|
79
|
+
return self.detector.detect(env, ctx)
|
|
80
|
+
|
|
81
|
+
def test_pip_uninstall_holguard(self, tmp_path: Path) -> None:
|
|
82
|
+
signals = self._detect("pip uninstall holguard", tmp_path)
|
|
83
|
+
assert any(s.signal_id == "bypass:guard-uninstall" for s in signals)
|
|
84
|
+
assert all(s.severity == "critical" for s in signals)
|
|
85
|
+
|
|
86
|
+
def test_pip3_uninstall_holguard_with_y(self, tmp_path: Path) -> None:
|
|
87
|
+
signals = self._detect("pip3 uninstall -y holguard", tmp_path)
|
|
88
|
+
assert any(s.signal_id == "bypass:guard-uninstall" for s in signals)
|
|
89
|
+
|
|
90
|
+
def test_pip_uninstall_codex_plugin_scanner(self, tmp_path: Path) -> None:
|
|
91
|
+
signals = self._detect("pip uninstall codex-plugin-scanner", tmp_path)
|
|
92
|
+
assert any(s.signal_id == "bypass:guard-uninstall" for s in signals)
|
|
93
|
+
|
|
94
|
+
def test_brew_uninstall_hol_guard(self, tmp_path: Path) -> None:
|
|
95
|
+
signals = self._detect("brew uninstall hol-guard", tmp_path)
|
|
96
|
+
assert any(s.signal_id == "bypass:guard-uninstall" for s in signals)
|
|
97
|
+
|
|
98
|
+
def test_rm_guard_db(self, tmp_path: Path) -> None:
|
|
99
|
+
signals = self._detect("rm ~/.hol-guard/guard.db", tmp_path)
|
|
100
|
+
assert any(s.signal_id == "bypass:guard-config-destroy" for s in signals)
|
|
101
|
+
|
|
102
|
+
def test_rm_guard_home(self, tmp_path: Path) -> None:
|
|
103
|
+
signals = self._detect("rm -rf ~/.hol-guard", tmp_path)
|
|
104
|
+
assert any(s.signal_id == "bypass:guard-config-destroy" for s in signals)
|
|
105
|
+
|
|
106
|
+
def test_kill_guard_daemon(self, tmp_path: Path) -> None:
|
|
107
|
+
signals = self._detect("kill -9 $(pgrep hol-guard)", tmp_path)
|
|
108
|
+
assert any(s.signal_id == "bypass:guard-daemon-kill" for s in signals)
|
|
109
|
+
|
|
110
|
+
def test_pkill_hol_guard(self, tmp_path: Path) -> None:
|
|
111
|
+
signals = self._detect("pkill -f hol-guard", tmp_path)
|
|
112
|
+
assert any(s.signal_id == "bypass:guard-daemon-kill" for s in signals)
|
|
113
|
+
|
|
114
|
+
def test_pkill_wireguard_is_not_bypass(self, tmp_path: Path) -> None:
|
|
115
|
+
signals = self._detect("pkill -f wireguard", tmp_path)
|
|
116
|
+
assert not any(s.signal_id == "bypass:guard-daemon-kill" for s in signals)
|
|
117
|
+
|
|
118
|
+
def test_rm_myguard_db_backup_is_not_bypass(self, tmp_path: Path) -> None:
|
|
119
|
+
signals = self._detect("rm ./myguard.db.backup", tmp_path)
|
|
120
|
+
assert not any(s.signal_id == "bypass:guard-config-destroy" for s in signals)
|
|
121
|
+
|
|
122
|
+
def test_pkill_safeguard_worker_is_not_bypass(self, tmp_path: Path) -> None:
|
|
123
|
+
signals = self._detect("pkill -f safeguard-worker", tmp_path)
|
|
124
|
+
assert not any(s.signal_id == "bypass:guard-daemon-kill" for s in signals)
|
|
125
|
+
|
|
126
|
+
def test_launchctl_unload_guard(self, tmp_path: Path) -> None:
|
|
127
|
+
signals = self._detect("launchctl unload ~/Library/LaunchAgents/hol-guard.plist", tmp_path)
|
|
128
|
+
assert any(s.signal_id == "bypass:guard-daemon-kill" for s in signals)
|
|
129
|
+
|
|
130
|
+
def test_benign_pip_install_not_flagged(self, tmp_path: Path) -> None:
|
|
131
|
+
signals = self._detect("pip install requests", tmp_path)
|
|
132
|
+
assert signals == ()
|
|
133
|
+
|
|
134
|
+
def test_benign_rm_log_not_flagged(self, tmp_path: Path) -> None:
|
|
135
|
+
signals = self._detect("rm -rf /tmp/myproject.log", tmp_path)
|
|
136
|
+
assert signals == ()
|
|
137
|
+
|
|
138
|
+
def test_benign_kill_other_process_not_flagged(self, tmp_path: Path) -> None:
|
|
139
|
+
signals = self._detect("kill -9 12345", tmp_path)
|
|
140
|
+
assert signals == ()
|
|
141
|
+
|
|
142
|
+
def test_npm_uninstall_hol_guard(self, tmp_path: Path) -> None:
|
|
143
|
+
signals = self._detect("npm uninstall -g hol-guard", tmp_path)
|
|
144
|
+
assert any(s.signal_id == "bypass:guard-uninstall" for s in signals)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class TestComposeActionFromSignals:
|
|
148
|
+
"""Tests for composition_rules.compose_action_from_signals."""
|
|
149
|
+
|
|
150
|
+
def test_no_signals_returns_base_action(self) -> None:
|
|
151
|
+
result = compose_action_from_signals((), "allow")
|
|
152
|
+
assert result.action == "allow"
|
|
153
|
+
assert not result.upgraded
|
|
154
|
+
assert not result.downgraded
|
|
155
|
+
|
|
156
|
+
def test_no_signals_block_base(self) -> None:
|
|
157
|
+
result = compose_action_from_signals((), "block")
|
|
158
|
+
assert result.action == "block"
|
|
159
|
+
|
|
160
|
+
def test_bypass_signal_upgrades_to_block(self) -> None:
|
|
161
|
+
signal = _make_signal(
|
|
162
|
+
signal_id="bypass:guard-uninstall", category="bypass", severity="critical", confidence="strong"
|
|
163
|
+
)
|
|
164
|
+
result = compose_action_from_signals((signal,), "allow")
|
|
165
|
+
assert result.action == "block"
|
|
166
|
+
assert result.upgraded
|
|
167
|
+
|
|
168
|
+
def test_persistence_signal_upgrades_to_ask(self) -> None:
|
|
169
|
+
signal = _make_signal(signal_id="persist:cron", category="persistence", severity="high", confidence="strong")
|
|
170
|
+
result = compose_action_from_signals((signal,), "allow")
|
|
171
|
+
assert result.action in ("ask", "block")
|
|
172
|
+
assert result.upgraded
|
|
173
|
+
|
|
174
|
+
def test_critical_risk_signal_upgrades_to_block(self) -> None:
|
|
175
|
+
signal = _make_signal(signal_id="risk:critical", category="data_flow", severity="critical", confidence="strong")
|
|
176
|
+
result = compose_action_from_signals((signal,), "allow")
|
|
177
|
+
assert result.action == "block"
|
|
178
|
+
assert result.upgraded
|
|
179
|
+
|
|
180
|
+
def test_strong_fp_with_no_risk_downgrades_block_to_ask(self) -> None:
|
|
181
|
+
fp = _make_signal(
|
|
182
|
+
signal_id="fp:source-search:grep", category="false_positive", severity="info", confidence="strong"
|
|
183
|
+
)
|
|
184
|
+
result = compose_action_from_signals((fp,), "block")
|
|
185
|
+
assert result.action == "ask"
|
|
186
|
+
assert result.downgraded
|
|
187
|
+
|
|
188
|
+
def test_strong_fp_source_search_downgrades_ask_to_warn(self) -> None:
|
|
189
|
+
fp = _make_signal(
|
|
190
|
+
signal_id="fp:source-search:grep", category="false_positive", severity="info", confidence="strong"
|
|
191
|
+
)
|
|
192
|
+
result = compose_action_from_signals((fp,), "ask")
|
|
193
|
+
assert result.action == "warn"
|
|
194
|
+
assert result.downgraded
|
|
195
|
+
|
|
196
|
+
def test_bypass_beats_fp_downgrade(self) -> None:
|
|
197
|
+
bypass = _make_signal(
|
|
198
|
+
signal_id="bypass:guard-uninstall", category="bypass", severity="critical", confidence="strong"
|
|
199
|
+
)
|
|
200
|
+
fp = _make_signal(
|
|
201
|
+
signal_id="fp:source-search:grep", category="false_positive", severity="info", confidence="strong"
|
|
202
|
+
)
|
|
203
|
+
result = compose_action_from_signals((bypass, fp), "allow")
|
|
204
|
+
assert result.action == "block"
|
|
205
|
+
assert result.upgraded
|
|
206
|
+
assert not result.downgraded
|
|
207
|
+
|
|
208
|
+
def test_fp_weak_confidence_does_not_downgrade(self) -> None:
|
|
209
|
+
fp = _make_signal(
|
|
210
|
+
signal_id="fp:source-search:grep", category="false_positive", severity="info", confidence="weak"
|
|
211
|
+
)
|
|
212
|
+
result = compose_action_from_signals((fp,), "block")
|
|
213
|
+
assert result.action == "block"
|
|
214
|
+
assert not result.downgraded
|
|
215
|
+
|
|
216
|
+
def test_composition_result_is_frozen(self) -> None:
|
|
217
|
+
result = compose_action_from_signals((), "allow")
|
|
218
|
+
with pytest.raises((AttributeError, TypeError)):
|
|
219
|
+
result.action = "block" # type: ignore[misc]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/.github/ISSUE_TEMPLATE/feature-request.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/approval-center-layout.test.ts
RENAMED
|
File without changes
|
|
File without changes
|
{plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/approval-center-primitives.tsx
RENAMED
|
File without changes
|
{plugin_scanner-2.0.151 → plugin_scanner-2.0.152}/dashboard/src/approval-center-review-cards.tsx
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|