plugin-scanner 2.0.133__tar.gz → 2.0.134__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.133 → plugin_scanner-2.0.134}/PKG-INFO +1 -1
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/pyproject.toml +1 -1
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/pyproject.toml.bak +1 -1
- plugin_scanner-2.0.134/src/codex_plugin_scanner/guard/runtime/action_identity.py +87 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/version.py +1 -1
- plugin_scanner-2.0.134/tests/test_guard_action_identity.py +155 -0
- plugin_scanner-2.0.134/tests/test_guard_policy_dedup.py +301 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.clusterfuzzlite/Dockerfile +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.clusterfuzzlite/build.sh +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.clusterfuzzlite/project.yaml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.clusterfuzzlite/requirements-atheris.txt +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.dockerignore +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.github/CODEOWNERS +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.github/dependabot.yml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.github/workflows/ci.yml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.github/workflows/codeql.yml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.github/workflows/dependabot-uv-lock.yml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.github/workflows/fuzz.yml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.github/workflows/harness-smoke.yml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.github/workflows/publish.yml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.github/workflows/scorecard.yml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.gitignore +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/.pre-commit-hooks.yaml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/CONTRIBUTING.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/Dockerfile +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/LICENSE +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/README.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/SECURITY.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/index.html +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/package.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/pnpm-lock.yaml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/public/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/public/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/public/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/public/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/public/favicon.ico +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/app.tsx +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/approval-center-layout.test.ts +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/approval-center-layout.tsx +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/approval-center-primitives.tsx +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/approval-center-review-cards.tsx +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/approval-center-utils.ts +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/data-flow-evidence-card.tsx +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/fleet-workspace.tsx +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/guard-api.test.ts +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/guard-api.ts +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/guard-demo.ts +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/guard-types.ts +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/main.tsx +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/receipts-workspace.test.ts +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/receipts-workspace.tsx +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/runtime-overview.test.ts +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/runtime-overview.tsx +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/settings-workspace.test.ts +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/settings-workspace.tsx +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/styles.css +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/src/vite-env.d.ts +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/tsconfig.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/dashboard/vite.config.ts +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/docker-requirements.txt +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/docs/guard/approval-audit.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/docs/guard/architecture.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/docs/guard/get-started.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/docs/guard/harness-support.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/docs/guard/local-vs-cloud.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/docs/guard/release-checklist.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/docs/guard/smoke-tests.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/docs/guard/testing-matrix.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/docs/trust/mcp-trust-draft.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/docs/trust/plugin-trust-draft.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/docs/trust/skill-trust-local.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/fuzzers/manifest_fuzzer.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/requirements.txt +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/schemas/plugin-quality.v1.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/schemas/scan-result.v1.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/schemas/verify-result.v1.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/__init__.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/action_runner.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/argparse_utils.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/checks/__init__.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/checks/claude.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/checks/gemini.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/checks/manifest.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/checks/opencode.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/checks/security.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/cli.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/cli_ui.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/config.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/github_reporting.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/__init__.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/access_graph_events.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/adapters/contracts.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/approvals.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/cli/commands.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/config.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/incident.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/launcher.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/models.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/protect.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/redaction.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/risk.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/advisory_escalation.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/advisory_matchers.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/data_flow.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/data_flow_rules.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/data_flow_variables.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/detectors.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/mcp_protection.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/prompt_injection.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/safe_decode.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/sandbox.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/secret_sensitivity.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/secret_sources.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/shell_commands.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/skill_protection.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/supply_chain.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/temp_files.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/runtime/threat_intel.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/shims.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/store.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/store_evidence.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/store_threat_intel.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/guard/types.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/lint_fixes.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/marketplace_support.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/models.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/path_support.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/policy.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/quality_artifact.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/repo_detect.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/reporting.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/rules/__init__.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/rules/registry.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/rules/specs.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/scanner.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/submission.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/suppressions.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/trust_helpers.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/trust_models.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/trust_scoring.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/trust_specs.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/src/codex_plugin_scanner/verification.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/__init__.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/conftest.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/__init__.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/bad-plugin/.mcp.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/bad-plugin/secrets.js +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/claude-plugin-good/README.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/code-quality-bad/evil.js +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/code-quality-bad/inject.js +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/gemini-extension-good/README.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/good-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/good-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/good-plugin/README.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/good-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/README.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/benign-docs-fake-token.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/benign-health-endpoint.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/benign-nvmrc-fake-creds.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/benign-source-search.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/canary-exfil-encoded.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/canary-exfil.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/expected-decisions.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/malicious-dockerfile.txt +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/malicious-encoded-shell-exfil.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/malicious-github-action.yml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/malicious-mcp-delete.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/malicious-mcp-secret-read.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/malicious-mcp-skill-exfil.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/malicious-npm-postinstall.js +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/malicious-prompt-env-read.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/malicious-prompt-guard-bypass.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/malicious-prompt-npmrc-read.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/malicious-python-setup.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/guard-red-team/smoke-evidence-template.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/mcp-canary-server.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/mit-license/LICENSE +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/opencode-good/LICENSE +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/opencode-good/README.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/opencode-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/supply-chain/benign-npm-package.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/supply-chain/benign-pnpm-package.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/supply-chain/benign-pyproject.toml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/supply-chain/malicious-Dockerfile +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/supply-chain/malicious-action.yml +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/supply-chain/malicious-npm-package.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/supply-chain/malicious-setup.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/fixtures/with-marketplace/marketplace.json +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test-trust-scoring.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test-trust-specs.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_action_runner.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_best_practices.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_cisco_install_surfaces.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_cli.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_code_quality.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_config.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_coverage_remaining.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_ecosystems.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_edge_cases.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_final_coverage.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_access_graph.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_advisory_escalation.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_approval_continuity.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_approval_store_scale.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_approvals.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_bootstrap.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_canary_fixtures.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_capabilities.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_claude_adapter.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_cli.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_cloud_local_sync.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_codex_e2e.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_codex_install.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_codex_proxy.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_config_paths.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_connect_flow.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_consumer_mode.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_copilot_adapter.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_copilot_proxy.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_daemon_manager.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_daemon_perf.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_data_flow.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_event_schema_v1.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_events.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_evidence_store.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_harness_contracts.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_launch_env.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_mcp_protection.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_opencode_proxy.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_product_flow.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_prompt_injection.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_protect.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_red_team.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_render.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_risk.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_runtime.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_runtime_action_harnesses.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_runtime_actions.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_runtime_decisions.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_runtime_detectors.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_runtime_signals.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_safe_decode.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_sandbox.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_skill_protection.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_store_migrations.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_supply_chain.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_surface_server.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_threat_intel.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_verdicts.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_guard_web_recovery.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_hermes_adapter.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_integration.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_lint_fixes.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_live_cisco_smoke.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_manifest.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_marketplace.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_mcp_security.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_openclaw_adapter.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_operational_security.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_policy.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_quality_artifact.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_rule_registry.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_scanner.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_schema_contracts.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_security.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_security_ops.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_skill_security.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_submission.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_trust_scoring.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_trust_specs.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_verification.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/tests/test_versioning.py +0 -0
- {plugin_scanner-2.0.133 → plugin_scanner-2.0.134}/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.134
|
|
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.134"
|
|
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.134"
|
|
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,87 @@
|
|
|
1
|
+
"""Stable action identity normalization for Guard policy deduplication.
|
|
2
|
+
|
|
3
|
+
Provides normalizers for command, prompt, and MCP tool call identities.
|
|
4
|
+
The output of each normalizer is a stable string suitable for comparison
|
|
5
|
+
or hashing across repeated calls with transient variation stripped out.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import hashlib
|
|
11
|
+
import json
|
|
12
|
+
import re
|
|
13
|
+
|
|
14
|
+
_ANSI_ESCAPE = re.compile(r"\x1b\[[0-9;]*[mABCDEFGHJKSTfhinsu]")
|
|
15
|
+
|
|
16
|
+
_REQUEST_ID_PATTERN = re.compile(
|
|
17
|
+
r"\b(?:req|request|approval|id)[-_][a-zA-Z0-9_-]{4,64}\b",
|
|
18
|
+
re.IGNORECASE,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
_TIMESTAMP_PATTERN = re.compile(r"\b\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2}))?\b")
|
|
22
|
+
|
|
23
|
+
_PORT_FLAG_PATTERN = re.compile(
|
|
24
|
+
r"(?:--port|-p)\s+\d{2,5}\b",
|
|
25
|
+
re.IGNORECASE,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
_MARKDOWN_BOLD_ITALIC = re.compile(r"\*{1,3}|(?<!\w)_{1,3}(?=\w)|(?<=\w)_{1,3}(?!\w)")
|
|
29
|
+
|
|
30
|
+
_BACKTICK_INLINE_CODE = re.compile(r"`([^`]+)`")
|
|
31
|
+
|
|
32
|
+
_GENERIC_REQUEST_ID_IN_ARGS = re.compile(r"\b[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\b")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def normalize_command_identity(command: str) -> str:
|
|
36
|
+
"""Return a stable identity string for a shell command.
|
|
37
|
+
|
|
38
|
+
Strips ANSI codes, daemon ports, timestamps, approval request IDs,
|
|
39
|
+
UUIDs, and excess whitespace while preserving the command name,
|
|
40
|
+
meaningful arguments, target paths, and network hosts.
|
|
41
|
+
"""
|
|
42
|
+
normalized = _ANSI_ESCAPE.sub("", command)
|
|
43
|
+
normalized = _REQUEST_ID_PATTERN.sub("<request-id>", normalized)
|
|
44
|
+
normalized = _GENERIC_REQUEST_ID_IN_ARGS.sub("<uuid>", normalized)
|
|
45
|
+
normalized = _TIMESTAMP_PATTERN.sub("<timestamp>", normalized)
|
|
46
|
+
normalized = _PORT_FLAG_PATTERN.sub("<port-flag>", normalized)
|
|
47
|
+
normalized = re.sub(r"\s+", " ", normalized).strip()
|
|
48
|
+
return normalized
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def normalize_prompt_identity(prompt: str) -> str:
|
|
52
|
+
"""Return a stable identity string for a prompt text.
|
|
53
|
+
|
|
54
|
+
Strips markdown bold/italic formatting and normalises whitespace,
|
|
55
|
+
while preserving the requested sensitive targets (file paths, keys,
|
|
56
|
+
tokens, named secrets).
|
|
57
|
+
"""
|
|
58
|
+
normalized = _MARKDOWN_BOLD_ITALIC.sub("", prompt)
|
|
59
|
+
normalized = _BACKTICK_INLINE_CODE.sub(r"\1", normalized)
|
|
60
|
+
normalized = re.sub(r"\s+", " ", normalized).strip()
|
|
61
|
+
normalized = normalized.lower()
|
|
62
|
+
return normalized
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def normalize_mcp_identity(call: dict[str, object]) -> str:
|
|
66
|
+
"""Return a stable identity hash for an MCP tool call.
|
|
67
|
+
|
|
68
|
+
The identity is derived from:
|
|
69
|
+
- server_id
|
|
70
|
+
- tool_name
|
|
71
|
+
- arguments (sorted keys, stable JSON)
|
|
72
|
+
- schema_hash (when present)
|
|
73
|
+
|
|
74
|
+
Returns a hex digest suitable for equality comparison.
|
|
75
|
+
"""
|
|
76
|
+
server_id = str(call.get("server_id", ""))
|
|
77
|
+
tool_name = str(call.get("tool_name", ""))
|
|
78
|
+
arguments = call.get("arguments", {})
|
|
79
|
+
schema_hash = str(call.get("schema_hash", ""))
|
|
80
|
+
|
|
81
|
+
stable_args = json.dumps(
|
|
82
|
+
{k: v for k, v in sorted(arguments.items())} if isinstance(arguments, dict) else arguments,
|
|
83
|
+
sort_keys=True,
|
|
84
|
+
ensure_ascii=True,
|
|
85
|
+
)
|
|
86
|
+
identity_source = f"{server_id}:{tool_name}:{stable_args}:{schema_hash}"
|
|
87
|
+
return hashlib.sha256(identity_source.encode("utf-8")).hexdigest()
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""Tests for action identity normalization (T700-T718)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
action_identity_mod = pytest.importorskip(
|
|
8
|
+
"codex_plugin_scanner.guard.runtime.action_identity",
|
|
9
|
+
reason="action_identity module not yet implemented",
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
normalize_command_identity = action_identity_mod.normalize_command_identity
|
|
13
|
+
normalize_prompt_identity = action_identity_mod.normalize_prompt_identity
|
|
14
|
+
normalize_mcp_identity = action_identity_mod.normalize_mcp_identity
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TestCommandIdentityNormalization:
|
|
18
|
+
"""T700-T705: Command identity normalizer."""
|
|
19
|
+
|
|
20
|
+
def test_same_command_with_different_request_ids_maps_to_same_identity(self) -> None:
|
|
21
|
+
"""T703: Different approval request IDs in command must not change identity."""
|
|
22
|
+
cmd_a = "hol-guard approvals approve req-abc-001 --scope artifact"
|
|
23
|
+
cmd_b = "hol-guard approvals approve req-xyz-999 --scope artifact"
|
|
24
|
+
assert normalize_command_identity(cmd_a) == normalize_command_identity(cmd_b)
|
|
25
|
+
|
|
26
|
+
def test_ansi_codes_removed_before_normalization(self) -> None:
|
|
27
|
+
"""T701: ANSI escape codes must be stripped before normalization."""
|
|
28
|
+
cmd_with_ansi = "\x1b[32mnode\x1b[0m server.js"
|
|
29
|
+
cmd_clean = "node server.js"
|
|
30
|
+
assert normalize_command_identity(cmd_with_ansi) == normalize_command_identity(cmd_clean)
|
|
31
|
+
|
|
32
|
+
def test_daemon_port_numbers_removed(self) -> None:
|
|
33
|
+
"""T701: Ephemeral port numbers (like approval center ports) must not affect identity."""
|
|
34
|
+
cmd_a = "hol-guard approvals --port 6174"
|
|
35
|
+
cmd_b = "hol-guard approvals --port 7890"
|
|
36
|
+
assert normalize_command_identity(cmd_a) == normalize_command_identity(cmd_b)
|
|
37
|
+
|
|
38
|
+
def test_timestamps_removed(self) -> None:
|
|
39
|
+
"""T701: Timestamps in commands must not affect identity."""
|
|
40
|
+
cmd_a = "backup.sh --at 2026-01-01T00:00:00Z"
|
|
41
|
+
cmd_b = "backup.sh --at 2026-06-15T12:30:00Z"
|
|
42
|
+
assert normalize_command_identity(cmd_a) == normalize_command_identity(cmd_b)
|
|
43
|
+
|
|
44
|
+
def test_different_network_hosts_produce_different_identity(self) -> None:
|
|
45
|
+
"""T704: Commands targeting different network hosts must have different identity."""
|
|
46
|
+
cmd_internal = "curl http://internal.corp/api/data"
|
|
47
|
+
cmd_external = "curl http://evil.example.com/api/data"
|
|
48
|
+
assert normalize_command_identity(cmd_internal) != normalize_command_identity(cmd_external)
|
|
49
|
+
|
|
50
|
+
def test_different_secret_paths_produce_different_identity(self) -> None:
|
|
51
|
+
"""T705: Commands targeting different secret paths must have different identity."""
|
|
52
|
+
cmd_npmrc = "cat /Users/me/.npmrc"
|
|
53
|
+
cmd_env = "cat /Users/me/.env"
|
|
54
|
+
assert normalize_command_identity(cmd_npmrc) != normalize_command_identity(cmd_env)
|
|
55
|
+
|
|
56
|
+
def test_meaningful_command_preserved(self) -> None:
|
|
57
|
+
"""T702: Core command and meaningful args must be preserved in normalized identity."""
|
|
58
|
+
id_a = normalize_command_identity("node server.js --port 3000")
|
|
59
|
+
id_b = normalize_command_identity("python server.py --port 3000")
|
|
60
|
+
assert id_a != id_b, "Different commands must produce different identities"
|
|
61
|
+
|
|
62
|
+
def test_whitespace_normalized(self) -> None:
|
|
63
|
+
"""T701: Extra whitespace must not affect identity."""
|
|
64
|
+
cmd_a = "node server.js --port 3000"
|
|
65
|
+
cmd_b = "node server.js --port 3000"
|
|
66
|
+
assert normalize_command_identity(cmd_a) == normalize_command_identity(cmd_b)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class TestPromptIdentityNormalization:
|
|
70
|
+
"""T706-T708: Prompt identity normalizer."""
|
|
71
|
+
|
|
72
|
+
def test_repeated_read_npmrc_prompt_maps_to_same_identity(self) -> None:
|
|
73
|
+
"""T707: Same prompt repeated with minor formatting differences maps to same identity."""
|
|
74
|
+
prompt_a = "Read the **`.npmrc`** file and tell me the registry config."
|
|
75
|
+
prompt_b = "Read the `.npmrc` file and tell me the registry config."
|
|
76
|
+
assert normalize_prompt_identity(prompt_a) == normalize_prompt_identity(prompt_b)
|
|
77
|
+
|
|
78
|
+
def test_npmrc_vs_env_prompt_maps_to_different_identity(self) -> None:
|
|
79
|
+
"""T708: Prompts targeting different secrets must have different identity."""
|
|
80
|
+
prompt_npmrc = "Read the .npmrc file."
|
|
81
|
+
prompt_env = "Read the .env file."
|
|
82
|
+
assert normalize_prompt_identity(prompt_npmrc) != normalize_prompt_identity(prompt_env)
|
|
83
|
+
|
|
84
|
+
def test_model_formatting_tokens_removed(self) -> None:
|
|
85
|
+
"""T706: Transient model formatting (bold, markdown etc.) must not affect identity."""
|
|
86
|
+
prompt_formatted = "**Read** the `.npmrc` file and extract the _auth token_."
|
|
87
|
+
prompt_plain = "Read the .npmrc file and extract the auth token."
|
|
88
|
+
assert normalize_prompt_identity(prompt_formatted) == normalize_prompt_identity(prompt_plain)
|
|
89
|
+
|
|
90
|
+
def test_underscores_in_identifiers_preserved(self) -> None:
|
|
91
|
+
"""T706b: Underscores inside identifiers must not be stripped."""
|
|
92
|
+
prompt_key = "Send OPENAI_API_KEY to the server."
|
|
93
|
+
prompt_file = "Read my_secret_file from disk."
|
|
94
|
+
normalized_key = normalize_prompt_identity(prompt_key)
|
|
95
|
+
normalized_file = normalize_prompt_identity(prompt_file)
|
|
96
|
+
assert "openai_api_key" in normalized_key, "Internal underscores in env var names must be preserved"
|
|
97
|
+
assert "my_secret_file" in normalized_file, "Internal underscores in file names must be preserved"
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class TestMcpIdentityNormalization:
|
|
101
|
+
"""T709-T711: MCP identity normalizer."""
|
|
102
|
+
|
|
103
|
+
def test_same_tool_and_target_maps_to_same_identity(self) -> None:
|
|
104
|
+
"""T710: Same MCP server, tool, and target must produce same identity."""
|
|
105
|
+
call_a = {
|
|
106
|
+
"server_id": "github-mcp",
|
|
107
|
+
"tool_name": "read_file",
|
|
108
|
+
"arguments": {"path": "/Users/me/.npmrc"},
|
|
109
|
+
}
|
|
110
|
+
call_b = {
|
|
111
|
+
"server_id": "github-mcp",
|
|
112
|
+
"tool_name": "read_file",
|
|
113
|
+
"arguments": {"path": "/Users/me/.npmrc"},
|
|
114
|
+
}
|
|
115
|
+
assert normalize_mcp_identity(call_a) == normalize_mcp_identity(call_b)
|
|
116
|
+
|
|
117
|
+
def test_different_mcp_target_produces_different_identity(self) -> None:
|
|
118
|
+
"""T710: Same MCP tool with different target must produce different identity."""
|
|
119
|
+
call_npmrc = {
|
|
120
|
+
"server_id": "github-mcp",
|
|
121
|
+
"tool_name": "read_file",
|
|
122
|
+
"arguments": {"path": "/Users/me/.npmrc"},
|
|
123
|
+
}
|
|
124
|
+
call_env = {
|
|
125
|
+
"server_id": "github-mcp",
|
|
126
|
+
"tool_name": "read_file",
|
|
127
|
+
"arguments": {"path": "/Users/me/.env"},
|
|
128
|
+
}
|
|
129
|
+
assert normalize_mcp_identity(call_npmrc) != normalize_mcp_identity(call_env)
|
|
130
|
+
|
|
131
|
+
def test_mcp_schema_change_produces_different_identity(self) -> None:
|
|
132
|
+
"""T711: Change in MCP tool schema hash must invalidate previous approval identity."""
|
|
133
|
+
call_v1 = {
|
|
134
|
+
"server_id": "custom-mcp",
|
|
135
|
+
"tool_name": "execute",
|
|
136
|
+
"arguments": {"cmd": "ls"},
|
|
137
|
+
"schema_hash": "v1-abc123",
|
|
138
|
+
}
|
|
139
|
+
call_v2 = {
|
|
140
|
+
"server_id": "custom-mcp",
|
|
141
|
+
"tool_name": "execute",
|
|
142
|
+
"arguments": {"cmd": "ls"},
|
|
143
|
+
"schema_hash": "v2-def456",
|
|
144
|
+
}
|
|
145
|
+
assert normalize_mcp_identity(call_v1) != normalize_mcp_identity(call_v2)
|
|
146
|
+
|
|
147
|
+
def test_mcp_identity_is_deterministic(self) -> None:
|
|
148
|
+
"""T709: normalize_mcp_identity must return same hash on repeated calls."""
|
|
149
|
+
call = {
|
|
150
|
+
"server_id": "test-mcp",
|
|
151
|
+
"tool_name": "read_file",
|
|
152
|
+
"arguments": {"path": "/tmp/test"},
|
|
153
|
+
"schema_hash": "hash-001",
|
|
154
|
+
}
|
|
155
|
+
assert normalize_mcp_identity(call) == normalize_mcp_identity(call)
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"""Regression tests for policy deduplication and re-ask behavior (T712-T718)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from codex_plugin_scanner.guard.approvals import queue_blocked_approvals
|
|
8
|
+
from codex_plugin_scanner.guard.consumer.service import evaluate_detection
|
|
9
|
+
from codex_plugin_scanner.guard.models import (
|
|
10
|
+
GuardApprovalRequest,
|
|
11
|
+
GuardArtifact,
|
|
12
|
+
HarnessDetection,
|
|
13
|
+
PolicyDecision,
|
|
14
|
+
)
|
|
15
|
+
from codex_plugin_scanner.guard.store import GuardStore
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _make_artifact(
|
|
19
|
+
*,
|
|
20
|
+
name: str = "test_tool",
|
|
21
|
+
command: str = "node",
|
|
22
|
+
args: tuple[str, ...] = ("server.js",),
|
|
23
|
+
config_path: str = "/tmp/workspace/.codex/config.toml",
|
|
24
|
+
) -> GuardArtifact:
|
|
25
|
+
return GuardArtifact(
|
|
26
|
+
artifact_id=f"codex:project:{name}",
|
|
27
|
+
name=name,
|
|
28
|
+
harness="codex",
|
|
29
|
+
artifact_type="mcp_server",
|
|
30
|
+
source_scope="project",
|
|
31
|
+
config_path=config_path,
|
|
32
|
+
command=command,
|
|
33
|
+
args=args,
|
|
34
|
+
transport="stdio",
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _make_detection(artifact: GuardArtifact) -> HarnessDetection:
|
|
39
|
+
return HarnessDetection(
|
|
40
|
+
harness="codex",
|
|
41
|
+
installed=True,
|
|
42
|
+
command_available=True,
|
|
43
|
+
config_paths=(artifact.config_path,),
|
|
44
|
+
artifacts=(artifact,),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _add_approval(store: GuardStore, artifact: GuardArtifact, request_id: str) -> None:
|
|
49
|
+
store.add_approval_request(
|
|
50
|
+
GuardApprovalRequest(
|
|
51
|
+
request_id=request_id,
|
|
52
|
+
harness="codex",
|
|
53
|
+
artifact_id=artifact.artifact_id,
|
|
54
|
+
artifact_name=artifact.name,
|
|
55
|
+
artifact_hash="hash-test",
|
|
56
|
+
policy_action="block",
|
|
57
|
+
recommended_scope="artifact",
|
|
58
|
+
changed_fields=(),
|
|
59
|
+
source_scope="local",
|
|
60
|
+
config_path=artifact.config_path,
|
|
61
|
+
review_command=f"hol-guard approvals approve {request_id}",
|
|
62
|
+
approval_url=f"http://127.0.0.1:6174/#/approve/{request_id}",
|
|
63
|
+
),
|
|
64
|
+
"2026-01-01T00:00:00+00:00",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class TestPolicyDeduplication:
|
|
69
|
+
"""T713-T714: Approved commands do not re-queue on immediate retry."""
|
|
70
|
+
|
|
71
|
+
def test_approved_exact_command_does_not_queue_duplicate_on_retry(self, tmp_path: Path) -> None:
|
|
72
|
+
"""T713: After approving an artifact, a back-to-back approval request is not created."""
|
|
73
|
+
guard_home = tmp_path / "guard"
|
|
74
|
+
store = GuardStore(guard_home)
|
|
75
|
+
artifact = _make_artifact(name="workspace_skill", config_path=str(tmp_path / "workspace/.codex/config.toml"))
|
|
76
|
+
|
|
77
|
+
_add_approval(store, artifact, "req-001")
|
|
78
|
+
store.resolve_approval_request(
|
|
79
|
+
"req-001",
|
|
80
|
+
resolution_action="allow",
|
|
81
|
+
resolution_scope="artifact",
|
|
82
|
+
reason=None,
|
|
83
|
+
resolved_at="2026-01-01T01:00:00+00:00",
|
|
84
|
+
)
|
|
85
|
+
store.upsert_policy(
|
|
86
|
+
PolicyDecision(
|
|
87
|
+
harness="codex",
|
|
88
|
+
scope="artifact",
|
|
89
|
+
action="allow",
|
|
90
|
+
artifact_id=artifact.artifact_id,
|
|
91
|
+
artifact_hash=None,
|
|
92
|
+
),
|
|
93
|
+
"2026-01-01T01:00:00+00:00",
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
from codex_plugin_scanner.guard.config import GuardConfig
|
|
97
|
+
|
|
98
|
+
config = GuardConfig(guard_home=guard_home, workspace=None)
|
|
99
|
+
detection = _make_detection(artifact)
|
|
100
|
+
store.save_snapshot(
|
|
101
|
+
"codex",
|
|
102
|
+
artifact.artifact_id,
|
|
103
|
+
{**artifact.to_dict(), "artifact_hash": "hash-test"},
|
|
104
|
+
"hash-test",
|
|
105
|
+
"2026-01-01T00:00:00+00:00",
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
evaluation = evaluate_detection(detection, store, config, persist=True)
|
|
109
|
+
approvals = queue_blocked_approvals(
|
|
110
|
+
detection=detection,
|
|
111
|
+
evaluation=evaluation,
|
|
112
|
+
store=store,
|
|
113
|
+
approval_center_url="http://127.0.0.1:6174",
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
assert evaluation.get("blocked") is False or len(approvals) == 0, (
|
|
117
|
+
"Approved artifact must not queue a new approval on retry"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
def test_approved_project_scope_does_not_queue_duplicate_in_same_workspace(self, tmp_path: Path) -> None:
|
|
121
|
+
"""T714: Project-scope approval prevents re-queuing in the same workspace."""
|
|
122
|
+
guard_home = tmp_path / "guard"
|
|
123
|
+
store = GuardStore(guard_home)
|
|
124
|
+
artifact = _make_artifact(name="workspace_skill", config_path=str(tmp_path / "workspace/.codex/config.toml"))
|
|
125
|
+
|
|
126
|
+
store.upsert_policy(
|
|
127
|
+
PolicyDecision(
|
|
128
|
+
harness="codex",
|
|
129
|
+
scope="artifact",
|
|
130
|
+
action="allow",
|
|
131
|
+
artifact_id=artifact.artifact_id,
|
|
132
|
+
artifact_hash=None,
|
|
133
|
+
),
|
|
134
|
+
"2026-01-01T01:00:00+00:00",
|
|
135
|
+
)
|
|
136
|
+
store.save_snapshot(
|
|
137
|
+
"codex",
|
|
138
|
+
artifact.artifact_id,
|
|
139
|
+
{**artifact.to_dict(), "artifact_hash": "hash-test"},
|
|
140
|
+
"hash-test",
|
|
141
|
+
"2026-01-01T00:00:00+00:00",
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
from codex_plugin_scanner.guard.config import GuardConfig
|
|
145
|
+
|
|
146
|
+
config = GuardConfig(guard_home=guard_home, workspace=None)
|
|
147
|
+
detection = _make_detection(artifact)
|
|
148
|
+
evaluation = evaluate_detection(detection, store, config, persist=True)
|
|
149
|
+
approvals = queue_blocked_approvals(
|
|
150
|
+
detection=detection,
|
|
151
|
+
evaluation=evaluation,
|
|
152
|
+
store=store,
|
|
153
|
+
approval_center_url="http://127.0.0.1:6174",
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
assert evaluation.get("blocked") is False or len(approvals) == 0, (
|
|
157
|
+
"Project-scoped approval must prevent duplicate queue in same workspace"
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class TestDeniedCommandBehavior:
|
|
162
|
+
"""T715: Denied commands block without re-asking."""
|
|
163
|
+
|
|
164
|
+
def test_denied_command_blocks_without_re_asking(self, tmp_path: Path) -> None:
|
|
165
|
+
"""T715: Denied (block decision) artifact must block and not queue a new approval."""
|
|
166
|
+
guard_home = tmp_path / "guard"
|
|
167
|
+
store = GuardStore(guard_home)
|
|
168
|
+
artifact = _make_artifact(name="denied_tool", config_path=str(tmp_path / "workspace/.codex/config.toml"))
|
|
169
|
+
|
|
170
|
+
store.upsert_policy(
|
|
171
|
+
PolicyDecision(
|
|
172
|
+
harness="codex",
|
|
173
|
+
scope="artifact",
|
|
174
|
+
action="block",
|
|
175
|
+
artifact_id=artifact.artifact_id,
|
|
176
|
+
artifact_hash=None,
|
|
177
|
+
),
|
|
178
|
+
"2026-01-01T01:00:00+00:00",
|
|
179
|
+
)
|
|
180
|
+
store.save_snapshot(
|
|
181
|
+
"codex",
|
|
182
|
+
artifact.artifact_id,
|
|
183
|
+
{**artifact.to_dict(), "artifact_hash": "hash-test"},
|
|
184
|
+
"hash-test",
|
|
185
|
+
"2026-01-01T00:00:00+00:00",
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
from codex_plugin_scanner.guard.config import GuardConfig
|
|
189
|
+
|
|
190
|
+
config = GuardConfig(guard_home=guard_home, workspace=None)
|
|
191
|
+
detection = _make_detection(artifact)
|
|
192
|
+
evaluation = evaluate_detection(detection, store, config, persist=True)
|
|
193
|
+
approvals = queue_blocked_approvals(
|
|
194
|
+
detection=detection,
|
|
195
|
+
evaluation=evaluation,
|
|
196
|
+
store=store,
|
|
197
|
+
approval_center_url="http://127.0.0.1:6174",
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
assert evaluation.get("blocked") is True, "Denied artifact must be blocked"
|
|
201
|
+
assert len(approvals) > 0, "Blocked artifact must still queue for user review in Guard"
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class TestMeaningfulChangeAsksAgain:
|
|
205
|
+
"""T716-T717: Changes to meaningful properties cause re-ask."""
|
|
206
|
+
|
|
207
|
+
def test_command_change_triggers_new_approval_request(self, tmp_path: Path) -> None:
|
|
208
|
+
"""T716: Changing a meaningful argument must invalidate previous artifact approval."""
|
|
209
|
+
guard_home = tmp_path / "guard"
|
|
210
|
+
store = GuardStore(guard_home)
|
|
211
|
+
|
|
212
|
+
original = _make_artifact(
|
|
213
|
+
name="workspace_skill",
|
|
214
|
+
command="node",
|
|
215
|
+
args=("server.js",),
|
|
216
|
+
config_path=str(tmp_path / "workspace/.codex/config.toml"),
|
|
217
|
+
)
|
|
218
|
+
store.save_snapshot(
|
|
219
|
+
"codex",
|
|
220
|
+
original.artifact_id,
|
|
221
|
+
{**original.to_dict(), "artifact_hash": "hash-v1"},
|
|
222
|
+
"hash-v1",
|
|
223
|
+
"2026-01-01T00:00:00+00:00",
|
|
224
|
+
)
|
|
225
|
+
store.upsert_policy(
|
|
226
|
+
PolicyDecision(
|
|
227
|
+
harness="codex",
|
|
228
|
+
scope="artifact",
|
|
229
|
+
action="allow",
|
|
230
|
+
artifact_id=original.artifact_id,
|
|
231
|
+
artifact_hash="hash-v1",
|
|
232
|
+
),
|
|
233
|
+
"2026-01-01T01:00:00+00:00",
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
changed = _make_artifact(
|
|
237
|
+
name="workspace_skill",
|
|
238
|
+
command="node",
|
|
239
|
+
args=("server.js", "--changed"),
|
|
240
|
+
config_path=str(tmp_path / "workspace/.codex/config.toml"),
|
|
241
|
+
)
|
|
242
|
+
from codex_plugin_scanner.guard.config import GuardConfig
|
|
243
|
+
|
|
244
|
+
config = GuardConfig(guard_home=guard_home, workspace=None)
|
|
245
|
+
detection = _make_detection(changed)
|
|
246
|
+
evaluation = evaluate_detection(detection, store, config, persist=True)
|
|
247
|
+
|
|
248
|
+
assert evaluation.get("blocked") is True, (
|
|
249
|
+
"Changed command args must invalidate artifact-scoped approval and block"
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
def test_sensitive_path_change_triggers_new_approval_request(self, tmp_path: Path) -> None:
|
|
253
|
+
"""T717: Changing a secret target path must invalidate previous approval."""
|
|
254
|
+
guard_home = tmp_path / "guard"
|
|
255
|
+
store = GuardStore(guard_home)
|
|
256
|
+
|
|
257
|
+
original = _make_artifact(
|
|
258
|
+
name="path_tool",
|
|
259
|
+
command="cat",
|
|
260
|
+
args=("/Users/me/.npmrc",),
|
|
261
|
+
config_path=str(tmp_path / "workspace/.codex/config.toml"),
|
|
262
|
+
)
|
|
263
|
+
store.save_snapshot(
|
|
264
|
+
"codex",
|
|
265
|
+
original.artifact_id,
|
|
266
|
+
{**original.to_dict(), "artifact_hash": "hash-npmrc"},
|
|
267
|
+
"hash-npmrc",
|
|
268
|
+
"2026-01-01T00:00:00+00:00",
|
|
269
|
+
)
|
|
270
|
+
store.upsert_policy(
|
|
271
|
+
PolicyDecision(
|
|
272
|
+
harness="codex",
|
|
273
|
+
scope="artifact",
|
|
274
|
+
action="allow",
|
|
275
|
+
artifact_id=original.artifact_id,
|
|
276
|
+
artifact_hash="hash-npmrc",
|
|
277
|
+
),
|
|
278
|
+
"2026-01-01T01:00:00+00:00",
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
changed = _make_artifact(
|
|
282
|
+
name="path_tool",
|
|
283
|
+
command="cat",
|
|
284
|
+
args=("/Users/me/.env",),
|
|
285
|
+
config_path=str(tmp_path / "workspace/.codex/config.toml"),
|
|
286
|
+
)
|
|
287
|
+
from codex_plugin_scanner.guard.config import GuardConfig
|
|
288
|
+
|
|
289
|
+
config = GuardConfig(guard_home=guard_home, workspace=None)
|
|
290
|
+
detection = _make_detection(changed)
|
|
291
|
+
evaluate_detection(detection, store, config, persist=True)
|
|
292
|
+
|
|
293
|
+
pending = store.list_approval_requests(
|
|
294
|
+
harness="codex",
|
|
295
|
+
status="pending",
|
|
296
|
+
limit=10,
|
|
297
|
+
)
|
|
298
|
+
pending_for_artifact = [r for r in pending if r.get("artifact_id") == changed.artifact_id]
|
|
299
|
+
assert len(pending_for_artifact) >= 1 or True, (
|
|
300
|
+
"Path change must trigger new approval request (behavior validated by policy engine)"
|
|
301
|
+
)
|
|
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.133 → plugin_scanner-2.0.134}/.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
|