plugin-scanner 2.0.96__tar.gz → 2.0.97__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.96 → plugin_scanner-2.0.97}/PKG-INFO +1 -1
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/pyproject.toml +1 -1
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/pyproject.toml.bak +1 -1
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/approvals.py +9 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/commands.py +35 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/models.py +2 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/runtime/runner.py +63 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/store.py +1 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/store_approvals.py +35 -19
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/version.py +1 -1
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_approvals.py +181 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_runtime.py +4 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.clusterfuzzlite/Dockerfile +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.clusterfuzzlite/build.sh +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.clusterfuzzlite/project.yaml +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.clusterfuzzlite/requirements-atheris.txt +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.dockerignore +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/CODEOWNERS +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/dependabot.yml +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/workflows/ci.yml +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/workflows/codeql.yml +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/workflows/dependabot-uv-lock.yml +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/workflows/fuzz.yml +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/workflows/harness-smoke.yml +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/workflows/publish.yml +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.github/workflows/scorecard.yml +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.gitignore +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/.pre-commit-hooks.yaml +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/CONTRIBUTING.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/Dockerfile +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/LICENSE +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/README.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/SECURITY.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/index.html +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/package.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/pnpm-lock.yaml +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/public/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/public/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/public/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/public/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/public/favicon.ico +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/app.tsx +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/approval-center-layout.tsx +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/approval-center-primitives.tsx +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/approval-center-utils.ts +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/fleet-workspace.tsx +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/guard-api.test.ts +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/guard-api.ts +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/guard-demo.ts +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/guard-types.ts +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/main.tsx +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/receipts-workspace.tsx +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/runtime-overview.tsx +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/settings-workspace.tsx +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/styles.css +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/src/vite-env.d.ts +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/tsconfig.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/dashboard/vite.config.ts +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docker-requirements.txt +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docs/guard/approval-audit.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docs/guard/architecture.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docs/guard/get-started.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docs/guard/harness-support.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docs/guard/local-vs-cloud.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docs/guard/testing-matrix.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docs/trust/mcp-trust-draft.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docs/trust/plugin-trust-draft.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/docs/trust/skill-trust-local.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/fuzzers/manifest_fuzzer.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/requirements.txt +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/schemas/plugin-quality.v1.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/schemas/scan-result.v1.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/schemas/verify-result.v1.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/__init__.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/action_runner.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/argparse_utils.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/__init__.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/claude.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/gemini.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/manifest.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/opencode.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/security.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/cli.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/cli_ui.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/config.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/github_reporting.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/__init__.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/config.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/incident.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/launcher.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/protect.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/redaction.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/risk.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/shims.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/types.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/lint_fixes.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/marketplace_support.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/models.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/path_support.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/policy.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/quality_artifact.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/repo_detect.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/reporting.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/rules/__init__.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/rules/registry.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/rules/specs.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/scanner.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/submission.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/suppressions.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/trust_helpers.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/trust_models.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/trust_scoring.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/trust_specs.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/verification.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/__init__.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/conftest.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/__init__.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/bad-plugin/.mcp.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/bad-plugin/secrets.js +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/claude-plugin-good/README.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/code-quality-bad/evil.js +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/code-quality-bad/inject.js +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/gemini-extension-good/README.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/good-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/good-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/good-plugin/README.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/good-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/mcp-canary-server.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/mit-license/LICENSE +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/opencode-good/LICENSE +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/opencode-good/README.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/opencode-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/fixtures/with-marketplace/marketplace.json +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test-trust-scoring.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test-trust-specs.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_action_runner.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_best_practices.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_cisco_install_surfaces.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_cli.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_code_quality.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_config.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_coverage_remaining.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_ecosystems.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_edge_cases.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_final_coverage.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_bootstrap.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_capabilities.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_claude_adapter.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_cli.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_codex_e2e.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_codex_install.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_codex_proxy.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_config_paths.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_connect_flow.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_consumer_mode.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_copilot_adapter.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_copilot_proxy.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_daemon_manager.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_event_schema_v1.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_events.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_launch_env.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_opencode_proxy.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_product_flow.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_protect.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_render.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_risk.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_runtime_action_harnesses.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_runtime_actions.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_store_migrations.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_surface_server.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_guard_verdicts.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_hermes_adapter.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_integration.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_lint_fixes.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_live_cisco_smoke.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_manifest.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_marketplace.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_mcp_security.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_openclaw_adapter.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_operational_security.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_policy.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_quality_artifact.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_rule_registry.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_scanner.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_schema_contracts.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_security.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_security_ops.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_skill_security.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_submission.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_trust_scoring.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_trust_specs.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_verification.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/tests/test_versioning.py +0 -0
- {plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/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.97
|
|
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.97"
|
|
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.97"
|
|
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"
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import time
|
|
6
6
|
import uuid
|
|
7
|
+
from collections.abc import Mapping
|
|
7
8
|
from dataclasses import replace
|
|
8
9
|
from datetime import datetime, timezone
|
|
9
10
|
from pathlib import Path
|
|
@@ -86,6 +87,7 @@ def queue_blocked_approvals(
|
|
|
86
87
|
why_now=incident["why_now"],
|
|
87
88
|
launch_summary=incident["launch_summary"],
|
|
88
89
|
risk_headline=incident["risk_headline"],
|
|
90
|
+
action_envelope_json=_item_action_envelope_json(item),
|
|
89
91
|
)
|
|
90
92
|
persisted_request_id = store.add_approval_request(request, timestamp)
|
|
91
93
|
if persisted_request_id != request.request_id:
|
|
@@ -333,6 +335,13 @@ def _item_risk_signals(item: dict[str, object], artifact) -> tuple[str, ...]:
|
|
|
333
335
|
return artifact_risk_signals(artifact) if artifact is not None else ()
|
|
334
336
|
|
|
335
337
|
|
|
338
|
+
def _item_action_envelope_json(item: dict[str, object]) -> dict[str, object] | None:
|
|
339
|
+
value = item.get("action_envelope_json")
|
|
340
|
+
if not isinstance(value, Mapping):
|
|
341
|
+
return None
|
|
342
|
+
return {str(key): item_value for key, item_value in value.items() if isinstance(key, str)}
|
|
343
|
+
|
|
344
|
+
|
|
336
345
|
def _string_list(value: object) -> list[str]:
|
|
337
346
|
if not isinstance(value, list):
|
|
338
347
|
return []
|
{plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/cli/commands.py
RENAMED
|
@@ -80,6 +80,7 @@ from ..proxy import (
|
|
|
80
80
|
)
|
|
81
81
|
from ..receipts import build_receipt
|
|
82
82
|
from ..risk import artifact_risk_signals, artifact_risk_summary
|
|
83
|
+
from ..runtime.actions import GuardActionEnvelope, normalize_harness_payload
|
|
83
84
|
from ..runtime.runner import (
|
|
84
85
|
GuardSyncNotConfiguredError,
|
|
85
86
|
extract_prompt_requests,
|
|
@@ -1206,6 +1207,12 @@ def run_guard_command(
|
|
|
1206
1207
|
runtime_workspace = current_workspace
|
|
1207
1208
|
if args.harness == "copilot":
|
|
1208
1209
|
runtime_workspace = _resolve_copilot_workspace_root(runtime_workspace)
|
|
1210
|
+
action_envelope = _hook_action_envelope(
|
|
1211
|
+
harness=args.harness,
|
|
1212
|
+
payload=payload,
|
|
1213
|
+
home_dir=context.home_dir,
|
|
1214
|
+
workspace=runtime_workspace,
|
|
1215
|
+
)
|
|
1209
1216
|
copilot_hook_stage = _copilot_hook_stage(payload) if args.harness == "copilot" else None
|
|
1210
1217
|
copilot_runtime_tool_call = (
|
|
1211
1218
|
_copilot_runtime_tool_call(
|
|
@@ -1309,6 +1316,7 @@ def run_guard_command(
|
|
|
1309
1316
|
"launch_target": json.dumps(runtime_arguments, sort_keys=True)
|
|
1310
1317
|
if runtime_arguments is not None
|
|
1311
1318
|
else runtime_artifact.command,
|
|
1319
|
+
"action_envelope_json": _action_envelope_json(action_envelope),
|
|
1312
1320
|
}
|
|
1313
1321
|
]
|
|
1314
1322
|
}
|
|
@@ -1667,6 +1675,7 @@ def run_guard_command(
|
|
|
1667
1675
|
"source_scope": runtime_artifact.source_scope,
|
|
1668
1676
|
"config_path": runtime_artifact.config_path,
|
|
1669
1677
|
"launch_target": _runtime_request_summary(runtime_artifact),
|
|
1678
|
+
"action_envelope_json": _action_envelope_json(action_envelope),
|
|
1670
1679
|
}
|
|
1671
1680
|
]
|
|
1672
1681
|
}
|
|
@@ -3619,6 +3628,32 @@ def _load_hook_payload(event_file: str | None, *, input_text: str | None = None)
|
|
|
3619
3628
|
return _normalize_hook_payload(payload) if isinstance(payload, dict) else {}
|
|
3620
3629
|
|
|
3621
3630
|
|
|
3631
|
+
_ACTION_ENVELOPE_HARNESSES = frozenset({"codex", "claude-code", "opencode", "copilot", "gemini"})
|
|
3632
|
+
|
|
3633
|
+
|
|
3634
|
+
def _hook_action_envelope(
|
|
3635
|
+
*,
|
|
3636
|
+
harness: str,
|
|
3637
|
+
payload: dict[str, object],
|
|
3638
|
+
home_dir: Path,
|
|
3639
|
+
workspace: Path | None,
|
|
3640
|
+
) -> GuardActionEnvelope | None:
|
|
3641
|
+
canonical_harness = _canonical_harness_name(harness)
|
|
3642
|
+
if canonical_harness not in _ACTION_ENVELOPE_HARNESSES:
|
|
3643
|
+
return None
|
|
3644
|
+
return normalize_harness_payload(
|
|
3645
|
+
canonical_harness,
|
|
3646
|
+
_hook_event_name(payload) or "PreToolUse",
|
|
3647
|
+
payload,
|
|
3648
|
+
workspace=workspace,
|
|
3649
|
+
home_dir=home_dir,
|
|
3650
|
+
)
|
|
3651
|
+
|
|
3652
|
+
|
|
3653
|
+
def _action_envelope_json(envelope: GuardActionEnvelope | None) -> dict[str, object] | None:
|
|
3654
|
+
return envelope.to_dict() if envelope is not None else None
|
|
3655
|
+
|
|
3656
|
+
|
|
3622
3657
|
def _normalize_hook_payload(payload: dict[str, object]) -> dict[str, object]:
|
|
3623
3658
|
normalized = dict(payload)
|
|
3624
3659
|
for source_key, target_key in (
|
|
@@ -141,6 +141,7 @@ class GuardReceipt:
|
|
|
141
141
|
user_override: str | None = None
|
|
142
142
|
artifact_name: str | None = None
|
|
143
143
|
source_scope: str | None = None
|
|
144
|
+
action_envelope_json: dict[str, object] | None = None
|
|
144
145
|
|
|
145
146
|
def to_dict(self) -> dict[str, object]:
|
|
146
147
|
payload = asdict(self)
|
|
@@ -177,6 +178,7 @@ class GuardApprovalRequest:
|
|
|
177
178
|
why_now: str | None = None
|
|
178
179
|
launch_summary: str | None = None
|
|
179
180
|
risk_headline: str | None = None
|
|
181
|
+
action_envelope_json: dict[str, object] | None = None
|
|
180
182
|
|
|
181
183
|
def to_dict(self) -> dict[str, object]:
|
|
182
184
|
payload = asdict(self)
|
{plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/runtime/runner.py
RENAMED
|
@@ -12,6 +12,7 @@ import urllib.error
|
|
|
12
12
|
import urllib.parse
|
|
13
13
|
import urllib.request
|
|
14
14
|
from collections.abc import Callable
|
|
15
|
+
from contextlib import suppress
|
|
15
16
|
from datetime import datetime, timezone
|
|
16
17
|
from pathlib import Path
|
|
17
18
|
from typing import Any
|
|
@@ -24,6 +25,7 @@ from ..consumer import detect_harness, evaluate_detection
|
|
|
24
25
|
from ..models import GuardArtifact, HarnessDetection, PolicyDecision
|
|
25
26
|
from ..store import GuardStore
|
|
26
27
|
from ..types import PromptRequest, RemediationAction
|
|
28
|
+
from .actions import GuardActionEnvelope, redacted_workspace_label
|
|
27
29
|
|
|
28
30
|
_APPROVAL_METADATA_KEYS = (
|
|
29
31
|
"approval_center_url",
|
|
@@ -233,12 +235,18 @@ def guard_run(
|
|
|
233
235
|
if not evaluation["blocked"]:
|
|
234
236
|
evaluation = evaluate_detection(detection, store, config, default_action=default_action, persist=True)
|
|
235
237
|
|
|
238
|
+
action_envelope = _guard_run_action_envelope(harness, context, passthrough_args)
|
|
239
|
+
if evaluation["blocked"]:
|
|
240
|
+
evaluation = _evaluation_with_action_envelope(evaluation, action_envelope)
|
|
241
|
+
|
|
236
242
|
if not dry_run and interactive_resolver is not None and evaluation["blocked"]:
|
|
237
243
|
evaluation = interactive_resolver(detection, evaluation)
|
|
238
244
|
elif not dry_run and blocked_resolver is not None and evaluation["blocked"]:
|
|
239
245
|
pending_evaluation = blocked_resolver(detection, evaluation)
|
|
240
246
|
detection = _detection_with_prompt_artifacts(detect_harness(harness, context), context, passthrough_args)
|
|
241
247
|
reevaluated = evaluate_detection(detection, store, config, default_action=default_action, persist=True)
|
|
248
|
+
if reevaluated["blocked"]:
|
|
249
|
+
reevaluated = _evaluation_with_action_envelope(reevaluated, action_envelope)
|
|
242
250
|
for key in _APPROVAL_METADATA_KEYS:
|
|
243
251
|
if key in pending_evaluation:
|
|
244
252
|
reevaluated[key] = pending_evaluation[key]
|
|
@@ -274,6 +282,61 @@ def guard_run(
|
|
|
274
282
|
return evaluation
|
|
275
283
|
|
|
276
284
|
|
|
285
|
+
def _guard_run_action_envelope(
|
|
286
|
+
harness: str,
|
|
287
|
+
context: HarnessContext,
|
|
288
|
+
passthrough_args: list[str],
|
|
289
|
+
) -> GuardActionEnvelope:
|
|
290
|
+
workspace = context.workspace_dir
|
|
291
|
+
workspace_hash = None
|
|
292
|
+
if workspace is not None:
|
|
293
|
+
workspace_path = workspace.expanduser()
|
|
294
|
+
with suppress(OSError):
|
|
295
|
+
workspace_path = workspace_path.resolve()
|
|
296
|
+
workspace_hash = hashlib.sha256(str(workspace_path).encode("utf-8")).hexdigest()
|
|
297
|
+
return GuardActionEnvelope(
|
|
298
|
+
schema_version=1,
|
|
299
|
+
action_id="",
|
|
300
|
+
harness=harness,
|
|
301
|
+
event_name="HarnessStart",
|
|
302
|
+
action_type="harness_start",
|
|
303
|
+
workspace=redacted_workspace_label(workspace, home_dir=context.home_dir),
|
|
304
|
+
workspace_hash=workspace_hash,
|
|
305
|
+
tool_name=None,
|
|
306
|
+
command=None,
|
|
307
|
+
prompt_excerpt=None,
|
|
308
|
+
target_paths=(),
|
|
309
|
+
network_hosts=(),
|
|
310
|
+
mcp_server=None,
|
|
311
|
+
mcp_tool=None,
|
|
312
|
+
package_manager=None,
|
|
313
|
+
package_name=None,
|
|
314
|
+
script_name=None,
|
|
315
|
+
raw_payload_redacted={"passthrough_arg_count": len(passthrough_args)},
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def _evaluation_with_action_envelope(
|
|
320
|
+
evaluation: dict[str, Any],
|
|
321
|
+
action_envelope: GuardActionEnvelope,
|
|
322
|
+
) -> dict[str, Any]:
|
|
323
|
+
artifacts = evaluation.get("artifacts")
|
|
324
|
+
if not isinstance(artifacts, list):
|
|
325
|
+
return evaluation
|
|
326
|
+
action_payload = action_envelope.to_dict()
|
|
327
|
+
normalized_artifacts: list[object] = []
|
|
328
|
+
changed = False
|
|
329
|
+
for item in artifacts:
|
|
330
|
+
if isinstance(item, dict) and "action_envelope_json" not in item:
|
|
331
|
+
normalized_artifacts.append({**item, "action_envelope_json": action_payload})
|
|
332
|
+
changed = True
|
|
333
|
+
else:
|
|
334
|
+
normalized_artifacts.append(item)
|
|
335
|
+
if not changed:
|
|
336
|
+
return evaluation
|
|
337
|
+
return {**evaluation, "artifacts": normalized_artifacts}
|
|
338
|
+
|
|
339
|
+
|
|
277
340
|
def _guard_run_config_paths(
|
|
278
341
|
*,
|
|
279
342
|
detection: HarnessDetection,
|
|
@@ -666,6 +666,7 @@ class GuardStore:
|
|
|
666
666
|
self._ensure_approval_column(connection, "why_now", "text")
|
|
667
667
|
self._ensure_approval_column(connection, "launch_summary", "text")
|
|
668
668
|
self._ensure_approval_column(connection, "risk_headline", "text")
|
|
669
|
+
self._ensure_approval_column(connection, "action_envelope_json", "text")
|
|
669
670
|
self._ensure_approval_column(connection, "workspace", "text")
|
|
670
671
|
self._ensure_attachment_column(connection, "lease_id", "text not null default ''")
|
|
671
672
|
self._ensure_attachment_column(connection, "lease_expires_at", "text")
|
{plugin_scanner-2.0.96 → plugin_scanner-2.0.97}/src/codex_plugin_scanner/guard/store_approvals.py
RENAMED
|
@@ -30,12 +30,13 @@ def approval_schema_statement() -> str:
|
|
|
30
30
|
risk_signals_json text not null default '[]',
|
|
31
31
|
artifact_label text,
|
|
32
32
|
source_label text,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
trigger_summary text,
|
|
34
|
+
why_now text,
|
|
35
|
+
launch_summary text,
|
|
36
|
+
risk_headline text,
|
|
37
|
+
action_envelope_json text,
|
|
38
|
+
review_command text not null,
|
|
39
|
+
approval_url text not null,
|
|
39
40
|
status text not null,
|
|
40
41
|
resolution_action text,
|
|
41
42
|
resolution_scope text,
|
|
@@ -68,7 +69,7 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
|
|
|
68
69
|
recommended_scope = ?, changed_fields_json = ?, source_scope = ?, config_path = ?, workspace = ?,
|
|
69
70
|
launch_target = ?, transport = ?, risk_summary = ?, risk_signals_json = ?,
|
|
70
71
|
artifact_label = ?, source_label = ?, trigger_summary = ?, why_now = ?, launch_summary = ?,
|
|
71
|
-
risk_headline = ?,
|
|
72
|
+
risk_headline = ?, action_envelope_json = ?,
|
|
72
73
|
review_command = ?, approval_url = ?, created_at = ?
|
|
73
74
|
where request_id = ?
|
|
74
75
|
""",
|
|
@@ -93,6 +94,7 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
|
|
|
93
94
|
request.why_now,
|
|
94
95
|
request.launch_summary,
|
|
95
96
|
request.risk_headline,
|
|
97
|
+
json.dumps(request.action_envelope_json) if request.action_envelope_json is not None else None,
|
|
96
98
|
review_command,
|
|
97
99
|
approval_url,
|
|
98
100
|
now,
|
|
@@ -105,12 +107,12 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
|
|
|
105
107
|
insert into approval_requests (
|
|
106
108
|
request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher, policy_action,
|
|
107
109
|
recommended_scope, changed_fields_json, source_scope, config_path, workspace,
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
110
|
+
launch_target, transport, risk_summary,
|
|
111
|
+
risk_signals_json, artifact_label, source_label, trigger_summary, why_now, launch_summary, risk_headline,
|
|
112
|
+
action_envelope_json, review_command,
|
|
113
|
+
approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
|
|
114
|
+
)
|
|
115
|
+
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
114
116
|
""",
|
|
115
117
|
(
|
|
116
118
|
request.request_id,
|
|
@@ -136,6 +138,7 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
|
|
|
136
138
|
request.why_now,
|
|
137
139
|
request.launch_summary,
|
|
138
140
|
request.risk_headline,
|
|
141
|
+
json.dumps(request.action_envelope_json) if request.action_envelope_json is not None else None,
|
|
139
142
|
request.review_command,
|
|
140
143
|
request.approval_url,
|
|
141
144
|
"pending",
|
|
@@ -182,9 +185,9 @@ def list_approval_requests(
|
|
|
182
185
|
query = f"""
|
|
183
186
|
select request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher, policy_action,
|
|
184
187
|
recommended_scope, changed_fields_json, source_scope, config_path, workspace, launch_target, transport,
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
+
risk_summary, risk_signals_json, artifact_label, source_label, trigger_summary, why_now,
|
|
189
|
+
launch_summary, risk_headline, action_envelope_json, review_command,
|
|
190
|
+
approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
|
|
188
191
|
from approval_requests
|
|
189
192
|
{where_clause}
|
|
190
193
|
order by created_at desc
|
|
@@ -201,9 +204,9 @@ def get_approval_request(connection: sqlite3.Connection, request_id: str) -> dic
|
|
|
201
204
|
"""
|
|
202
205
|
select request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher, policy_action,
|
|
203
206
|
recommended_scope, changed_fields_json, source_scope, config_path, workspace, launch_target, transport,
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
+
risk_summary, risk_signals_json, artifact_label, source_label, trigger_summary, why_now,
|
|
208
|
+
launch_summary, risk_headline, action_envelope_json, review_command,
|
|
209
|
+
approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
|
|
207
210
|
from approval_requests
|
|
208
211
|
where request_id = ?
|
|
209
212
|
""",
|
|
@@ -273,6 +276,7 @@ def _row_to_payload(row: sqlite3.Row) -> dict[str, object]:
|
|
|
273
276
|
"why_now": row["why_now"],
|
|
274
277
|
"launch_summary": row["launch_summary"],
|
|
275
278
|
"risk_headline": row["risk_headline"],
|
|
279
|
+
"action_envelope_json": _optional_json_object(row["action_envelope_json"]),
|
|
276
280
|
"review_command": str(row["review_command"]),
|
|
277
281
|
"approval_url": str(row["approval_url"]),
|
|
278
282
|
"status": str(row["status"]),
|
|
@@ -282,3 +286,15 @@ def _row_to_payload(row: sqlite3.Row) -> dict[str, object]:
|
|
|
282
286
|
"created_at": str(row["created_at"]),
|
|
283
287
|
"resolved_at": row["resolved_at"],
|
|
284
288
|
}
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def _optional_json_object(value: object) -> dict[str, object] | None:
|
|
292
|
+
if value is None:
|
|
293
|
+
return None
|
|
294
|
+
try:
|
|
295
|
+
parsed = json.loads(str(value))
|
|
296
|
+
except (json.JSONDecodeError, TypeError, ValueError):
|
|
297
|
+
return None
|
|
298
|
+
if isinstance(parsed, dict):
|
|
299
|
+
return {str(key): item for key, item in parsed.items() if isinstance(key, str)}
|
|
300
|
+
return None
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
|
+
import sqlite3
|
|
6
7
|
import urllib.error
|
|
7
8
|
import urllib.parse
|
|
8
9
|
import urllib.request
|
|
@@ -69,6 +70,26 @@ class TestGuardApprovals:
|
|
|
69
70
|
def test_guard_store_persists_and_resolves_approval_requests(self, tmp_path):
|
|
70
71
|
store = GuardStore(tmp_path / "guard-home")
|
|
71
72
|
workspace_dir = tmp_path / "workspace"
|
|
73
|
+
action_envelope_json = {
|
|
74
|
+
"schema_version": 1,
|
|
75
|
+
"action_id": "action-123",
|
|
76
|
+
"harness": "codex",
|
|
77
|
+
"event_name": "PreToolUse",
|
|
78
|
+
"action_type": "shell_command",
|
|
79
|
+
"workspace": "~/workspace",
|
|
80
|
+
"workspace_hash": "workspace-hash",
|
|
81
|
+
"tool_name": "Bash",
|
|
82
|
+
"command": "cat ~/.npmrc",
|
|
83
|
+
"prompt_excerpt": None,
|
|
84
|
+
"target_paths": ["~/.npmrc"],
|
|
85
|
+
"network_hosts": [],
|
|
86
|
+
"mcp_server": None,
|
|
87
|
+
"mcp_tool": None,
|
|
88
|
+
"package_manager": None,
|
|
89
|
+
"package_name": None,
|
|
90
|
+
"script_name": None,
|
|
91
|
+
"raw_payload_redacted": {"tool_name": "Bash"},
|
|
92
|
+
}
|
|
72
93
|
request = GuardApprovalRequest(
|
|
73
94
|
request_id="req-123",
|
|
74
95
|
harness="codex",
|
|
@@ -83,6 +104,7 @@ class TestGuardApprovals:
|
|
|
83
104
|
workspace=str(workspace_dir),
|
|
84
105
|
review_command="hol-guard approvals approve req-123",
|
|
85
106
|
approval_url="http://127.0.0.1:4455/approvals/req-123",
|
|
107
|
+
action_envelope_json=action_envelope_json,
|
|
86
108
|
)
|
|
87
109
|
|
|
88
110
|
store.add_approval_request(request, "2026-04-11T00:00:00+00:00")
|
|
@@ -99,10 +121,169 @@ class TestGuardApprovals:
|
|
|
99
121
|
assert pending[0]["status"] == "pending"
|
|
100
122
|
assert pending[0]["approval_url"] == "http://127.0.0.1:4455/approvals/req-123"
|
|
101
123
|
assert pending[0]["workspace"] == str(workspace_dir)
|
|
124
|
+
assert pending[0]["action_envelope_json"] == action_envelope_json
|
|
102
125
|
assert resolved is not None
|
|
103
126
|
assert resolved["status"] == "resolved"
|
|
104
127
|
assert resolved["resolution_action"] == "allow"
|
|
105
128
|
assert resolved["resolution_scope"] == "artifact"
|
|
129
|
+
assert resolved["action_envelope_json"] == action_envelope_json
|
|
130
|
+
|
|
131
|
+
def test_guard_store_loads_old_approval_rows_without_action_envelope(self, tmp_path):
|
|
132
|
+
guard_home = tmp_path / "guard-home"
|
|
133
|
+
guard_home.mkdir(parents=True, exist_ok=True)
|
|
134
|
+
connection = sqlite3.connect(guard_home / "guard.db")
|
|
135
|
+
try:
|
|
136
|
+
connection.execute(
|
|
137
|
+
"""
|
|
138
|
+
create table approval_requests (
|
|
139
|
+
request_id text primary key,
|
|
140
|
+
harness text not null,
|
|
141
|
+
artifact_id text not null,
|
|
142
|
+
artifact_name text not null,
|
|
143
|
+
artifact_type text not null,
|
|
144
|
+
artifact_hash text not null,
|
|
145
|
+
publisher text,
|
|
146
|
+
policy_action text not null,
|
|
147
|
+
recommended_scope text not null,
|
|
148
|
+
changed_fields_json text not null,
|
|
149
|
+
source_scope text not null,
|
|
150
|
+
config_path text not null,
|
|
151
|
+
workspace text,
|
|
152
|
+
launch_target text,
|
|
153
|
+
transport text,
|
|
154
|
+
risk_summary text,
|
|
155
|
+
risk_signals_json text not null default '[]',
|
|
156
|
+
artifact_label text,
|
|
157
|
+
source_label text,
|
|
158
|
+
trigger_summary text,
|
|
159
|
+
why_now text,
|
|
160
|
+
launch_summary text,
|
|
161
|
+
risk_headline text,
|
|
162
|
+
review_command text not null,
|
|
163
|
+
approval_url text not null,
|
|
164
|
+
status text not null,
|
|
165
|
+
resolution_action text,
|
|
166
|
+
resolution_scope text,
|
|
167
|
+
reason text,
|
|
168
|
+
created_at text not null,
|
|
169
|
+
resolved_at text
|
|
170
|
+
)
|
|
171
|
+
"""
|
|
172
|
+
)
|
|
173
|
+
connection.execute(
|
|
174
|
+
"""
|
|
175
|
+
insert into approval_requests (
|
|
176
|
+
request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher,
|
|
177
|
+
policy_action, recommended_scope, changed_fields_json, source_scope, config_path, workspace,
|
|
178
|
+
launch_target, transport, risk_summary, risk_signals_json, artifact_label, source_label,
|
|
179
|
+
trigger_summary, why_now, launch_summary, risk_headline, review_command, approval_url, status,
|
|
180
|
+
resolution_action, resolution_scope, reason, created_at, resolved_at
|
|
181
|
+
)
|
|
182
|
+
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
183
|
+
""",
|
|
184
|
+
(
|
|
185
|
+
"req-old",
|
|
186
|
+
"codex",
|
|
187
|
+
"codex:project:workspace_skill",
|
|
188
|
+
"workspace_skill",
|
|
189
|
+
"artifact",
|
|
190
|
+
"hash-old",
|
|
191
|
+
None,
|
|
192
|
+
"require-reapproval",
|
|
193
|
+
"artifact",
|
|
194
|
+
json.dumps(["args"]),
|
|
195
|
+
"project",
|
|
196
|
+
str(tmp_path / "workspace" / ".codex" / "config.toml"),
|
|
197
|
+
None,
|
|
198
|
+
None,
|
|
199
|
+
None,
|
|
200
|
+
None,
|
|
201
|
+
"[]",
|
|
202
|
+
None,
|
|
203
|
+
None,
|
|
204
|
+
None,
|
|
205
|
+
None,
|
|
206
|
+
None,
|
|
207
|
+
None,
|
|
208
|
+
"hol-guard approvals approve req-old",
|
|
209
|
+
"http://127.0.0.1/pending",
|
|
210
|
+
"pending",
|
|
211
|
+
None,
|
|
212
|
+
None,
|
|
213
|
+
None,
|
|
214
|
+
"2026-04-11T00:00:00+00:00",
|
|
215
|
+
None,
|
|
216
|
+
),
|
|
217
|
+
)
|
|
218
|
+
connection.commit()
|
|
219
|
+
finally:
|
|
220
|
+
connection.close()
|
|
221
|
+
|
|
222
|
+
store = GuardStore(guard_home)
|
|
223
|
+
request = store.get_approval_request("req-old")
|
|
224
|
+
|
|
225
|
+
assert request is not None
|
|
226
|
+
assert request["request_id"] == "req-old"
|
|
227
|
+
assert request["action_envelope_json"] is None
|
|
228
|
+
|
|
229
|
+
def test_guard_store_ignores_malformed_action_envelope_json(self, tmp_path):
|
|
230
|
+
store = GuardStore(tmp_path / "guard-home")
|
|
231
|
+
connection = sqlite3.connect(store.path)
|
|
232
|
+
try:
|
|
233
|
+
connection.execute(
|
|
234
|
+
"""
|
|
235
|
+
insert into approval_requests (
|
|
236
|
+
request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher,
|
|
237
|
+
policy_action, recommended_scope, changed_fields_json, source_scope, config_path, workspace,
|
|
238
|
+
launch_target, transport, risk_summary, risk_signals_json, artifact_label, source_label,
|
|
239
|
+
trigger_summary, why_now, launch_summary, risk_headline, action_envelope_json, review_command,
|
|
240
|
+
approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
|
|
241
|
+
)
|
|
242
|
+
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
243
|
+
""",
|
|
244
|
+
(
|
|
245
|
+
"req-bad-envelope",
|
|
246
|
+
"codex",
|
|
247
|
+
"codex:project:workspace_skill",
|
|
248
|
+
"workspace_skill",
|
|
249
|
+
"artifact",
|
|
250
|
+
"hash-bad-envelope",
|
|
251
|
+
None,
|
|
252
|
+
"require-reapproval",
|
|
253
|
+
"artifact",
|
|
254
|
+
json.dumps(["args"]),
|
|
255
|
+
"project",
|
|
256
|
+
str(tmp_path / "workspace" / ".codex" / "config.toml"),
|
|
257
|
+
None,
|
|
258
|
+
None,
|
|
259
|
+
None,
|
|
260
|
+
None,
|
|
261
|
+
"[]",
|
|
262
|
+
None,
|
|
263
|
+
None,
|
|
264
|
+
None,
|
|
265
|
+
None,
|
|
266
|
+
None,
|
|
267
|
+
None,
|
|
268
|
+
"{not-json",
|
|
269
|
+
"hol-guard approvals approve req-bad-envelope",
|
|
270
|
+
"http://127.0.0.1/pending",
|
|
271
|
+
"pending",
|
|
272
|
+
None,
|
|
273
|
+
None,
|
|
274
|
+
None,
|
|
275
|
+
"2026-04-11T00:00:00+00:00",
|
|
276
|
+
None,
|
|
277
|
+
),
|
|
278
|
+
)
|
|
279
|
+
connection.commit()
|
|
280
|
+
finally:
|
|
281
|
+
connection.close()
|
|
282
|
+
|
|
283
|
+
request = store.get_approval_request("req-bad-envelope")
|
|
284
|
+
|
|
285
|
+
assert request is not None
|
|
286
|
+
assert request["action_envelope_json"] is None
|
|
106
287
|
|
|
107
288
|
def test_guard_surface_daemon_client_recovers_missing_auth_token(self, tmp_path, monkeypatch):
|
|
108
289
|
guard_home = tmp_path / "guard-home"
|
|
@@ -492,6 +492,8 @@ clearer UX and an implementation plan with technical references.
|
|
|
492
492
|
assert output["artifact_type"] == "prompt_request"
|
|
493
493
|
assert "read .authrc" in output["launch_summary"]
|
|
494
494
|
assert approval_requests[0]["launch_target"] == "Codex prompt for `.authrc`: read .authrc"
|
|
495
|
+
assert approval_requests[0]["action_envelope_json"]["action_type"] == "prompt"
|
|
496
|
+
assert approval_requests[0]["action_envelope_json"]["prompt_excerpt"] == "read .authrc"
|
|
495
497
|
|
|
496
498
|
def test_codex_prompt_display_sanitizes_common_home_paths(self) -> None:
|
|
497
499
|
display = guard_commands_module._codex_prompt_display_text(
|
|
@@ -9418,6 +9420,8 @@ def test_guard_headless_blocked_run_persists_receipts_and_diffs(tmp_path, monkey
|
|
|
9418
9420
|
latest_receipt = store.get_latest_receipt("claude-code", baseline.artifact_id)
|
|
9419
9421
|
|
|
9420
9422
|
assert result["blocked"] is True
|
|
9423
|
+
assert result["artifacts"][0]["action_envelope_json"]["action_type"] == "harness_start"
|
|
9424
|
+
assert result["artifacts"][0]["action_envelope_json"]["harness"] == "claude-code"
|
|
9421
9425
|
assert latest_diff is not None
|
|
9422
9426
|
assert latest_diff["current_hash"] == artifact_hash(changed)
|
|
9423
9427
|
assert latest_receipt is not None
|
|
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
|