plugin-scanner 2.0.100__tar.gz → 2.0.102__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.100 → plugin_scanner-2.0.102}/PKG-INFO +1 -1
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/pyproject.toml +1 -1
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/pyproject.toml.bak +1 -1
- plugin_scanner-2.0.102/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +88 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/adapters/hermes.py +13 -1
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/adapters/openclaw.py +13 -1
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/approvals.py +8 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/cli/commands.py +14 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/consumer/service.py +7 -1
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/models.py +1 -0
- plugin_scanner-2.0.102/src/codex_plugin_scanner/guard/policy/__init__.py +5 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/policy/engine.py +31 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/store.py +1 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/store_approvals.py +13 -9
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/version.py +1 -1
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_approvals.py +29 -3
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_runtime.py +48 -1
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_hermes_adapter.py +68 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_openclaw_adapter.py +68 -0
- plugin_scanner-2.0.100/src/codex_plugin_scanner/guard/policy/__init__.py +0 -5
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.clusterfuzzlite/Dockerfile +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.clusterfuzzlite/build.sh +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.clusterfuzzlite/project.yaml +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.clusterfuzzlite/requirements-atheris.txt +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.dockerignore +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.github/CODEOWNERS +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.github/dependabot.yml +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.github/workflows/ci.yml +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.github/workflows/codeql.yml +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.github/workflows/dependabot-uv-lock.yml +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.github/workflows/fuzz.yml +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.github/workflows/harness-smoke.yml +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.github/workflows/publish.yml +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.github/workflows/scorecard.yml +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.gitignore +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/.pre-commit-hooks.yaml +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/CONTRIBUTING.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/Dockerfile +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/LICENSE +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/README.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/SECURITY.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/index.html +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/package.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/pnpm-lock.yaml +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/public/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/public/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/public/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/public/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/public/favicon.ico +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/src/app.tsx +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/src/approval-center-layout.tsx +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/src/approval-center-primitives.tsx +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/src/approval-center-utils.ts +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/src/fleet-workspace.tsx +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/src/guard-api.test.ts +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/src/guard-api.ts +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/src/guard-demo.ts +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/src/guard-types.ts +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/src/main.tsx +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/src/receipts-workspace.tsx +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/src/runtime-overview.tsx +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/src/settings-workspace.tsx +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/src/styles.css +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/src/vite-env.d.ts +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/tsconfig.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/dashboard/vite.config.ts +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/docker-requirements.txt +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/docs/guard/approval-audit.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/docs/guard/architecture.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/docs/guard/get-started.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/docs/guard/harness-support.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/docs/guard/local-vs-cloud.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/docs/guard/testing-matrix.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/docs/trust/mcp-trust-draft.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/docs/trust/plugin-trust-draft.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/docs/trust/skill-trust-local.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/fuzzers/manifest_fuzzer.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/requirements.txt +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/schemas/plugin-quality.v1.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/schemas/scan-result.v1.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/schemas/verify-result.v1.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/__init__.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/action_runner.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/argparse_utils.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/checks/__init__.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/checks/claude.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/checks/gemini.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/checks/manifest.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/checks/opencode.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/checks/security.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/cli.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/cli_ui.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/config.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/github_reporting.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/__init__.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/config.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/incident.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/launcher.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/protect.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/redaction.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/risk.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/shims.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/types.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/lint_fixes.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/marketplace_support.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/models.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/path_support.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/policy.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/quality_artifact.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/repo_detect.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/reporting.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/rules/__init__.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/rules/registry.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/rules/specs.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/scanner.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/submission.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/suppressions.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/trust_helpers.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/trust_models.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/trust_scoring.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/trust_specs.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/verification.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/__init__.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/conftest.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/__init__.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/bad-plugin/.mcp.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/bad-plugin/secrets.js +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/claude-plugin-good/README.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/code-quality-bad/evil.js +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/code-quality-bad/inject.js +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/gemini-extension-good/README.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/good-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/good-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/good-plugin/README.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/good-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/mcp-canary-server.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/mit-license/LICENSE +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/opencode-good/LICENSE +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/opencode-good/README.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/opencode-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/fixtures/with-marketplace/marketplace.json +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test-trust-scoring.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test-trust-specs.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_action_runner.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_best_practices.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_cisco_install_surfaces.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_cli.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_code_quality.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_config.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_coverage_remaining.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_ecosystems.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_edge_cases.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_final_coverage.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_bootstrap.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_capabilities.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_claude_adapter.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_cli.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_codex_e2e.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_codex_install.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_codex_proxy.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_config_paths.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_connect_flow.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_consumer_mode.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_copilot_adapter.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_copilot_proxy.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_daemon_manager.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_event_schema_v1.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_events.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_launch_env.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_opencode_proxy.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_product_flow.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_protect.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_render.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_risk.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_runtime_action_harnesses.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_runtime_actions.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_runtime_decisions.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_runtime_signals.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_store_migrations.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_surface_server.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_guard_verdicts.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_integration.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_lint_fixes.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_live_cisco_smoke.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_manifest.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_marketplace.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_mcp_security.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_operational_security.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_policy.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_quality_artifact.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_rule_registry.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_scanner.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_schema_contracts.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_security.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_security_ops.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_skill_security.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_submission.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_trust_scoring.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_trust_specs.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_verification.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/tests/test_versioning.py +0 -0
- {plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/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.102
|
|
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.102"
|
|
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.102"
|
|
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,88 @@
|
|
|
1
|
+
"""Guard Cloud agent identity hints for local harness adapters."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import sqlite3
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from .base import HarnessContext
|
|
10
|
+
|
|
11
|
+
_SERVICE_RUNTIME_PROFILE_STATE_KEY = "service_runtime_profile"
|
|
12
|
+
_PROFILE_FIELDS = (
|
|
13
|
+
"runtime",
|
|
14
|
+
"label",
|
|
15
|
+
"workspace",
|
|
16
|
+
"surface",
|
|
17
|
+
"client_name",
|
|
18
|
+
"client_title",
|
|
19
|
+
"client_version",
|
|
20
|
+
"agent_id",
|
|
21
|
+
"principal_id",
|
|
22
|
+
)
|
|
23
|
+
_ENV_FIELDS = {
|
|
24
|
+
"runtime": "RUNTIME",
|
|
25
|
+
"label": "LABEL",
|
|
26
|
+
"workspace": "WORKSPACE",
|
|
27
|
+
"agent_id": "AGENT_ID",
|
|
28
|
+
"principal_id": "PRINCIPAL_ID",
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def cloud_agent_identity_hints(
|
|
33
|
+
context: HarnessContext,
|
|
34
|
+
*,
|
|
35
|
+
runtime: str,
|
|
36
|
+
) -> dict[str, str] | None:
|
|
37
|
+
payload = _read_service_runtime_profile(context.guard_home / "guard.db")
|
|
38
|
+
if payload is None or _string_field(payload, "runtime") != runtime:
|
|
39
|
+
return None
|
|
40
|
+
hints = {field: value for field in _PROFILE_FIELDS if (value := _string_field(payload, field)) is not None}
|
|
41
|
+
return hints if hints else None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def cloud_agent_identity_environment(
|
|
45
|
+
identity: object,
|
|
46
|
+
*,
|
|
47
|
+
prefix: str,
|
|
48
|
+
) -> dict[str, str]:
|
|
49
|
+
if not isinstance(identity, dict):
|
|
50
|
+
return {}
|
|
51
|
+
env: dict[str, str] = {}
|
|
52
|
+
for field, suffix in _ENV_FIELDS.items():
|
|
53
|
+
value = identity.get(field)
|
|
54
|
+
if isinstance(value, str) and value:
|
|
55
|
+
env[f"{prefix}_GUARD_CLOUD_{suffix}"] = value
|
|
56
|
+
return env
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _read_service_runtime_profile(db_path: Path) -> dict[str, object] | None:
|
|
60
|
+
if not db_path.exists():
|
|
61
|
+
return None
|
|
62
|
+
try:
|
|
63
|
+
db_uri = f"{db_path.resolve().as_uri()}?mode=ro"
|
|
64
|
+
connection = sqlite3.connect(db_uri, uri=True)
|
|
65
|
+
try:
|
|
66
|
+
row = connection.execute(
|
|
67
|
+
"select payload_json from sync_state where state_key = ?",
|
|
68
|
+
(_SERVICE_RUNTIME_PROFILE_STATE_KEY,),
|
|
69
|
+
).fetchone()
|
|
70
|
+
finally:
|
|
71
|
+
connection.close()
|
|
72
|
+
except (OSError, sqlite3.Error):
|
|
73
|
+
return None
|
|
74
|
+
if row is None:
|
|
75
|
+
return None
|
|
76
|
+
try:
|
|
77
|
+
payload = json.loads(str(row[0]))
|
|
78
|
+
except json.JSONDecodeError:
|
|
79
|
+
return None
|
|
80
|
+
return payload if isinstance(payload, dict) else None
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _string_field(payload: dict[str, object], field: str) -> str | None:
|
|
84
|
+
value = payload.get(field)
|
|
85
|
+
if not isinstance(value, str):
|
|
86
|
+
return None
|
|
87
|
+
stripped = value.strip()
|
|
88
|
+
return stripped or None
|
{plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/adapters/hermes.py
RENAMED
|
@@ -16,6 +16,7 @@ from pathlib import Path
|
|
|
16
16
|
from ..models import GuardArtifact, HarnessDetection
|
|
17
17
|
from ..shims import install_guard_shim, remove_guard_shim
|
|
18
18
|
from .base import HarnessAdapter, HarnessContext, _command_available, _json_payload, _run_command_probe
|
|
19
|
+
from .cloud_identity import cloud_agent_identity_environment, cloud_agent_identity_hints
|
|
19
20
|
|
|
20
21
|
# Optional: PyYAML is preferred when available for robust YAML parsing.
|
|
21
22
|
# The adapter works without it via a line-based fallback parser.
|
|
@@ -83,6 +84,7 @@ class HermesHarnessAdapter(HarnessAdapter):
|
|
|
83
84
|
)
|
|
84
85
|
source_configs = _load_mcp_server_sources(context.home_dir / ".hermes")
|
|
85
86
|
overlay_servers = _overlay_servers(context=context, source_configs=source_configs)
|
|
87
|
+
cloud_identity = cloud_agent_identity_hints(context, runtime=self.harness)
|
|
86
88
|
overlay_path.write_text(json.dumps(overlay_servers, indent=2) + "\n", encoding="utf-8")
|
|
87
89
|
pretool_path.write_text(
|
|
88
90
|
json.dumps(_pretool_payload(context=context), indent=2) + "\n",
|
|
@@ -109,6 +111,8 @@ class HermesHarnessAdapter(HarnessAdapter):
|
|
|
109
111
|
*[str(note) for note in shim_manifest.get("notes", [])],
|
|
110
112
|
],
|
|
111
113
|
}
|
|
114
|
+
if cloud_identity is not None:
|
|
115
|
+
manifest["cloud_agent_identity"] = cloud_identity
|
|
112
116
|
manifest_path.write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8")
|
|
113
117
|
return manifest
|
|
114
118
|
|
|
@@ -147,10 +151,17 @@ class HermesHarnessAdapter(HarnessAdapter):
|
|
|
147
151
|
pretool_path = manifest.get("pretool_hook_path")
|
|
148
152
|
if not isinstance(overlay_path, str) or not isinstance(pretool_path, str):
|
|
149
153
|
return {}
|
|
150
|
-
|
|
154
|
+
environment = {
|
|
151
155
|
"HERMES_GUARD_MCP_OVERLAY_PATH": overlay_path,
|
|
152
156
|
"HERMES_GUARD_PRETOOL_PATH": pretool_path,
|
|
153
157
|
}
|
|
158
|
+
environment.update(
|
|
159
|
+
cloud_agent_identity_environment(
|
|
160
|
+
cloud_agent_identity_hints(context, runtime=self.harness),
|
|
161
|
+
prefix="HERMES",
|
|
162
|
+
)
|
|
163
|
+
)
|
|
164
|
+
return environment
|
|
154
165
|
|
|
155
166
|
def runtime_probe(self, context: HarnessContext) -> dict[str, object] | None:
|
|
156
167
|
manifest = _json_payload(_managed_root(context) / "manifest.json")
|
|
@@ -165,6 +176,7 @@ class HermesHarnessAdapter(HarnessAdapter):
|
|
|
165
176
|
and isinstance(pretool_path, str)
|
|
166
177
|
and Path(pretool_path).exists()
|
|
167
178
|
),
|
|
179
|
+
"cloud_agent_identity_configured": bool(cloud_agent_identity_hints(context, runtime=self.harness)),
|
|
168
180
|
}
|
|
169
181
|
|
|
170
182
|
def approval_flow(self, *, managed_install: dict[str, object] | None = None) -> dict[str, object]:
|
|
@@ -15,6 +15,7 @@ from .base import (
|
|
|
15
15
|
_json_payload,
|
|
16
16
|
_run_command_probe,
|
|
17
17
|
)
|
|
18
|
+
from .cloud_identity import cloud_agent_identity_environment, cloud_agent_identity_hints
|
|
18
19
|
from .openclaw_config import load_config
|
|
19
20
|
from .openclaw_support import (
|
|
20
21
|
config_artifacts,
|
|
@@ -77,6 +78,7 @@ class OpenClawHarnessAdapter(HarnessAdapter):
|
|
|
77
78
|
pretool_path=pretool_path,
|
|
78
79
|
)
|
|
79
80
|
detection = self.detect(context)
|
|
81
|
+
cloud_identity = cloud_agent_identity_hints(context, runtime=self.harness)
|
|
80
82
|
overlay_path.write_text(json.dumps(overlay_payload(detection), indent=2) + "\n", encoding="utf-8")
|
|
81
83
|
pretool_path.write_text(json.dumps(pretool_payload(context=context), indent=2) + "\n", encoding="utf-8")
|
|
82
84
|
manifest = {
|
|
@@ -102,6 +104,8 @@ class OpenClawHarnessAdapter(HarnessAdapter):
|
|
|
102
104
|
*[str(note) for note in shim_manifest.get("notes", [])],
|
|
103
105
|
],
|
|
104
106
|
}
|
|
107
|
+
if cloud_identity is not None:
|
|
108
|
+
manifest["cloud_agent_identity"] = cloud_identity
|
|
105
109
|
manifest_path.write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8")
|
|
106
110
|
return manifest
|
|
107
111
|
|
|
@@ -137,11 +141,18 @@ class OpenClawHarnessAdapter(HarnessAdapter):
|
|
|
137
141
|
pretool_path = manifest.get("pretool_hook_path")
|
|
138
142
|
if not isinstance(overlay_path, str) or not isinstance(pretool_path, str):
|
|
139
143
|
return {}
|
|
140
|
-
|
|
144
|
+
environment = {
|
|
141
145
|
"OPENCLAW_GUARD_OVERLAY_PATH": overlay_path,
|
|
142
146
|
"OPENCLAW_GUARD_PRETOOL_PATH": pretool_path,
|
|
143
147
|
"OPENCLAW_GUARD_CHANNEL_POSTURE": "enabled",
|
|
144
148
|
}
|
|
149
|
+
environment.update(
|
|
150
|
+
cloud_agent_identity_environment(
|
|
151
|
+
cloud_agent_identity_hints(context, runtime=self.harness),
|
|
152
|
+
prefix="OPENCLAW",
|
|
153
|
+
)
|
|
154
|
+
)
|
|
155
|
+
return environment
|
|
145
156
|
|
|
146
157
|
def runtime_probe(self, context: HarnessContext) -> dict[str, object] | None:
|
|
147
158
|
manifest = _json_payload(managed_root(context) / "manifest.json")
|
|
@@ -156,6 +167,7 @@ class OpenClawHarnessAdapter(HarnessAdapter):
|
|
|
156
167
|
and isinstance(pretool_path, str)
|
|
157
168
|
and Path(pretool_path).exists()
|
|
158
169
|
),
|
|
170
|
+
"cloud_agent_identity_configured": bool(cloud_agent_identity_hints(context, runtime=self.harness)),
|
|
159
171
|
}
|
|
160
172
|
|
|
161
173
|
def approval_flow(self, *, managed_install: dict[str, object] | None = None) -> dict[str, object]:
|
{plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/approvals.py
RENAMED
|
@@ -88,6 +88,7 @@ def queue_blocked_approvals(
|
|
|
88
88
|
launch_summary=incident["launch_summary"],
|
|
89
89
|
risk_headline=incident["risk_headline"],
|
|
90
90
|
action_envelope_json=_item_action_envelope_json(item),
|
|
91
|
+
decision_v2_json=_item_decision_v2_json(item),
|
|
91
92
|
)
|
|
92
93
|
persisted_request_id = store.add_approval_request(request, timestamp)
|
|
93
94
|
if persisted_request_id != request.request_id:
|
|
@@ -342,6 +343,13 @@ def _item_action_envelope_json(item: dict[str, object]) -> dict[str, object] | N
|
|
|
342
343
|
return {str(key): item_value for key, item_value in value.items() if isinstance(key, str)}
|
|
343
344
|
|
|
344
345
|
|
|
346
|
+
def _item_decision_v2_json(item: dict[str, object]) -> dict[str, object] | None:
|
|
347
|
+
value = item.get("decision_v2_json")
|
|
348
|
+
if not isinstance(value, Mapping):
|
|
349
|
+
return None
|
|
350
|
+
return {str(key): item_value for key, item_value in value.items() if isinstance(key, str)}
|
|
351
|
+
|
|
352
|
+
|
|
345
353
|
def _string_list(value: object) -> list[str]:
|
|
346
354
|
if not isinstance(value, list):
|
|
347
355
|
return []
|
{plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/cli/commands.py
RENAMED
|
@@ -15,6 +15,7 @@ import sys
|
|
|
15
15
|
import urllib.error
|
|
16
16
|
import urllib.parse
|
|
17
17
|
import webbrowser
|
|
18
|
+
from collections.abc import Mapping
|
|
18
19
|
from contextlib import suppress
|
|
19
20
|
from dataclasses import replace
|
|
20
21
|
from datetime import datetime, timedelta, timezone
|
|
@@ -3130,6 +3131,9 @@ def _native_prompt_context(artifact: GuardArtifact) -> str:
|
|
|
3130
3131
|
|
|
3131
3132
|
|
|
3132
3133
|
def _runtime_artifact_native_reason(artifact: GuardArtifact, response_payload: dict[str, object]) -> str:
|
|
3134
|
+
decision_message = _decision_v2_harness_message(response_payload)
|
|
3135
|
+
if decision_message is not None:
|
|
3136
|
+
return decision_message
|
|
3133
3137
|
if artifact.artifact_type == "prompt_request":
|
|
3134
3138
|
harness = response_payload.get("harness")
|
|
3135
3139
|
prompt_classes = _prompt_request_classes(artifact)
|
|
@@ -3173,6 +3177,16 @@ def _runtime_artifact_native_reason(artifact: GuardArtifact, response_payload: d
|
|
|
3173
3177
|
return "HOL Guard flagged this request for review."
|
|
3174
3178
|
|
|
3175
3179
|
|
|
3180
|
+
def _decision_v2_harness_message(response_payload: dict[str, object]) -> str | None:
|
|
3181
|
+
decision_v2 = response_payload.get("decision_v2_json")
|
|
3182
|
+
if not isinstance(decision_v2, Mapping):
|
|
3183
|
+
return None
|
|
3184
|
+
message = decision_v2.get("harness_message")
|
|
3185
|
+
if isinstance(message, str) and message.strip():
|
|
3186
|
+
return message.strip()
|
|
3187
|
+
return None
|
|
3188
|
+
|
|
3189
|
+
|
|
3176
3190
|
def _claude_prompt_additional_context(
|
|
3177
3191
|
*,
|
|
3178
3192
|
harness: str,
|
{plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/consumer/service.py
RENAMED
|
@@ -15,9 +15,10 @@ from ..capabilities import compute_capability_delta, normalize_artifact_capabili
|
|
|
15
15
|
from ..config import GuardConfig
|
|
16
16
|
from ..incident import build_incident_context
|
|
17
17
|
from ..models import GuardArtifact, HarnessDetection, PolicyDecision
|
|
18
|
-
from ..policy import decide_action
|
|
18
|
+
from ..policy import build_decision_v2, decide_action
|
|
19
19
|
from ..receipts import build_receipt
|
|
20
20
|
from ..risk import artifact_risk_signals_typed, artifact_risk_summary, summarize_signals
|
|
21
|
+
from ..runtime.signals import RiskSignalV2
|
|
21
22
|
from ..schemas import build_consumer_mode_contract
|
|
22
23
|
from ..store import GuardStore
|
|
23
24
|
from ..types import (
|
|
@@ -384,6 +385,7 @@ def evaluate_detection(
|
|
|
384
385
|
current_capabilities = normalize_artifact_capabilities(artifact)
|
|
385
386
|
capability_delta = compute_capability_delta(previous_capabilities, current_capabilities)
|
|
386
387
|
structured_signals = artifact_risk_signals_typed(artifact)
|
|
388
|
+
risk_signals_v2 = tuple(RiskSignalV2.from_guard_signal(signal) for signal in structured_signals)
|
|
387
389
|
history_context = build_history_context(store, detection.harness, artifact.artifact_id, artifact.publisher)
|
|
388
390
|
provenance_bundle = build_provenance_bundle(store, artifact.publisher)
|
|
389
391
|
verdict = score_verdict(structured_signals, capability_delta, provenance_bundle, history_context)
|
|
@@ -405,6 +407,7 @@ def evaluate_detection(
|
|
|
405
407
|
)
|
|
406
408
|
if _is_blocking_action(policy_action):
|
|
407
409
|
blocked = True
|
|
410
|
+
decision_v2 = build_decision_v2(policy_action, reason=policy_action, signals=risk_signals_v2)
|
|
408
411
|
risk_signals = tuple(signal.explanation for signal in structured_signals)
|
|
409
412
|
risk_summary = artifact_risk_summary(artifact) if structured_signals else summarize_signals(())
|
|
410
413
|
changed_capabilities = [delta.delta_type for delta in capability_delta] or list(diff["changed_fields"])
|
|
@@ -495,6 +498,7 @@ def evaluate_detection(
|
|
|
495
498
|
"changed": diff["changed"],
|
|
496
499
|
"changed_fields": diff["changed_fields"],
|
|
497
500
|
"policy_action": policy_action,
|
|
501
|
+
"decision_v2_json": decision_v2.to_dict(),
|
|
498
502
|
"artifact_hash": diff["current_hash"],
|
|
499
503
|
"risk_signals": list(risk_signals),
|
|
500
504
|
"risk_summary": risk_summary,
|
|
@@ -536,6 +540,7 @@ def evaluate_detection(
|
|
|
536
540
|
)
|
|
537
541
|
if _is_blocking_action(policy_action):
|
|
538
542
|
blocked = True
|
|
543
|
+
decision_v2 = build_decision_v2(policy_action, reason=policy_action)
|
|
539
544
|
artifact_name = previous.get("name")
|
|
540
545
|
source_scope = previous.get("source_scope")
|
|
541
546
|
config_path = previous.get("config_path")
|
|
@@ -605,6 +610,7 @@ def evaluate_detection(
|
|
|
605
610
|
"changed": True,
|
|
606
611
|
"changed_fields": ["removed"],
|
|
607
612
|
"policy_action": policy_action,
|
|
613
|
+
"decision_v2_json": decision_v2.to_dict(),
|
|
608
614
|
"artifact_hash": previous_hash,
|
|
609
615
|
"removed": True,
|
|
610
616
|
"risk_signals": ["artifact removed from local harness configuration"],
|
|
@@ -179,6 +179,7 @@ class GuardApprovalRequest:
|
|
|
179
179
|
launch_summary: str | None = None
|
|
180
180
|
risk_headline: str | None = None
|
|
181
181
|
action_envelope_json: dict[str, object] | None = None
|
|
182
|
+
decision_v2_json: dict[str, object] | None = None
|
|
182
183
|
|
|
183
184
|
def to_dict(self) -> dict[str, object]:
|
|
184
185
|
payload = asdict(self)
|
{plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/policy/engine.py
RENAMED
|
@@ -2,8 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
from collections.abc import Sequence
|
|
6
|
+
|
|
5
7
|
from ..config import GuardConfig
|
|
6
8
|
from ..models import GuardAction
|
|
9
|
+
from ..runtime.decisions import GuardDecisionV2, decision_from_legacy_policy_action
|
|
10
|
+
from ..runtime.signals import RiskSignalV2
|
|
7
11
|
|
|
8
12
|
VALID_GUARD_ACTIONS = {"allow", "warn", "review", "block", "sandbox-required", "require-reapproval"}
|
|
9
13
|
SAFE_CHANGED_HASH_ACTION: GuardAction = "require-reapproval"
|
|
@@ -29,3 +33,30 @@ def decide_action(
|
|
|
29
33
|
if config.default_action in VALID_GUARD_ACTIONS:
|
|
30
34
|
return config.default_action
|
|
31
35
|
return SAFE_DEFAULT_ACTION
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def build_decision_v2(
|
|
39
|
+
policy_action: GuardAction,
|
|
40
|
+
*,
|
|
41
|
+
reason: str,
|
|
42
|
+
signals: Sequence[RiskSignalV2] = (),
|
|
43
|
+
) -> GuardDecisionV2:
|
|
44
|
+
return decision_from_legacy_policy_action(policy_action, reason=reason, signals=signals)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def decide_action_with_v2(
|
|
48
|
+
configured_action: str | None,
|
|
49
|
+
default_action: str | None,
|
|
50
|
+
config: GuardConfig,
|
|
51
|
+
changed: bool,
|
|
52
|
+
*,
|
|
53
|
+
reason: str,
|
|
54
|
+
signals: Sequence[RiskSignalV2] = (),
|
|
55
|
+
) -> tuple[GuardAction, GuardDecisionV2]:
|
|
56
|
+
action = decide_action(
|
|
57
|
+
configured_action=configured_action,
|
|
58
|
+
default_action=default_action,
|
|
59
|
+
config=config,
|
|
60
|
+
changed=changed,
|
|
61
|
+
)
|
|
62
|
+
return action, build_decision_v2(action, reason=reason, signals=signals)
|
|
@@ -667,6 +667,7 @@ class GuardStore:
|
|
|
667
667
|
self._ensure_approval_column(connection, "launch_summary", "text")
|
|
668
668
|
self._ensure_approval_column(connection, "risk_headline", "text")
|
|
669
669
|
self._ensure_approval_column(connection, "action_envelope_json", "text")
|
|
670
|
+
self._ensure_approval_column(connection, "decision_v2_json", "text")
|
|
670
671
|
self._ensure_approval_column(connection, "workspace", "text")
|
|
671
672
|
self._ensure_attachment_column(connection, "lease_id", "text not null default ''")
|
|
672
673
|
self._ensure_attachment_column(connection, "lease_expires_at", "text")
|
{plugin_scanner-2.0.100 → plugin_scanner-2.0.102}/src/codex_plugin_scanner/guard/store_approvals.py
RENAMED
|
@@ -34,8 +34,9 @@ def approval_schema_statement() -> str:
|
|
|
34
34
|
why_now text,
|
|
35
35
|
launch_summary text,
|
|
36
36
|
risk_headline text,
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
action_envelope_json text,
|
|
38
|
+
decision_v2_json text,
|
|
39
|
+
review_command text not null,
|
|
39
40
|
approval_url text not null,
|
|
40
41
|
status text not null,
|
|
41
42
|
resolution_action text,
|
|
@@ -69,7 +70,7 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
|
|
|
69
70
|
recommended_scope = ?, changed_fields_json = ?, source_scope = ?, config_path = ?, workspace = ?,
|
|
70
71
|
launch_target = ?, transport = ?, risk_summary = ?, risk_signals_json = ?,
|
|
71
72
|
artifact_label = ?, source_label = ?, trigger_summary = ?, why_now = ?, launch_summary = ?,
|
|
72
|
-
risk_headline = ?, action_envelope_json = ?,
|
|
73
|
+
risk_headline = ?, action_envelope_json = ?, decision_v2_json = ?,
|
|
73
74
|
review_command = ?, approval_url = ?, created_at = ?
|
|
74
75
|
where request_id = ?
|
|
75
76
|
""",
|
|
@@ -95,6 +96,7 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
|
|
|
95
96
|
request.launch_summary,
|
|
96
97
|
request.risk_headline,
|
|
97
98
|
json.dumps(request.action_envelope_json) if request.action_envelope_json is not None else None,
|
|
99
|
+
json.dumps(request.decision_v2_json) if request.decision_v2_json is not None else None,
|
|
98
100
|
review_command,
|
|
99
101
|
approval_url,
|
|
100
102
|
now,
|
|
@@ -109,10 +111,10 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
|
|
|
109
111
|
recommended_scope, changed_fields_json, source_scope, config_path, workspace,
|
|
110
112
|
launch_target, transport, risk_summary,
|
|
111
113
|
risk_signals_json, artifact_label, source_label, trigger_summary, why_now, launch_summary, risk_headline,
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
action_envelope_json, decision_v2_json, review_command,
|
|
115
|
+
approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
|
|
116
|
+
)
|
|
117
|
+
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
116
118
|
""",
|
|
117
119
|
(
|
|
118
120
|
request.request_id,
|
|
@@ -139,6 +141,7 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
|
|
|
139
141
|
request.launch_summary,
|
|
140
142
|
request.risk_headline,
|
|
141
143
|
json.dumps(request.action_envelope_json) if request.action_envelope_json is not None else None,
|
|
144
|
+
json.dumps(request.decision_v2_json) if request.decision_v2_json is not None else None,
|
|
142
145
|
request.review_command,
|
|
143
146
|
request.approval_url,
|
|
144
147
|
"pending",
|
|
@@ -186,7 +189,7 @@ def list_approval_requests(
|
|
|
186
189
|
select request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher, policy_action,
|
|
187
190
|
recommended_scope, changed_fields_json, source_scope, config_path, workspace, launch_target, transport,
|
|
188
191
|
risk_summary, risk_signals_json, artifact_label, source_label, trigger_summary, why_now,
|
|
189
|
-
launch_summary, risk_headline, action_envelope_json, review_command,
|
|
192
|
+
launch_summary, risk_headline, action_envelope_json, decision_v2_json, review_command,
|
|
190
193
|
approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
|
|
191
194
|
from approval_requests
|
|
192
195
|
{where_clause}
|
|
@@ -205,7 +208,7 @@ def get_approval_request(connection: sqlite3.Connection, request_id: str) -> dic
|
|
|
205
208
|
select request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher, policy_action,
|
|
206
209
|
recommended_scope, changed_fields_json, source_scope, config_path, workspace, launch_target, transport,
|
|
207
210
|
risk_summary, risk_signals_json, artifact_label, source_label, trigger_summary, why_now,
|
|
208
|
-
launch_summary, risk_headline, action_envelope_json, review_command,
|
|
211
|
+
launch_summary, risk_headline, action_envelope_json, decision_v2_json, review_command,
|
|
209
212
|
approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
|
|
210
213
|
from approval_requests
|
|
211
214
|
where request_id = ?
|
|
@@ -277,6 +280,7 @@ def _row_to_payload(row: sqlite3.Row) -> dict[str, object]:
|
|
|
277
280
|
"launch_summary": row["launch_summary"],
|
|
278
281
|
"risk_headline": row["risk_headline"],
|
|
279
282
|
"action_envelope_json": _optional_json_object(row["action_envelope_json"]),
|
|
283
|
+
"decision_v2_json": _optional_json_object(row["decision_v2_json"]),
|
|
280
284
|
"review_command": str(row["review_command"]),
|
|
281
285
|
"approval_url": str(row["approval_url"]),
|
|
282
286
|
"status": str(row["status"]),
|
|
@@ -90,6 +90,18 @@ class TestGuardApprovals:
|
|
|
90
90
|
"script_name": None,
|
|
91
91
|
"raw_payload_redacted": {"tool_name": "Bash"},
|
|
92
92
|
}
|
|
93
|
+
decision_v2_json = {
|
|
94
|
+
"action": "ask",
|
|
95
|
+
"reason": "require-reapproval",
|
|
96
|
+
"user_title": "Review workspace_skill",
|
|
97
|
+
"user_body": "HOL Guard needs approval before this action continues.",
|
|
98
|
+
"harness_message": "HOL Guard paused this action for approval.",
|
|
99
|
+
"dashboard_primary_detail": "Shell command can read a local secret file.",
|
|
100
|
+
"approval_scopes": ["artifact", "workspace"],
|
|
101
|
+
"retry_instruction": "Approve it in HOL Guard, then retry.",
|
|
102
|
+
"signals": [],
|
|
103
|
+
"confidence": "likely",
|
|
104
|
+
}
|
|
93
105
|
request = GuardApprovalRequest(
|
|
94
106
|
request_id="req-123",
|
|
95
107
|
harness="codex",
|
|
@@ -105,6 +117,7 @@ class TestGuardApprovals:
|
|
|
105
117
|
review_command="hol-guard approvals approve req-123",
|
|
106
118
|
approval_url="http://127.0.0.1:4455/approvals/req-123",
|
|
107
119
|
action_envelope_json=action_envelope_json,
|
|
120
|
+
decision_v2_json=decision_v2_json,
|
|
108
121
|
)
|
|
109
122
|
|
|
110
123
|
store.add_approval_request(request, "2026-04-11T00:00:00+00:00")
|
|
@@ -122,11 +135,13 @@ class TestGuardApprovals:
|
|
|
122
135
|
assert pending[0]["approval_url"] == "http://127.0.0.1:4455/approvals/req-123"
|
|
123
136
|
assert pending[0]["workspace"] == str(workspace_dir)
|
|
124
137
|
assert pending[0]["action_envelope_json"] == action_envelope_json
|
|
138
|
+
assert pending[0]["decision_v2_json"] == decision_v2_json
|
|
125
139
|
assert resolved is not None
|
|
126
140
|
assert resolved["status"] == "resolved"
|
|
127
141
|
assert resolved["resolution_action"] == "allow"
|
|
128
142
|
assert resolved["resolution_scope"] == "artifact"
|
|
129
143
|
assert resolved["action_envelope_json"] == action_envelope_json
|
|
144
|
+
assert resolved["decision_v2_json"] == decision_v2_json
|
|
130
145
|
|
|
131
146
|
def test_guard_store_loads_old_approval_rows_without_action_envelope(self, tmp_path):
|
|
132
147
|
guard_home = tmp_path / "guard-home"
|
|
@@ -225,8 +240,9 @@ class TestGuardApprovals:
|
|
|
225
240
|
assert request is not None
|
|
226
241
|
assert request["request_id"] == "req-old"
|
|
227
242
|
assert request["action_envelope_json"] is None
|
|
243
|
+
assert request["decision_v2_json"] is None
|
|
228
244
|
|
|
229
|
-
def
|
|
245
|
+
def test_guard_store_ignores_malformed_action_and_decision_json(self, tmp_path):
|
|
230
246
|
store = GuardStore(tmp_path / "guard-home")
|
|
231
247
|
connection = sqlite3.connect(store.path)
|
|
232
248
|
try:
|
|
@@ -236,10 +252,13 @@ class TestGuardApprovals:
|
|
|
236
252
|
request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher,
|
|
237
253
|
policy_action, recommended_scope, changed_fields_json, source_scope, config_path, workspace,
|
|
238
254
|
launch_target, transport, risk_summary, risk_signals_json, artifact_label, source_label,
|
|
239
|
-
trigger_summary, why_now, launch_summary, risk_headline, action_envelope_json,
|
|
255
|
+
trigger_summary, why_now, launch_summary, risk_headline, action_envelope_json, decision_v2_json,
|
|
256
|
+
review_command,
|
|
240
257
|
approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
|
|
241
258
|
)
|
|
242
|
-
values (
|
|
259
|
+
values (
|
|
260
|
+
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
|
261
|
+
)
|
|
243
262
|
""",
|
|
244
263
|
(
|
|
245
264
|
"req-bad-envelope",
|
|
@@ -266,6 +285,7 @@ class TestGuardApprovals:
|
|
|
266
285
|
None,
|
|
267
286
|
None,
|
|
268
287
|
"{not-json",
|
|
288
|
+
"{also-not-json",
|
|
269
289
|
"hol-guard approvals approve req-bad-envelope",
|
|
270
290
|
"http://127.0.0.1/pending",
|
|
271
291
|
"pending",
|
|
@@ -284,6 +304,7 @@ class TestGuardApprovals:
|
|
|
284
304
|
|
|
285
305
|
assert request is not None
|
|
286
306
|
assert request["action_envelope_json"] is None
|
|
307
|
+
assert request["decision_v2_json"] is None
|
|
287
308
|
|
|
288
309
|
def test_guard_surface_daemon_client_recovers_missing_auth_token(self, tmp_path, monkeypatch):
|
|
289
310
|
guard_home = tmp_path / "guard-home"
|
|
@@ -1960,6 +1981,11 @@ class TestGuardApprovals:
|
|
|
1960
1981
|
assert output["approval_center_url"].startswith("http://127.0.0.1:")
|
|
1961
1982
|
assert approvals[0]["harness"] == "codex"
|
|
1962
1983
|
assert approvals[0]["status"] == "pending"
|
|
1984
|
+
assert approvals[0]["decision_v2_json"]["action"] == "ask"
|
|
1985
|
+
assert (
|
|
1986
|
+
approvals[0]["decision_v2_json"]["harness_message"]
|
|
1987
|
+
== "HOL Guard needs a fresh approval because this action changed."
|
|
1988
|
+
)
|
|
1963
1989
|
|
|
1964
1990
|
def test_guard_approvals_cli_lists_and_resolves_requests(self, tmp_path, capsys):
|
|
1965
1991
|
home_dir = tmp_path / "home"
|
|
@@ -28,7 +28,7 @@ from codex_plugin_scanner.guard.config import GuardConfig, load_guard_config
|
|
|
28
28
|
from codex_plugin_scanner.guard.consumer import artifact_hash, evaluate_detection
|
|
29
29
|
from codex_plugin_scanner.guard.daemon import GuardDaemonServer
|
|
30
30
|
from codex_plugin_scanner.guard.models import GuardApprovalRequest, GuardArtifact, HarnessDetection, PolicyDecision
|
|
31
|
-
from codex_plugin_scanner.guard.policy import decide_action
|
|
31
|
+
from codex_plugin_scanner.guard.policy import decide_action, decide_action_with_v2
|
|
32
32
|
from codex_plugin_scanner.guard.proxy import RemoteGuardProxy, StdioGuardProxy
|
|
33
33
|
from codex_plugin_scanner.guard.receipts import build_receipt
|
|
34
34
|
from codex_plugin_scanner.guard.runtime import runner as guard_runner_module
|
|
@@ -2023,6 +2023,8 @@ clearer UX and an implementation plan with technical references.
|
|
|
2023
2023
|
|
|
2024
2024
|
assert evaluation["blocked"] is True
|
|
2025
2025
|
assert evaluation["artifacts"][0]["policy_action"] == "block"
|
|
2026
|
+
assert evaluation["artifacts"][0]["decision_v2_json"]["action"] == "block"
|
|
2027
|
+
assert evaluation["artifacts"][0]["decision_v2_json"]["harness_message"] == "HOL Guard blocked this action."
|
|
2026
2028
|
assert receipts[0]["capabilities_summary"] == "mcp server • stdio • node"
|
|
2027
2029
|
|
|
2028
2030
|
def test_guard_evaluate_detection_blocks_for_sandbox_required_override(self, tmp_path):
|
|
@@ -7132,6 +7134,30 @@ def test_runtime_artifact_native_reason_truncates_long_risk_summaries() -> None:
|
|
|
7132
7134
|
assert reason.endswith("...")
|
|
7133
7135
|
|
|
7134
7136
|
|
|
7137
|
+
def test_runtime_artifact_native_reason_prefers_decision_v2_harness_message() -> None:
|
|
7138
|
+
artifact = GuardArtifact(
|
|
7139
|
+
artifact_id="claude-code:project:tool-action:test",
|
|
7140
|
+
name="destructive shell command",
|
|
7141
|
+
harness="claude-code",
|
|
7142
|
+
artifact_type="tool_action_request",
|
|
7143
|
+
source_scope="project",
|
|
7144
|
+
config_path="/tmp/settings.local.json",
|
|
7145
|
+
metadata={},
|
|
7146
|
+
)
|
|
7147
|
+
|
|
7148
|
+
reason = guard_commands_module._runtime_artifact_native_reason(
|
|
7149
|
+
artifact,
|
|
7150
|
+
{
|
|
7151
|
+
"decision_v2_json": {
|
|
7152
|
+
"harness_message": "HOL Guard stopped this exact shell command before it touched secrets.",
|
|
7153
|
+
},
|
|
7154
|
+
"risk_summary": "Generic fallback summary.",
|
|
7155
|
+
},
|
|
7156
|
+
)
|
|
7157
|
+
|
|
7158
|
+
assert reason == "HOL Guard stopped this exact shell command before it touched secrets."
|
|
7159
|
+
|
|
7160
|
+
|
|
7135
7161
|
def test_native_approval_center_context_uses_harness_specific_retry_copy() -> None:
|
|
7136
7162
|
payload = {
|
|
7137
7163
|
"approval_center_url": "http://127.0.0.1:4455",
|
|
@@ -9491,6 +9517,27 @@ def test_guard_invalid_default_action_falls_back_to_reapproval(tmp_path):
|
|
|
9491
9517
|
assert action == "require-reapproval"
|
|
9492
9518
|
|
|
9493
9519
|
|
|
9520
|
+
def test_decide_action_with_v2_preserves_legacy_action_and_adds_decision(tmp_path):
|
|
9521
|
+
config = GuardConfig(
|
|
9522
|
+
guard_home=tmp_path / "guard-home",
|
|
9523
|
+
workspace=None,
|
|
9524
|
+
default_action="block",
|
|
9525
|
+
)
|
|
9526
|
+
|
|
9527
|
+
action, decision = decide_action_with_v2(
|
|
9528
|
+
configured_action=None,
|
|
9529
|
+
default_action=None,
|
|
9530
|
+
config=config,
|
|
9531
|
+
changed=False,
|
|
9532
|
+
reason="invalid-default-fallback",
|
|
9533
|
+
)
|
|
9534
|
+
|
|
9535
|
+
assert action == "block"
|
|
9536
|
+
assert decision.action == "block"
|
|
9537
|
+
assert decision.reason == "invalid-default-fallback"
|
|
9538
|
+
assert decision.harness_message == "HOL Guard blocked this action."
|
|
9539
|
+
|
|
9540
|
+
|
|
9494
9541
|
def test_guard_hook_invalid_policy_action_falls_back_to_reapproval(tmp_path, capsys, monkeypatch):
|
|
9495
9542
|
home_dir = tmp_path / "home"
|
|
9496
9543
|
workspace_dir = tmp_path / "workspace"
|