plugin-scanner 2.0.134__tar.gz → 2.0.135__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.134 → plugin_scanner-2.0.135}/PKG-INFO +1 -1
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/pyproject.toml +1 -1
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/pyproject.toml.bak +1 -1
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/store.py +1 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/store_approvals.py +36 -5
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/version.py +1 -1
- plugin_scanner-2.0.135/tests/test_guard_approval_store_dedup.py +219 -0
- plugin_scanner-2.0.135/tests/test_guard_decision_propagation.py +162 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.clusterfuzzlite/Dockerfile +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.clusterfuzzlite/build.sh +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.clusterfuzzlite/project.yaml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.clusterfuzzlite/requirements-atheris.txt +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.dockerignore +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.github/CODEOWNERS +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.github/dependabot.yml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.github/workflows/ci.yml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.github/workflows/codeql.yml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.github/workflows/dependabot-uv-lock.yml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.github/workflows/fuzz.yml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.github/workflows/harness-smoke.yml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.github/workflows/publish.yml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.github/workflows/scorecard.yml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.gitignore +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/.pre-commit-hooks.yaml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/CONTRIBUTING.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/Dockerfile +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/LICENSE +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/README.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/SECURITY.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/index.html +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/package.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/pnpm-lock.yaml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/public/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/public/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/public/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/public/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/public/favicon.ico +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/app.tsx +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/approval-center-layout.test.ts +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/approval-center-layout.tsx +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/approval-center-primitives.tsx +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/approval-center-review-cards.tsx +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/approval-center-utils.ts +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/data-flow-evidence-card.tsx +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/fleet-workspace.tsx +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/guard-api.test.ts +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/guard-api.ts +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/guard-demo.ts +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/guard-types.ts +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/main.tsx +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/receipts-workspace.test.ts +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/receipts-workspace.tsx +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/runtime-overview.test.ts +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/runtime-overview.tsx +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/settings-workspace.test.ts +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/settings-workspace.tsx +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/styles.css +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/vite-env.d.ts +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/tsconfig.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/vite.config.ts +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/docker-requirements.txt +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/docs/guard/approval-audit.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/docs/guard/architecture.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/docs/guard/get-started.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/docs/guard/harness-support.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/docs/guard/local-vs-cloud.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/docs/guard/release-checklist.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/docs/guard/smoke-tests.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/docs/guard/testing-matrix.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/docs/trust/mcp-trust-draft.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/docs/trust/plugin-trust-draft.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/docs/trust/skill-trust-local.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/fuzzers/manifest_fuzzer.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/requirements.txt +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/schemas/plugin-quality.v1.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/schemas/scan-result.v1.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/schemas/verify-result.v1.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/__init__.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/action_runner.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/argparse_utils.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/checks/__init__.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/checks/claude.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/checks/gemini.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/checks/manifest.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/checks/opencode.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/checks/security.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/cli.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/cli_ui.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/config.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/github_reporting.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/__init__.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/access_graph_events.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/adapters/contracts.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/approvals.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/cli/commands.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/config.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/incident.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/launcher.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/models.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/protect.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/redaction.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/risk.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/action_identity.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/advisory_escalation.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/advisory_matchers.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/data_flow.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/data_flow_rules.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/data_flow_variables.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/detectors.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/mcp_protection.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/prompt_injection.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/safe_decode.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/sandbox.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/secret_sensitivity.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/secret_sources.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/shell_commands.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/skill_protection.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/supply_chain.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/temp_files.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/runtime/threat_intel.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/shims.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/store_evidence.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/store_threat_intel.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/types.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/lint_fixes.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/marketplace_support.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/models.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/path_support.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/policy.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/quality_artifact.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/repo_detect.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/reporting.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/rules/__init__.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/rules/registry.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/rules/specs.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/scanner.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/submission.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/suppressions.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/trust_helpers.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/trust_models.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/trust_scoring.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/trust_specs.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/verification.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/__init__.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/conftest.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/__init__.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/bad-plugin/.mcp.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/bad-plugin/secrets.js +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/claude-plugin-good/README.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/code-quality-bad/evil.js +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/code-quality-bad/inject.js +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/gemini-extension-good/README.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/good-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/good-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/good-plugin/README.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/good-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/README.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/benign-docs-fake-token.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/benign-health-endpoint.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/benign-nvmrc-fake-creds.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/benign-source-search.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/canary-exfil-encoded.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/canary-exfil.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/expected-decisions.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/malicious-dockerfile.txt +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/malicious-encoded-shell-exfil.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/malicious-github-action.yml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/malicious-mcp-delete.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/malicious-mcp-secret-read.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/malicious-mcp-skill-exfil.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/malicious-npm-postinstall.js +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/malicious-prompt-env-read.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/malicious-prompt-guard-bypass.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/malicious-prompt-npmrc-read.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/malicious-python-setup.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/guard-red-team/smoke-evidence-template.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/mcp-canary-server.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/mit-license/LICENSE +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/opencode-good/LICENSE +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/opencode-good/README.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/opencode-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/supply-chain/benign-npm-package.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/supply-chain/benign-pnpm-package.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/supply-chain/benign-pyproject.toml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/supply-chain/malicious-Dockerfile +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/supply-chain/malicious-action.yml +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/supply-chain/malicious-npm-package.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/supply-chain/malicious-setup.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/fixtures/with-marketplace/marketplace.json +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test-trust-scoring.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test-trust-specs.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_action_runner.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_best_practices.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_cisco_install_surfaces.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_cli.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_code_quality.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_config.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_coverage_remaining.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_ecosystems.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_edge_cases.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_final_coverage.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_access_graph.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_action_identity.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_advisory_escalation.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_approval_continuity.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_approval_store_scale.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_approvals.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_bootstrap.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_canary_fixtures.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_capabilities.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_claude_adapter.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_cli.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_cloud_local_sync.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_codex_e2e.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_codex_install.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_codex_proxy.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_config_paths.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_connect_flow.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_consumer_mode.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_copilot_adapter.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_copilot_proxy.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_daemon_manager.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_daemon_perf.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_data_flow.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_event_schema_v1.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_events.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_evidence_store.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_harness_contracts.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_launch_env.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_mcp_protection.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_opencode_proxy.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_policy_dedup.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_product_flow.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_prompt_injection.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_protect.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_red_team.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_render.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_risk.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_runtime.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_runtime_action_harnesses.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_runtime_actions.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_runtime_decisions.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_runtime_detectors.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_runtime_signals.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_safe_decode.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_sandbox.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_skill_protection.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_store_migrations.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_supply_chain.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_surface_server.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_threat_intel.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_verdicts.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_guard_web_recovery.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_hermes_adapter.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_integration.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_lint_fixes.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_live_cisco_smoke.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_manifest.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_marketplace.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_mcp_security.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_openclaw_adapter.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_operational_security.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_policy.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_quality_artifact.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_rule_registry.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_scanner.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_schema_contracts.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_security.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_security_ops.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_skill_security.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_submission.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_trust_scoring.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_trust_specs.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_verification.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/tests/test_versioning.py +0 -0
- {plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/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.135
|
|
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.135"
|
|
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.135"
|
|
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"
|
|
@@ -686,6 +686,7 @@ class GuardStore:
|
|
|
686
686
|
self._ensure_approval_column(connection, "action_envelope_json", "text")
|
|
687
687
|
self._ensure_approval_column(connection, "decision_v2_json", "text")
|
|
688
688
|
self._ensure_approval_column(connection, "workspace", "text")
|
|
689
|
+
self._ensure_approval_column(connection, "normalized_identity_key", "text")
|
|
689
690
|
self._ensure_approval_column(connection, "fallback_cli_command", "text")
|
|
690
691
|
self._ensure_attachment_column(connection, "lease_id", "text not null default ''")
|
|
691
692
|
self._ensure_attachment_column(connection, "lease_expires_at", "text")
|
{plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/src/codex_plugin_scanner/guard/store_approvals.py
RENAMED
|
@@ -6,6 +6,11 @@ import json
|
|
|
6
6
|
import sqlite3
|
|
7
7
|
|
|
8
8
|
from .models import GuardApprovalRequest
|
|
9
|
+
from .runtime.action_identity import normalize_command_identity
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _normalized_identity_key(launch_target: str | None) -> str:
|
|
13
|
+
return normalize_command_identity(launch_target or "")
|
|
9
14
|
|
|
10
15
|
|
|
11
16
|
def approval_schema_statement() -> str:
|
|
@@ -25,6 +30,7 @@ def approval_schema_statement() -> str:
|
|
|
25
30
|
config_path text not null,
|
|
26
31
|
workspace text,
|
|
27
32
|
launch_target text,
|
|
33
|
+
normalized_identity_key text,
|
|
28
34
|
transport text,
|
|
29
35
|
risk_summary text,
|
|
30
36
|
risk_signals_json text not null default '[]',
|
|
@@ -50,16 +56,37 @@ def approval_schema_statement() -> str:
|
|
|
50
56
|
|
|
51
57
|
|
|
52
58
|
def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalRequest, now: str) -> str:
|
|
59
|
+
identity_key = _normalized_identity_key(request.launch_target)
|
|
53
60
|
existing = connection.execute(
|
|
54
61
|
"""
|
|
55
62
|
select request_id
|
|
56
63
|
from approval_requests
|
|
57
|
-
where harness = ?
|
|
64
|
+
where harness = ?
|
|
65
|
+
and artifact_id = ?
|
|
66
|
+
and workspace IS ?
|
|
67
|
+
and normalized_identity_key = ?
|
|
68
|
+
and status = 'pending'
|
|
58
69
|
order by created_at desc
|
|
59
70
|
limit 1
|
|
60
71
|
""",
|
|
61
|
-
(request.harness, request.artifact_id),
|
|
72
|
+
(request.harness, request.artifact_id, request.workspace, identity_key),
|
|
62
73
|
).fetchone()
|
|
74
|
+
if existing is None:
|
|
75
|
+
existing = connection.execute(
|
|
76
|
+
"""
|
|
77
|
+
select request_id
|
|
78
|
+
from approval_requests
|
|
79
|
+
where harness = ?
|
|
80
|
+
and artifact_id = ?
|
|
81
|
+
and workspace IS ?
|
|
82
|
+
and launch_target IS ?
|
|
83
|
+
and normalized_identity_key IS NULL
|
|
84
|
+
and status = 'pending'
|
|
85
|
+
order by created_at desc
|
|
86
|
+
limit 1
|
|
87
|
+
""",
|
|
88
|
+
(request.harness, request.artifact_id, request.workspace, request.launch_target),
|
|
89
|
+
).fetchone()
|
|
63
90
|
request_id = str(existing["request_id"]) if existing is not None else request.request_id
|
|
64
91
|
if existing is not None:
|
|
65
92
|
review_command = _rewrite_review_command(request.review_command, request_id)
|
|
@@ -69,7 +96,7 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
|
|
|
69
96
|
update approval_requests
|
|
70
97
|
set artifact_name = ?, artifact_type = ?, artifact_hash = ?, publisher = ?, policy_action = ?,
|
|
71
98
|
recommended_scope = ?, changed_fields_json = ?, source_scope = ?, config_path = ?, workspace = ?,
|
|
72
|
-
launch_target = ?, transport = ?, risk_summary = ?, risk_signals_json = ?,
|
|
99
|
+
launch_target = ?, normalized_identity_key = ?, transport = ?, risk_summary = ?, risk_signals_json = ?,
|
|
73
100
|
artifact_label = ?, source_label = ?, trigger_summary = ?, why_now = ?, launch_summary = ?,
|
|
74
101
|
risk_headline = ?, action_envelope_json = ?, decision_v2_json = ?, fallback_cli_command = ?,
|
|
75
102
|
review_command = ?, approval_url = ?, created_at = ?
|
|
@@ -87,6 +114,7 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
|
|
|
87
114
|
request.config_path,
|
|
88
115
|
request.workspace,
|
|
89
116
|
request.launch_target,
|
|
117
|
+
_normalized_identity_key(request.launch_target),
|
|
90
118
|
request.transport,
|
|
91
119
|
request.risk_summary,
|
|
92
120
|
json.dumps(list(request.risk_signals)),
|
|
@@ -115,12 +143,14 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
|
|
|
115
143
|
insert into approval_requests (
|
|
116
144
|
request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher, policy_action,
|
|
117
145
|
recommended_scope, changed_fields_json, source_scope, config_path, workspace,
|
|
118
|
-
launch_target, transport, risk_summary,
|
|
146
|
+
launch_target, normalized_identity_key, transport, risk_summary,
|
|
119
147
|
risk_signals_json, artifact_label, source_label, trigger_summary, why_now, launch_summary, risk_headline,
|
|
120
148
|
action_envelope_json, decision_v2_json, fallback_cli_command, review_command,
|
|
121
149
|
approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
|
|
122
150
|
)
|
|
123
|
-
values (
|
|
151
|
+
values (
|
|
152
|
+
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
|
153
|
+
)
|
|
124
154
|
""",
|
|
125
155
|
(
|
|
126
156
|
request.request_id,
|
|
@@ -137,6 +167,7 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
|
|
|
137
167
|
request.config_path,
|
|
138
168
|
request.workspace,
|
|
139
169
|
request.launch_target,
|
|
170
|
+
_normalized_identity_key(request.launch_target),
|
|
140
171
|
request.transport,
|
|
141
172
|
request.risk_summary,
|
|
142
173
|
json.dumps(list(request.risk_signals)),
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"""Phase 25 — approval store dedup by normalized action identity and workspace.
|
|
2
|
+
|
|
3
|
+
T719: store collapses duplicate pending requests by normalized action identity + workspace.
|
|
4
|
+
T720: duplicate pending requests update one row instead of creating many rows.
|
|
5
|
+
T721: different workspaces still get separate approval requests.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import sqlite3
|
|
11
|
+
import uuid
|
|
12
|
+
|
|
13
|
+
from codex_plugin_scanner.guard.models import GuardApprovalRequest
|
|
14
|
+
from codex_plugin_scanner.guard.store_approvals import (
|
|
15
|
+
add_approval_request,
|
|
16
|
+
approval_index_statements,
|
|
17
|
+
approval_schema_statement,
|
|
18
|
+
count_approval_requests,
|
|
19
|
+
list_approval_requests,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _make_conn() -> sqlite3.Connection:
|
|
24
|
+
conn = sqlite3.connect(":memory:")
|
|
25
|
+
conn.row_factory = sqlite3.Row
|
|
26
|
+
conn.execute("pragma journal_mode=wal")
|
|
27
|
+
conn.execute(approval_schema_statement())
|
|
28
|
+
for stmt in approval_index_statements():
|
|
29
|
+
conn.execute(stmt)
|
|
30
|
+
return conn
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _make_request(
|
|
34
|
+
*,
|
|
35
|
+
harness: str = "codex",
|
|
36
|
+
workspace: str | None = "ws-a",
|
|
37
|
+
artifact_id: str | None = None,
|
|
38
|
+
launch_target: str | None = None,
|
|
39
|
+
) -> GuardApprovalRequest:
|
|
40
|
+
aid = artifact_id or f"codex:project:tool-{uuid.uuid4().hex[:8]}"
|
|
41
|
+
rid = str(uuid.uuid4())
|
|
42
|
+
return GuardApprovalRequest(
|
|
43
|
+
request_id=rid,
|
|
44
|
+
harness=harness,
|
|
45
|
+
artifact_id=aid,
|
|
46
|
+
artifact_name="tool",
|
|
47
|
+
artifact_type="mcp_server",
|
|
48
|
+
artifact_hash="abc123",
|
|
49
|
+
publisher=None,
|
|
50
|
+
policy_action="require-reapproval",
|
|
51
|
+
recommended_scope="session",
|
|
52
|
+
changed_fields=frozenset(["args"]),
|
|
53
|
+
source_scope="project",
|
|
54
|
+
config_path="/repo/config.toml",
|
|
55
|
+
workspace=workspace,
|
|
56
|
+
launch_target=launch_target,
|
|
57
|
+
transport="stdio",
|
|
58
|
+
risk_summary="risk",
|
|
59
|
+
risk_signals=[],
|
|
60
|
+
artifact_label=None,
|
|
61
|
+
source_label=None,
|
|
62
|
+
trigger_summary=None,
|
|
63
|
+
why_now=None,
|
|
64
|
+
launch_summary=None,
|
|
65
|
+
risk_headline=None,
|
|
66
|
+
action_envelope_json=None,
|
|
67
|
+
decision_v2_json=None,
|
|
68
|
+
fallback_cli_command=None,
|
|
69
|
+
review_command=f"hol-guard review {rid}",
|
|
70
|
+
approval_url=f"http://localhost:4455/approve/{rid}",
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class TestDuplicatePendingRequestCollapse:
|
|
75
|
+
"""T719-T720: Duplicate pending requests collapse to one row."""
|
|
76
|
+
|
|
77
|
+
def test_second_identical_request_updates_existing_row(self) -> None:
|
|
78
|
+
"""T720: A second pending request for the same artifact+workspace+launch_target
|
|
79
|
+
must update the existing row and not create a new one."""
|
|
80
|
+
conn = _make_conn()
|
|
81
|
+
artifact_id = "codex:project:tool-abc"
|
|
82
|
+
req1 = _make_request(artifact_id=artifact_id, workspace="ws-a", launch_target="run tool --flag")
|
|
83
|
+
req2 = _make_request(artifact_id=artifact_id, workspace="ws-a", launch_target="run tool --flag")
|
|
84
|
+
|
|
85
|
+
id1 = add_approval_request(conn, req1, "2026-01-01T00:00:00Z")
|
|
86
|
+
id2 = add_approval_request(conn, req2, "2026-01-01T00:01:00Z")
|
|
87
|
+
|
|
88
|
+
assert id1 == id2, "Second identical request must reuse the existing request_id"
|
|
89
|
+
total = count_approval_requests(conn, status="pending")
|
|
90
|
+
assert total == 1, f"Expected 1 pending row, got {total}"
|
|
91
|
+
|
|
92
|
+
def test_transient_variation_collapses_to_same_row(self) -> None:
|
|
93
|
+
"""T719: Transient variation (UUID in args) must not create a new row."""
|
|
94
|
+
conn = _make_conn()
|
|
95
|
+
artifact_id = "codex:project:tool-xyz"
|
|
96
|
+
req1 = _make_request(
|
|
97
|
+
artifact_id=artifact_id,
|
|
98
|
+
workspace="ws-b",
|
|
99
|
+
launch_target="run tool --request-id req-aaaaaaaaaaaa --flag",
|
|
100
|
+
)
|
|
101
|
+
req2 = _make_request(
|
|
102
|
+
artifact_id=artifact_id,
|
|
103
|
+
workspace="ws-b",
|
|
104
|
+
launch_target="run tool --request-id req-bbbbbbbbbbbb --flag",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
id1 = add_approval_request(conn, req1, "2026-01-01T00:00:00Z")
|
|
108
|
+
id2 = add_approval_request(conn, req2, "2026-01-01T00:01:00Z")
|
|
109
|
+
|
|
110
|
+
assert id1 == id2, "Same command with different transient request IDs must collapse to one row"
|
|
111
|
+
total = count_approval_requests(conn, status="pending")
|
|
112
|
+
assert total == 1, f"Expected 1 pending row after transient variation, got {total}"
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class TestDifferentWorkspacesGetSeparateRows:
|
|
116
|
+
"""T721: Different workspaces must produce separate approval request rows."""
|
|
117
|
+
|
|
118
|
+
def test_same_artifact_different_workspaces_creates_two_rows(self) -> None:
|
|
119
|
+
"""T721: Same artifact in different workspaces must each queue its own approval."""
|
|
120
|
+
conn = _make_conn()
|
|
121
|
+
artifact_id = "codex:project:tool-shared"
|
|
122
|
+
req_ws_a = _make_request(artifact_id=artifact_id, workspace="ws-a", launch_target="run tool")
|
|
123
|
+
req_ws_b = _make_request(artifact_id=artifact_id, workspace="ws-b", launch_target="run tool")
|
|
124
|
+
|
|
125
|
+
id_a = add_approval_request(conn, req_ws_a, "2026-01-01T00:00:00Z")
|
|
126
|
+
id_b = add_approval_request(conn, req_ws_b, "2026-01-01T00:01:00Z")
|
|
127
|
+
|
|
128
|
+
assert id_a != id_b, "Different workspaces must get separate request IDs"
|
|
129
|
+
total = count_approval_requests(conn, status="pending")
|
|
130
|
+
assert total == 2, f"Expected 2 pending rows for 2 workspaces, got {total}"
|
|
131
|
+
|
|
132
|
+
def test_null_and_named_workspace_get_separate_rows(self) -> None:
|
|
133
|
+
"""T721b: Null workspace and a named workspace must be treated as different."""
|
|
134
|
+
conn = _make_conn()
|
|
135
|
+
artifact_id = "codex:project:tool-null-ws"
|
|
136
|
+
req_null = _make_request(artifact_id=artifact_id, workspace=None, launch_target="run tool")
|
|
137
|
+
req_named = _make_request(artifact_id=artifact_id, workspace="ws-c", launch_target="run tool")
|
|
138
|
+
|
|
139
|
+
id_null = add_approval_request(conn, req_null, "2026-01-01T00:00:00Z")
|
|
140
|
+
id_named = add_approval_request(conn, req_named, "2026-01-01T00:01:00Z")
|
|
141
|
+
|
|
142
|
+
assert id_null != id_named, "Null workspace and named workspace must get separate request IDs"
|
|
143
|
+
pending = list_approval_requests(conn, status="pending")
|
|
144
|
+
assert len(pending) == 2, f"Expected 2 pending rows, got {len(pending)}"
|
|
145
|
+
|
|
146
|
+
def test_different_launch_targets_create_separate_rows(self) -> None:
|
|
147
|
+
"""T719b: Different commands for same artifact+workspace must queue separate approvals."""
|
|
148
|
+
conn = _make_conn()
|
|
149
|
+
artifact_id = "codex:project:tool-multi"
|
|
150
|
+
req_ls = _make_request(artifact_id=artifact_id, workspace="ws-a", launch_target="run ls /repo")
|
|
151
|
+
req_rm = _make_request(artifact_id=artifact_id, workspace="ws-a", launch_target="run rm /tmp/file")
|
|
152
|
+
|
|
153
|
+
id_ls = add_approval_request(conn, req_ls, "2026-01-01T00:00:00Z")
|
|
154
|
+
id_rm = add_approval_request(conn, req_rm, "2026-01-01T00:01:00Z")
|
|
155
|
+
|
|
156
|
+
assert id_ls != id_rm, "Different commands must not collapse into one approval row"
|
|
157
|
+
total = count_approval_requests(conn, status="pending")
|
|
158
|
+
assert total == 2, f"Expected 2 pending rows for different commands, got {total}"
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class TestLegacyNullIdentityKeyUpgradePath:
|
|
162
|
+
"""Regression: existing rows with NULL normalized_identity_key must still be deduped."""
|
|
163
|
+
|
|
164
|
+
def test_legacy_null_row_is_updated_not_duplicated(self) -> None:
|
|
165
|
+
"""After upgrade, a pending row with NULL identity key must be reused for the same
|
|
166
|
+
artifact+workspace instead of inserting a duplicate row."""
|
|
167
|
+
conn = _make_conn()
|
|
168
|
+
artifact_id = "codex:project:tool-legacy"
|
|
169
|
+
req_legacy = _make_request(artifact_id=artifact_id, workspace="ws-a", launch_target="run tool")
|
|
170
|
+
first_id = add_approval_request(conn, req_legacy, "2026-01-01T00:00:00Z")
|
|
171
|
+
|
|
172
|
+
conn.execute(
|
|
173
|
+
"update approval_requests set normalized_identity_key = NULL where request_id = ?",
|
|
174
|
+
(first_id,),
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
req_new = _make_request(artifact_id=artifact_id, workspace="ws-a", launch_target="run tool")
|
|
178
|
+
second_id = add_approval_request(conn, req_new, "2026-01-01T00:01:00Z")
|
|
179
|
+
|
|
180
|
+
assert first_id == second_id, "Legacy row with NULL identity key must be reused, not duplicated"
|
|
181
|
+
total = count_approval_requests(conn, status="pending")
|
|
182
|
+
assert total == 1, f"Expected 1 pending row after deduping legacy null row, got {total}"
|
|
183
|
+
|
|
184
|
+
def test_legacy_null_row_different_command_not_collapsed(self) -> None:
|
|
185
|
+
"""Legacy NULL rows for different commands must NOT be collapsed even during upgrade path."""
|
|
186
|
+
conn = _make_conn()
|
|
187
|
+
artifact_id = "codex:project:tool-multi"
|
|
188
|
+
req_a = _make_request(artifact_id=artifact_id, workspace="ws-a", launch_target="run cmd-a")
|
|
189
|
+
id_a = add_approval_request(conn, req_a, "2026-01-01T00:00:00Z")
|
|
190
|
+
conn.execute(
|
|
191
|
+
"update approval_requests set normalized_identity_key = NULL where request_id = ?",
|
|
192
|
+
(id_a,),
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
req_b = _make_request(artifact_id=artifact_id, workspace="ws-a", launch_target="run cmd-b")
|
|
196
|
+
id_b = add_approval_request(conn, req_b, "2026-01-01T00:01:00Z")
|
|
197
|
+
|
|
198
|
+
assert id_a != id_b, "Different commands must each get their own pending row even when legacy row is NULL"
|
|
199
|
+
total = count_approval_requests(conn, status="pending")
|
|
200
|
+
assert total == 2, f"Expected 2 pending rows for different commands, got {total}"
|
|
201
|
+
|
|
202
|
+
def test_legacy_null_launch_target_row_is_deduped(self) -> None:
|
|
203
|
+
"""Legacy rows with NULL launch_target AND NULL identity key must be deduped for the same artifact."""
|
|
204
|
+
conn = _make_conn()
|
|
205
|
+
artifact_id = "codex:project:tool-null-target"
|
|
206
|
+
req_null = _make_request(artifact_id=artifact_id, workspace="ws-a", launch_target=None)
|
|
207
|
+
first_id = add_approval_request(conn, req_null, "2026-01-01T00:00:00Z")
|
|
208
|
+
|
|
209
|
+
conn.execute(
|
|
210
|
+
"update approval_requests set normalized_identity_key = NULL where request_id = ?",
|
|
211
|
+
(first_id,),
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
req_retry = _make_request(artifact_id=artifact_id, workspace="ws-a", launch_target=None)
|
|
215
|
+
second_id = add_approval_request(conn, req_retry, "2026-01-01T00:01:00Z")
|
|
216
|
+
|
|
217
|
+
assert first_id == second_id, "NULL-launch-target legacy row must be reused for the same artifact"
|
|
218
|
+
total = count_approval_requests(conn, status="pending")
|
|
219
|
+
assert total == 1, f"Expected 1 pending row for NULL launch_target dedup, got {total}"
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""Phase 25 — immediate decision propagation: browser approve/block writes
|
|
2
|
+
decision before harness retry resumes (T722-T724).
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from codex_plugin_scanner.guard.approvals import apply_approval_resolution, queue_blocked_approvals
|
|
10
|
+
from codex_plugin_scanner.guard.config import GuardConfig
|
|
11
|
+
from codex_plugin_scanner.guard.consumer.service import evaluate_detection
|
|
12
|
+
from codex_plugin_scanner.guard.models import (
|
|
13
|
+
GuardArtifact,
|
|
14
|
+
HarnessDetection,
|
|
15
|
+
)
|
|
16
|
+
from codex_plugin_scanner.guard.store import GuardStore
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _make_artifact(
|
|
20
|
+
*,
|
|
21
|
+
name: str = "test_tool",
|
|
22
|
+
config_path: str = "/repo/workspace/.codex/config.toml",
|
|
23
|
+
) -> GuardArtifact:
|
|
24
|
+
return GuardArtifact(
|
|
25
|
+
artifact_id=f"codex:project:{name}",
|
|
26
|
+
name=name,
|
|
27
|
+
harness="codex",
|
|
28
|
+
artifact_type="mcp_server",
|
|
29
|
+
source_scope="project",
|
|
30
|
+
config_path=config_path,
|
|
31
|
+
command="node",
|
|
32
|
+
args=("server.js",),
|
|
33
|
+
transport="stdio",
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _make_detection(artifact: GuardArtifact) -> HarnessDetection:
|
|
38
|
+
return HarnessDetection(
|
|
39
|
+
harness="codex",
|
|
40
|
+
installed=True,
|
|
41
|
+
command_available=True,
|
|
42
|
+
config_paths=(artifact.config_path,),
|
|
43
|
+
artifacts=(artifact,),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class TestImmediateApproveDecisionPropagation:
|
|
48
|
+
"""T722-T723: Browser approve writes decision before harness retry resumes."""
|
|
49
|
+
|
|
50
|
+
def test_approve_decision_visible_to_evaluate_without_delay(self, tmp_path: Path) -> None:
|
|
51
|
+
"""T723: After apply_approval_resolution(allow), re-running evaluate_detection
|
|
52
|
+
immediately returns an allowed evaluation with no pending approval request.
|
|
53
|
+
"""
|
|
54
|
+
guard_home = tmp_path / "guard"
|
|
55
|
+
store = GuardStore(guard_home)
|
|
56
|
+
artifact = _make_artifact(name="sync_tool", config_path=str(tmp_path / "ws/.codex/config.toml"))
|
|
57
|
+
config = GuardConfig(guard_home=guard_home, workspace=None)
|
|
58
|
+
detection = _make_detection(artifact)
|
|
59
|
+
|
|
60
|
+
initial_eval = evaluate_detection(detection, store, config, persist=True)
|
|
61
|
+
assert initial_eval.get("blocked") is True, "Tool must be blocked before approval"
|
|
62
|
+
|
|
63
|
+
approvals = queue_blocked_approvals(
|
|
64
|
+
detection=detection,
|
|
65
|
+
evaluation=initial_eval,
|
|
66
|
+
store=store,
|
|
67
|
+
approval_center_url="http://127.0.0.1:6174",
|
|
68
|
+
)
|
|
69
|
+
assert len(approvals) > 0, "Must queue at least one approval request"
|
|
70
|
+
request_id = str(approvals[0]["request_id"])
|
|
71
|
+
|
|
72
|
+
apply_approval_resolution(
|
|
73
|
+
store=store,
|
|
74
|
+
request_id=request_id,
|
|
75
|
+
action="allow",
|
|
76
|
+
scope="artifact",
|
|
77
|
+
workspace=None,
|
|
78
|
+
reason=None,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
retry_eval = evaluate_detection(detection, store, config, persist=False)
|
|
82
|
+
assert retry_eval.get("blocked") is False, "T723: Evaluation immediately after approval must not be blocked"
|
|
83
|
+
artifact_result = (retry_eval.get("artifacts") or [{}])[0]
|
|
84
|
+
assert artifact_result.get("policy_action") == "allow", (
|
|
85
|
+
"T723: Evaluation immediately after approval must return allow policy"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
def test_approve_propagation_occurs_before_request_resolution_response(self, tmp_path: Path) -> None:
|
|
89
|
+
"""T722: apply_approval_resolution writes the policy before marking the
|
|
90
|
+
request resolved, so the harness can re-evaluate the moment the POST
|
|
91
|
+
response arrives.
|
|
92
|
+
"""
|
|
93
|
+
guard_home = tmp_path / "guard"
|
|
94
|
+
store = GuardStore(guard_home)
|
|
95
|
+
artifact = _make_artifact(name="ordered_tool", config_path=str(tmp_path / "ws/.codex/config.toml"))
|
|
96
|
+
config = GuardConfig(guard_home=guard_home, workspace=None)
|
|
97
|
+
detection = _make_detection(artifact)
|
|
98
|
+
|
|
99
|
+
eval_before = evaluate_detection(detection, store, config, persist=True)
|
|
100
|
+
approvals = queue_blocked_approvals(
|
|
101
|
+
detection=detection,
|
|
102
|
+
evaluation=eval_before,
|
|
103
|
+
store=store,
|
|
104
|
+
approval_center_url="http://127.0.0.1:6174",
|
|
105
|
+
)
|
|
106
|
+
request_id = str(approvals[0]["request_id"])
|
|
107
|
+
|
|
108
|
+
apply_approval_resolution(
|
|
109
|
+
store=store,
|
|
110
|
+
request_id=request_id,
|
|
111
|
+
action="allow",
|
|
112
|
+
scope="artifact",
|
|
113
|
+
workspace=None,
|
|
114
|
+
reason=None,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
resolved = store.get_approval_request(request_id)
|
|
118
|
+
assert resolved is not None
|
|
119
|
+
assert resolved["status"] == "resolved", "Request must be marked resolved after approval"
|
|
120
|
+
|
|
121
|
+
immediate_eval = evaluate_detection(detection, store, config, persist=False)
|
|
122
|
+
assert immediate_eval.get("blocked") is False, "T722: Policy must be written before request is marked resolved"
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class TestImmediateDenyDecisionPropagation:
|
|
126
|
+
"""T724: Browser deny writes decision before harness retry resumes."""
|
|
127
|
+
|
|
128
|
+
def test_deny_decision_visible_to_evaluate_without_delay(self, tmp_path: Path) -> None:
|
|
129
|
+
"""T724: After apply_approval_resolution(block), re-running evaluate_detection
|
|
130
|
+
immediately returns a blocked evaluation.
|
|
131
|
+
"""
|
|
132
|
+
guard_home = tmp_path / "guard"
|
|
133
|
+
store = GuardStore(guard_home)
|
|
134
|
+
artifact = _make_artifact(name="denied_tool", config_path=str(tmp_path / "ws/.codex/config.toml"))
|
|
135
|
+
config = GuardConfig(guard_home=guard_home, workspace=None)
|
|
136
|
+
detection = _make_detection(artifact)
|
|
137
|
+
|
|
138
|
+
initial_eval = evaluate_detection(detection, store, config, persist=True)
|
|
139
|
+
approvals = queue_blocked_approvals(
|
|
140
|
+
detection=detection,
|
|
141
|
+
evaluation=initial_eval,
|
|
142
|
+
store=store,
|
|
143
|
+
approval_center_url="http://127.0.0.1:6174",
|
|
144
|
+
)
|
|
145
|
+
assert len(approvals) > 0
|
|
146
|
+
request_id = str(approvals[0]["request_id"])
|
|
147
|
+
|
|
148
|
+
apply_approval_resolution(
|
|
149
|
+
store=store,
|
|
150
|
+
request_id=request_id,
|
|
151
|
+
action="block",
|
|
152
|
+
scope="artifact",
|
|
153
|
+
workspace=None,
|
|
154
|
+
reason="Not permitted by security policy",
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
retry_eval = evaluate_detection(detection, store, config, persist=False)
|
|
158
|
+
assert retry_eval.get("blocked") is True, "T724: Evaluation immediately after deny must be blocked"
|
|
159
|
+
artifact_result = (retry_eval.get("artifacts") or [{}])[0]
|
|
160
|
+
assert artifact_result.get("policy_action") == "block", (
|
|
161
|
+
"T724: Evaluation immediately after deny must return block policy"
|
|
162
|
+
)
|
|
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.134 → plugin_scanner-2.0.135}/.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.134 → plugin_scanner-2.0.135}/dashboard/src/approval-center-layout.test.ts
RENAMED
|
File without changes
|
|
File without changes
|
{plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/dashboard/src/approval-center-primitives.tsx
RENAMED
|
File without changes
|
{plugin_scanner-2.0.134 → plugin_scanner-2.0.135}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|