plugin-scanner 2.0.79__tar.gz → 2.0.81__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.79 → plugin_scanner-2.0.81}/PKG-INFO +1 -1
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/src/approval-center-primitives.tsx +1 -1
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/src/receipts-workspace.tsx +34 -29
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/pyproject.toml +1 -1
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/pyproject.toml.bak +1 -1
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/cli/commands.py +375 -1
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +3 -3
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/version.py +1 -1
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_runtime.py +988 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.clusterfuzzlite/Dockerfile +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.clusterfuzzlite/build.sh +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.clusterfuzzlite/project.yaml +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.clusterfuzzlite/requirements-atheris.txt +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.dockerignore +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.github/CODEOWNERS +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.github/dependabot.yml +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.github/workflows/ci.yml +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.github/workflows/codeql.yml +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.github/workflows/dependabot-uv-lock.yml +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.github/workflows/fuzz.yml +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.github/workflows/harness-smoke.yml +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.github/workflows/publish.yml +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.github/workflows/scorecard.yml +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.gitignore +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/.pre-commit-hooks.yaml +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/CONTRIBUTING.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/Dockerfile +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/LICENSE +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/README.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/SECURITY.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/index.html +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/package.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/pnpm-lock.yaml +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/public/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/public/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/public/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/public/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/public/favicon.ico +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/src/app.tsx +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/src/approval-center-layout.tsx +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/src/approval-center-utils.ts +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/src/fleet-workspace.tsx +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/src/guard-api.ts +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/src/guard-demo.ts +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/src/guard-types.ts +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/src/main.tsx +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/src/runtime-overview.tsx +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/src/settings-workspace.tsx +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/src/styles.css +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/src/vite-env.d.ts +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/tsconfig.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/vite.config.ts +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/docker-requirements.txt +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/docs/guard/approval-audit.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/docs/guard/architecture.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/docs/guard/get-started.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/docs/guard/harness-support.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/docs/guard/local-vs-cloud.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/docs/guard/testing-matrix.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/docs/trust/mcp-trust-draft.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/docs/trust/plugin-trust-draft.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/docs/trust/skill-trust-local.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/fuzzers/manifest_fuzzer.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/requirements.txt +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/schemas/plugin-quality.v1.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/schemas/scan-result.v1.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/schemas/verify-result.v1.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/__init__.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/action_runner.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/argparse_utils.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/checks/__init__.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/checks/claude.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/checks/gemini.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/checks/manifest.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/checks/opencode.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/checks/security.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/cli.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/cli_ui.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/config.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/github_reporting.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/__init__.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/approvals.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/config.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/incident.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/launcher.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/models.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/protect.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/redaction.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/risk.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/shims.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/store.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/types.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/lint_fixes.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/marketplace_support.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/models.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/path_support.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/policy.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/quality_artifact.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/repo_detect.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/reporting.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/rules/__init__.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/rules/registry.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/rules/specs.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/scanner.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/submission.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/suppressions.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/trust_helpers.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/trust_models.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/trust_scoring.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/trust_specs.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/verification.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/__init__.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/conftest.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/__init__.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/bad-plugin/.mcp.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/bad-plugin/secrets.js +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/claude-plugin-good/README.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/code-quality-bad/evil.js +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/code-quality-bad/inject.js +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/gemini-extension-good/README.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/good-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/good-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/good-plugin/README.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/good-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/mcp-canary-server.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/mit-license/LICENSE +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/opencode-good/LICENSE +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/opencode-good/README.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/opencode-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/fixtures/with-marketplace/marketplace.json +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test-trust-scoring.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test-trust-specs.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_action_runner.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_best_practices.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_cisco_install_surfaces.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_cli.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_code_quality.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_config.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_coverage_remaining.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_ecosystems.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_edge_cases.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_final_coverage.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_approvals.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_bootstrap.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_capabilities.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_claude_adapter.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_cli.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_codex_e2e.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_codex_install.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_codex_proxy.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_config_paths.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_connect_flow.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_consumer_mode.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_copilot_adapter.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_copilot_proxy.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_daemon_manager.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_event_schema_v1.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_events.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_launch_env.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_opencode_proxy.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_product_flow.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_protect.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_render.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_risk.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_store_migrations.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_surface_server.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_guard_verdicts.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_hermes_adapter.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_integration.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_lint_fixes.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_live_cisco_smoke.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_manifest.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_marketplace.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_mcp_security.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_operational_security.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_policy.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_quality_artifact.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_rule_registry.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_scanner.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_schema_contracts.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_security.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_security_ops.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_skill_security.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_submission.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_trust_scoring.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_trust_specs.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_verification.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/tests/test_versioning.py +0 -0
- {plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/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.81
|
|
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
|
{plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/dashboard/src/approval-center-primitives.tsx
RENAMED
|
@@ -402,7 +402,7 @@ function SidebarLink(props: {
|
|
|
402
402
|
aria-current={props.active ? "page" : undefined}
|
|
403
403
|
className={`flex min-h-10 items-center gap-2.5 rounded-lg px-3 py-2 text-sm font-medium no-underline transition-colors duration-150 ${
|
|
404
404
|
props.active
|
|
405
|
-
? "bg-brand-blue/
|
|
405
|
+
? "bg-brand-blue/[0.05] font-semibold text-brand-dark"
|
|
406
406
|
: "text-slate-600 hover:bg-slate-200/50 hover:text-slate-900"
|
|
407
407
|
}`}
|
|
408
408
|
>
|
|
@@ -19,14 +19,32 @@ type ReceiptsState =
|
|
|
19
19
|
| { kind: "ready"; items: GuardReceipt[] };
|
|
20
20
|
|
|
21
21
|
const receiptPageSize = 8;
|
|
22
|
-
const EMPTY_RECEIPTS: GuardReceipt[] = [];
|
|
23
22
|
|
|
24
23
|
export function ReceiptsWorkspace(props: { receipts: ReceiptsState }) {
|
|
24
|
+
if (props.receipts.kind === "loading") {
|
|
25
|
+
return (
|
|
26
|
+
<div className="space-y-4">
|
|
27
|
+
<div className="guard-skeleton h-8 w-64" />
|
|
28
|
+
<div className="guard-skeleton h-32 w-full" />
|
|
29
|
+
</div>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
if (props.receipts.kind === "error") {
|
|
33
|
+
return (
|
|
34
|
+
<Surface tone="danger">
|
|
35
|
+
<p className="text-sm text-brand-purple">{props.receipts.message}</p>
|
|
36
|
+
</Surface>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
return <ReadyReceiptsWorkspace receiptItems={props.receipts.items} />;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function ReadyReceiptsWorkspace(props: { receiptItems: GuardReceipt[] }) {
|
|
25
43
|
const [searchTerm, setSearchTerm] = useState("");
|
|
26
44
|
const [harnessFilter, setHarnessFilter] = useState("all");
|
|
27
45
|
const [decisionFilter, setDecisionFilter] = useState("all");
|
|
28
46
|
const [page, setPage] = useState(1);
|
|
29
|
-
const receiptCount = props.
|
|
47
|
+
const receiptCount = props.receiptItems.length;
|
|
30
48
|
|
|
31
49
|
const handleSearchChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
|
|
32
50
|
setSearchTerm(event.target.value);
|
|
@@ -48,7 +66,7 @@ export function ReceiptsWorkspace(props: { receipts: ReceiptsState }) {
|
|
|
48
66
|
setPage(1);
|
|
49
67
|
}, [decisionFilter, harnessFilter, searchTerm, receiptCount]);
|
|
50
68
|
|
|
51
|
-
const receiptItems = props.
|
|
69
|
+
const receiptItems = props.receiptItems;
|
|
52
70
|
|
|
53
71
|
const harnesses = useMemo(
|
|
54
72
|
() => Array.from(new Set(receiptItems.map((receipt) => receipt.harness))).sort(),
|
|
@@ -94,21 +112,7 @@ export function ReceiptsWorkspace(props: { receipts: ReceiptsState }) {
|
|
|
94
112
|
setPage((value) => Math.min(totalPages, value + 1));
|
|
95
113
|
}, [totalPages]);
|
|
96
114
|
|
|
97
|
-
|
|
98
|
-
return (
|
|
99
|
-
<div className="space-y-4">
|
|
100
|
-
<div className="guard-skeleton h-8 w-64" />
|
|
101
|
-
<div className="guard-skeleton h-32 w-full" />
|
|
102
|
-
</div>
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
if (props.receipts.kind === "error") {
|
|
106
|
-
return (
|
|
107
|
-
<Surface tone="danger">
|
|
108
|
-
<p className="text-sm text-brand-purple">{props.receipts.message}</p>
|
|
109
|
-
</Surface>
|
|
110
|
-
);
|
|
111
|
-
}
|
|
115
|
+
|
|
112
116
|
if (receiptItems.length === 0) {
|
|
113
117
|
return (
|
|
114
118
|
<EmptyState
|
|
@@ -123,7 +127,6 @@ export function ReceiptsWorkspace(props: { receipts: ReceiptsState }) {
|
|
|
123
127
|
<section className="guard-surface-in rounded-[2rem] border border-brand-blue/15 bg-[radial-gradient(circle_at_top_left,rgba(85,153,254,0.12),transparent_32%),linear-gradient(135deg,#ffffff_0%,#ffffff_62%,rgba(181,108,255,0.08)_100%)] p-5 shadow-[0_20px_60px_rgba(63,65,116,0.08)] sm:p-6 lg:p-7">
|
|
124
128
|
<div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
|
|
125
129
|
<div className="space-y-1">
|
|
126
|
-
<SectionLabel>History</SectionLabel>
|
|
127
130
|
<h1 className="mt-2 text-3xl font-semibold tracking-[-0.02em] text-brand-dark">
|
|
128
131
|
History
|
|
129
132
|
</h1>
|
|
@@ -132,7 +135,7 @@ export function ReceiptsWorkspace(props: { receipts: ReceiptsState }) {
|
|
|
132
135
|
</p>
|
|
133
136
|
</div>
|
|
134
137
|
<div className="flex flex-wrap gap-2">
|
|
135
|
-
<Badge tone="info">{props.
|
|
138
|
+
<Badge tone="info">{props.receiptItems.length} saved</Badge>
|
|
136
139
|
<Tag tone="slate">{filteredReceipts.length} shown</Tag>
|
|
137
140
|
</div>
|
|
138
141
|
</div>
|
|
@@ -140,7 +143,7 @@ export function ReceiptsWorkspace(props: { receipts: ReceiptsState }) {
|
|
|
140
143
|
|
|
141
144
|
<section className="rounded-[1.75rem] border border-slate-200/70 bg-white/80 p-5 shadow-sm sm:p-6">
|
|
142
145
|
<SectionLabel>Find history</SectionLabel>
|
|
143
|
-
<div className="mt-3
|
|
146
|
+
<div className="mt-3 grid gap-3 lg:grid-cols-[minmax(0,1fr)_180px]">
|
|
144
147
|
<ListControls
|
|
145
148
|
searchLabel="Search history"
|
|
146
149
|
searchValue={searchTerm}
|
|
@@ -152,7 +155,7 @@ export function ReceiptsWorkspace(props: { receipts: ReceiptsState }) {
|
|
|
152
155
|
onSearchChange={handleSearchChange}
|
|
153
156
|
onFilterChange={handleHarnessFilterChange}
|
|
154
157
|
/>
|
|
155
|
-
<label className="block
|
|
158
|
+
<label className="block">
|
|
156
159
|
<span className="sr-only">Filter evidence by decision</span>
|
|
157
160
|
<select
|
|
158
161
|
value={decisionFilter}
|
|
@@ -202,10 +205,10 @@ function HistoryRow(props: { receipt: GuardReceipt }) {
|
|
|
202
205
|
const changed = receipt.changed_capabilities.join(", ") || "Nothing recorded";
|
|
203
206
|
const decisionTone = receipt.policy_decision === "allow" ? "green" : receipt.policy_decision === "block" ? "purple" : "blue";
|
|
204
207
|
return (
|
|
205
|
-
<article className="px-4 py-
|
|
208
|
+
<article className="px-4 py-3 transition-colors duration-150 hover:bg-surface-1/70 sm:px-5">
|
|
206
209
|
<div className="grid gap-4 lg:grid-cols-[minmax(0,1fr)_150px_120px] lg:items-start">
|
|
207
210
|
<div className="min-w-0">
|
|
208
|
-
<div className="flex flex-wrap items-center gap-
|
|
211
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
209
212
|
<Tag tone={decisionTone}>{policyActionLabel(receipt.policy_decision)}</Tag>
|
|
210
213
|
<span className="text-xs font-medium text-muted-foreground">{harnessDisplayName(receipt.harness)}</span>
|
|
211
214
|
</div>
|
|
@@ -221,13 +224,15 @@ function HistoryRow(props: { receipt: GuardReceipt }) {
|
|
|
221
224
|
<p className="mt-1 line-clamp-2 text-xs font-medium leading-relaxed text-brand-dark">{changed}</p>
|
|
222
225
|
</div>
|
|
223
226
|
<div className="text-xs font-medium text-muted-foreground lg:text-right">
|
|
224
|
-
{receipt.timestamp}
|
|
227
|
+
{new Date(receipt.timestamp).toLocaleString("en-US", { dateStyle: "medium", timeStyle: "short" })}
|
|
225
228
|
</div>
|
|
226
229
|
</div>
|
|
227
|
-
<details className="group mt-
|
|
228
|
-
<summary className="
|
|
229
|
-
<span className="
|
|
230
|
-
|
|
230
|
+
<details className="group mt-2">
|
|
231
|
+
<summary className="flex cursor-pointer select-none items-center gap-2 text-xs font-semibold text-brand-blue [&::-webkit-details-marker]:hidden">
|
|
232
|
+
<span className="flex items-center gap-2">
|
|
233
|
+
<span className="transition-transform duration-150 group-open:rotate-90">›</span>
|
|
234
|
+
More details
|
|
235
|
+
</span>
|
|
231
236
|
</summary>
|
|
232
237
|
<div className="mt-3 rounded-xl border border-slate-200/70 bg-white p-3">
|
|
233
238
|
<KeyValueGrid
|
|
@@ -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.81"
|
|
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.81"
|
|
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"
|
{plugin_scanner-2.0.79 → plugin_scanner-2.0.81}/src/codex_plugin_scanner/guard/cli/commands.py
RENAMED
|
@@ -3604,6 +3604,7 @@ def _merged_prompt_runtime_artifact(harness: str, artifacts: list[GuardArtifact]
|
|
|
3604
3604
|
prompt_signals: list[str] = []
|
|
3605
3605
|
prompt_matched_texts: list[str] = []
|
|
3606
3606
|
prompt_request_classes: list[str] = []
|
|
3607
|
+
prompt_display_texts: list[str] = []
|
|
3607
3608
|
request_identity = "|".join(sorted(artifact.artifact_id for artifact in artifacts))
|
|
3608
3609
|
for artifact in artifacts:
|
|
3609
3610
|
metadata = artifact.metadata
|
|
@@ -3611,12 +3612,19 @@ def _merged_prompt_runtime_artifact(harness: str, artifacts: list[GuardArtifact]
|
|
|
3611
3612
|
matched_text = metadata.get("prompt_matched_text")
|
|
3612
3613
|
if isinstance(matched_text, str) and matched_text.strip():
|
|
3613
3614
|
prompt_matched_texts.append(matched_text.strip())
|
|
3615
|
+
display_text = metadata.get("prompt_display_text")
|
|
3616
|
+
if isinstance(display_text, str) and display_text.strip():
|
|
3617
|
+
prompt_display_texts.append(display_text.strip())
|
|
3614
3618
|
request_class = metadata.get("prompt_request_class")
|
|
3615
3619
|
if isinstance(request_class, str) and request_class.strip():
|
|
3616
3620
|
prompt_request_classes.append(request_class.strip())
|
|
3617
3621
|
deduped_signals = list(dict.fromkeys(prompt_signals))
|
|
3618
3622
|
deduped_matches = list(dict.fromkeys(prompt_matched_texts))
|
|
3619
3623
|
deduped_classes = list(dict.fromkeys(prompt_request_classes))
|
|
3624
|
+
deduped_display = list(dict.fromkeys(prompt_display_texts))
|
|
3625
|
+
request_summary = (
|
|
3626
|
+
deduped_display[0] if len(deduped_display) == 1 else "Prompt matches multiple guarded request classes."
|
|
3627
|
+
)
|
|
3620
3628
|
return GuardArtifact(
|
|
3621
3629
|
artifact_id=f"{harness}:session:prompt:multi:{hashlib.sha256(request_identity.encode('utf-8')).hexdigest()[:24]}",
|
|
3622
3630
|
name="prompt multi-signal request",
|
|
@@ -3628,7 +3636,10 @@ def _merged_prompt_runtime_artifact(harness: str, artifacts: list[GuardArtifact]
|
|
|
3628
3636
|
"prompt_signals": deduped_signals,
|
|
3629
3637
|
"prompt_summary": "Prompt matches multiple guarded request classes.",
|
|
3630
3638
|
"prompt_matched_texts": deduped_matches,
|
|
3639
|
+
"prompt_display_text": request_summary,
|
|
3631
3640
|
"prompt_request_classes": deduped_classes,
|
|
3641
|
+
"request_summary": request_summary,
|
|
3642
|
+
"runtime_request_summary": request_summary,
|
|
3632
3643
|
},
|
|
3633
3644
|
)
|
|
3634
3645
|
|
|
@@ -3648,6 +3659,7 @@ def _hook_runtime_artifact(
|
|
|
3648
3659
|
payload=payload,
|
|
3649
3660
|
config_path=str(_runtime_policy_path(harness, home_dir, workspace)),
|
|
3650
3661
|
source_scope=_coalesce_string(payload.get("source_scope"), "project"),
|
|
3662
|
+
cwd=workspace,
|
|
3651
3663
|
)
|
|
3652
3664
|
if output_artifact is not None:
|
|
3653
3665
|
return output_artifact
|
|
@@ -3675,6 +3687,11 @@ def _hook_runtime_artifact(
|
|
|
3675
3687
|
requests=prompt_requests,
|
|
3676
3688
|
)
|
|
3677
3689
|
if prompt_artifacts:
|
|
3690
|
+
if harness == "codex":
|
|
3691
|
+
prompt_artifacts = [
|
|
3692
|
+
_with_codex_prompt_display_metadata(artifact, prompt_text=prompt_text)
|
|
3693
|
+
for artifact in prompt_artifacts
|
|
3694
|
+
]
|
|
3678
3695
|
return _merged_prompt_runtime_artifact(harness, prompt_artifacts)
|
|
3679
3696
|
prompt_file_artifact = _codex_prompt_credential_file_artifact(
|
|
3680
3697
|
prompt_text=prompt_text,
|
|
@@ -3718,6 +3735,7 @@ _CODEX_SECRET_OUTPUT_PATTERN = re.compile(
|
|
|
3718
3735
|
r"(?i)(?:fake[_-]?credential|fake[_-]?secret|"
|
|
3719
3736
|
r"(?:api[_-]?key|auth[_-]?token|credential|npm[_-]?token|private[_-]?key|secret|token|password)\s*[:=])"
|
|
3720
3737
|
)
|
|
3738
|
+
_CODEX_PROMPT_SECRET_KEY_MARKERS = ("TOKEN", "SECRET", "PASSWORD", "PASS", "API_KEY", "API-KEY", "AUTH", "CREDENTIAL")
|
|
3721
3739
|
_CODEX_TOOL_RESPONSE_MAX_DEPTH = 5
|
|
3722
3740
|
_CODEX_TOOL_RESPONSE_TEXT_LIMIT = 20000
|
|
3723
3741
|
_CODEX_PROMPT_FILE_FINGERPRINT_LENGTH = 24
|
|
@@ -3728,6 +3746,7 @@ def _codex_post_tool_output_artifact(
|
|
|
3728
3746
|
payload: dict[str, object],
|
|
3729
3747
|
config_path: str,
|
|
3730
3748
|
source_scope: str,
|
|
3749
|
+
cwd: Path | None,
|
|
3731
3750
|
) -> GuardArtifact | None:
|
|
3732
3751
|
response_text = _collect_codex_tool_response_text(payload.get("tool_response"))
|
|
3733
3752
|
if not response_text or _CODEX_SECRET_OUTPUT_PATTERN.search(response_text) is None:
|
|
@@ -3741,6 +3760,8 @@ def _codex_post_tool_output_artifact(
|
|
|
3741
3760
|
command_text = command.strip()
|
|
3742
3761
|
if not command_text:
|
|
3743
3762
|
command_text = tool_name
|
|
3763
|
+
if _codex_command_is_read_only_source_search(command_text, cwd=cwd):
|
|
3764
|
+
return None
|
|
3744
3765
|
fingerprint = hashlib.sha256(
|
|
3745
3766
|
json.dumps(
|
|
3746
3767
|
{
|
|
@@ -3777,6 +3798,290 @@ def _codex_post_tool_output_artifact(
|
|
|
3777
3798
|
)
|
|
3778
3799
|
|
|
3779
3800
|
|
|
3801
|
+
_CODEX_READ_ONLY_SEARCH_COMMANDS = frozenset({"rg", "grep", "egrep", "fgrep"})
|
|
3802
|
+
_CODEX_READ_ONLY_SEARCH_WRAPPERS = frozenset({"bash", "sh", "zsh"})
|
|
3803
|
+
_CODEX_SEARCH_PATTERN_VALUE_FLAGS = frozenset({"-e", "--regexp", "-f", "--file"})
|
|
3804
|
+
_CODEX_SEARCH_OPTION_VALUE_FLAGS = frozenset(
|
|
3805
|
+
{
|
|
3806
|
+
*_CODEX_SEARCH_PATTERN_VALUE_FLAGS,
|
|
3807
|
+
"-g",
|
|
3808
|
+
"--glob",
|
|
3809
|
+
"--iglob",
|
|
3810
|
+
"--max-depth",
|
|
3811
|
+
"--type",
|
|
3812
|
+
"-t",
|
|
3813
|
+
"--type-not",
|
|
3814
|
+
}
|
|
3815
|
+
)
|
|
3816
|
+
_CODEX_SEARCH_OPTION_VALUE_FLAGS_BY_EXECUTABLE = {
|
|
3817
|
+
"rg": frozenset({"-T"}),
|
|
3818
|
+
}
|
|
3819
|
+
_CODEX_SEARCH_UNSAFE_FLAGS = frozenset({"--pre"})
|
|
3820
|
+
_CODEX_GIT_GLOBAL_VALUE_FLAGS = frozenset(
|
|
3821
|
+
{"-c", "--config-env", "--exec-path", "--git-dir", "--work-tree", "--namespace"}
|
|
3822
|
+
)
|
|
3823
|
+
_CODEX_SOURCE_SEARCH_PREFIXES = (
|
|
3824
|
+
"src/",
|
|
3825
|
+
"app/",
|
|
3826
|
+
"lib/",
|
|
3827
|
+
"tests/",
|
|
3828
|
+
"__tests__/",
|
|
3829
|
+
"workers/",
|
|
3830
|
+
"scripts/",
|
|
3831
|
+
"dashboard/",
|
|
3832
|
+
"packages/",
|
|
3833
|
+
)
|
|
3834
|
+
_CODEX_SOURCE_SEARCH_EXTENSIONS = frozenset(
|
|
3835
|
+
{
|
|
3836
|
+
".c",
|
|
3837
|
+
".cc",
|
|
3838
|
+
".cpp",
|
|
3839
|
+
".css",
|
|
3840
|
+
".go",
|
|
3841
|
+
".h",
|
|
3842
|
+
".hpp",
|
|
3843
|
+
".html",
|
|
3844
|
+
".java",
|
|
3845
|
+
".js",
|
|
3846
|
+
".jsx",
|
|
3847
|
+
".json",
|
|
3848
|
+
".md",
|
|
3849
|
+
".mjs",
|
|
3850
|
+
".py",
|
|
3851
|
+
".rs",
|
|
3852
|
+
".sh",
|
|
3853
|
+
".toml",
|
|
3854
|
+
".ts",
|
|
3855
|
+
".tsx",
|
|
3856
|
+
".yaml",
|
|
3857
|
+
".yml",
|
|
3858
|
+
}
|
|
3859
|
+
)
|
|
3860
|
+
_CODEX_SENSITIVE_SEARCH_BASENAMES = frozenset(
|
|
3861
|
+
{
|
|
3862
|
+
".aws",
|
|
3863
|
+
".docker",
|
|
3864
|
+
".env",
|
|
3865
|
+
".git-credentials",
|
|
3866
|
+
".kube",
|
|
3867
|
+
".netrc",
|
|
3868
|
+
".npmrc",
|
|
3869
|
+
".pypirc",
|
|
3870
|
+
".ssh",
|
|
3871
|
+
"credentials",
|
|
3872
|
+
"id_rsa",
|
|
3873
|
+
}
|
|
3874
|
+
)
|
|
3875
|
+
|
|
3876
|
+
|
|
3877
|
+
def _codex_command_is_read_only_source_search(command_text: str, *, cwd: Path | None) -> bool:
|
|
3878
|
+
command = command_text.strip()
|
|
3879
|
+
if not command:
|
|
3880
|
+
return False
|
|
3881
|
+
if _codex_command_has_unquoted_shell_control(command):
|
|
3882
|
+
return False
|
|
3883
|
+
try:
|
|
3884
|
+
parts = shlex.split(command)
|
|
3885
|
+
except ValueError:
|
|
3886
|
+
return False
|
|
3887
|
+
if not parts:
|
|
3888
|
+
return False
|
|
3889
|
+
if _codex_command_uses_untrusted_search_binary(parts[0]):
|
|
3890
|
+
return False
|
|
3891
|
+
executable = Path(parts[0]).name
|
|
3892
|
+
if executable in _CODEX_READ_ONLY_SEARCH_COMMANDS:
|
|
3893
|
+
if executable == "rg" and "--no-config" not in parts and os.environ.get("RIPGREP_CONFIG_PATH"):
|
|
3894
|
+
return False
|
|
3895
|
+
return _codex_search_targets_are_source_like(parts[1:], cwd=cwd, executable=executable)
|
|
3896
|
+
git_grep_args = _git_grep_search_args(parts[1:]) if executable == "git" else None
|
|
3897
|
+
if git_grep_args is not None:
|
|
3898
|
+
if _git_grep_uses_external_execution(git_grep_args):
|
|
3899
|
+
return False
|
|
3900
|
+
return _codex_search_targets_are_source_like(git_grep_args, cwd=cwd, executable=executable)
|
|
3901
|
+
script_index = _shell_wrapper_script_index(parts) if executable in _CODEX_READ_ONLY_SEARCH_WRAPPERS else None
|
|
3902
|
+
if script_index is not None and script_index < len(parts):
|
|
3903
|
+
return _codex_command_is_read_only_source_search(parts[script_index], cwd=cwd)
|
|
3904
|
+
return False
|
|
3905
|
+
|
|
3906
|
+
|
|
3907
|
+
def _codex_command_uses_untrusted_search_binary(executable_token: str) -> bool:
|
|
3908
|
+
return executable_token.startswith(".") or "/" in executable_token or "\\" in executable_token
|
|
3909
|
+
|
|
3910
|
+
|
|
3911
|
+
def _git_grep_search_args(args: list[str]) -> list[str] | None:
|
|
3912
|
+
index = 0
|
|
3913
|
+
while index < len(args):
|
|
3914
|
+
arg = args[index]
|
|
3915
|
+
if arg == "grep":
|
|
3916
|
+
return args[index + 1 :]
|
|
3917
|
+
if arg in _CODEX_GIT_GLOBAL_VALUE_FLAGS:
|
|
3918
|
+
index += 2
|
|
3919
|
+
continue
|
|
3920
|
+
if any(arg.startswith(f"{flag}=") for flag in _CODEX_GIT_GLOBAL_VALUE_FLAGS):
|
|
3921
|
+
index += 1
|
|
3922
|
+
continue
|
|
3923
|
+
if arg in {
|
|
3924
|
+
"--no-pager",
|
|
3925
|
+
"--bare",
|
|
3926
|
+
"--literal-pathspecs",
|
|
3927
|
+
"--no-literal-pathspecs",
|
|
3928
|
+
"--glob-pathspecs",
|
|
3929
|
+
"--noglob-pathspecs",
|
|
3930
|
+
}:
|
|
3931
|
+
index += 1
|
|
3932
|
+
continue
|
|
3933
|
+
return None
|
|
3934
|
+
return None
|
|
3935
|
+
|
|
3936
|
+
|
|
3937
|
+
def _git_grep_uses_external_execution(args: list[str]) -> bool:
|
|
3938
|
+
return any(
|
|
3939
|
+
arg == "-O"
|
|
3940
|
+
or (arg.startswith("-O") and len(arg) > 2)
|
|
3941
|
+
or arg == "--open-files-in-pager"
|
|
3942
|
+
or arg.startswith("--open-files-in-pager=")
|
|
3943
|
+
or arg in {"--textconv", "--ext-grep"}
|
|
3944
|
+
for arg in args
|
|
3945
|
+
)
|
|
3946
|
+
|
|
3947
|
+
|
|
3948
|
+
def _shell_wrapper_script_index(parts: list[str]) -> int | None:
|
|
3949
|
+
for index, arg in enumerate(parts[1:], start=1):
|
|
3950
|
+
if arg == "-c":
|
|
3951
|
+
return index + 1
|
|
3952
|
+
if arg.startswith("-") and not arg.startswith("--") and "c" in arg[1:]:
|
|
3953
|
+
return index + 1
|
|
3954
|
+
return None
|
|
3955
|
+
|
|
3956
|
+
|
|
3957
|
+
def _codex_command_has_unquoted_shell_control(command: str) -> bool:
|
|
3958
|
+
quote: str | None = None
|
|
3959
|
+
escaped = False
|
|
3960
|
+
for index, char in enumerate(command):
|
|
3961
|
+
if escaped:
|
|
3962
|
+
escaped = False
|
|
3963
|
+
continue
|
|
3964
|
+
if char == "\\":
|
|
3965
|
+
escaped = True
|
|
3966
|
+
continue
|
|
3967
|
+
if quote is not None:
|
|
3968
|
+
if char == quote:
|
|
3969
|
+
quote = None
|
|
3970
|
+
if quote == '"' and char == "`":
|
|
3971
|
+
return True
|
|
3972
|
+
if quote == '"' and char == "$" and index + 1 < len(command) and command[index + 1] == "(":
|
|
3973
|
+
return True
|
|
3974
|
+
continue
|
|
3975
|
+
if char in {"'", '"'}:
|
|
3976
|
+
quote = char
|
|
3977
|
+
continue
|
|
3978
|
+
if char in {"\n", "\r"}:
|
|
3979
|
+
return True
|
|
3980
|
+
if char in {"|", "&", ";", ">", "<", "`"}:
|
|
3981
|
+
return True
|
|
3982
|
+
if char == "$" and index + 1 < len(command) and command[index + 1] == "(":
|
|
3983
|
+
return True
|
|
3984
|
+
return False
|
|
3985
|
+
|
|
3986
|
+
|
|
3987
|
+
def _codex_search_targets_are_source_like(args: list[str], *, cwd: Path | None, executable: str) -> bool:
|
|
3988
|
+
positional: list[str] = []
|
|
3989
|
+
skip_next = False
|
|
3990
|
+
pattern_from_option = False
|
|
3991
|
+
option_value_flags = _CODEX_SEARCH_OPTION_VALUE_FLAGS | _CODEX_SEARCH_OPTION_VALUE_FLAGS_BY_EXECUTABLE.get(
|
|
3992
|
+
executable, frozenset()
|
|
3993
|
+
)
|
|
3994
|
+
for arg in args:
|
|
3995
|
+
if skip_next:
|
|
3996
|
+
skip_next = False
|
|
3997
|
+
continue
|
|
3998
|
+
if arg in _CODEX_SEARCH_UNSAFE_FLAGS or any(arg.startswith(f"{flag}=") for flag in _CODEX_SEARCH_UNSAFE_FLAGS):
|
|
3999
|
+
return False
|
|
4000
|
+
if arg in _CODEX_SEARCH_PATTERN_VALUE_FLAGS:
|
|
4001
|
+
pattern_from_option = True
|
|
4002
|
+
skip_next = True
|
|
4003
|
+
continue
|
|
4004
|
+
if any(arg.startswith(flag) and len(arg) > len(flag) for flag in ("-e", "-f")):
|
|
4005
|
+
pattern_from_option = True
|
|
4006
|
+
continue
|
|
4007
|
+
if arg in option_value_flags:
|
|
4008
|
+
skip_next = True
|
|
4009
|
+
continue
|
|
4010
|
+
if any(arg.startswith(f"{flag}=") for flag in _CODEX_SEARCH_PATTERN_VALUE_FLAGS):
|
|
4011
|
+
pattern_from_option = True
|
|
4012
|
+
continue
|
|
4013
|
+
if any(arg.startswith(f"{flag}=") for flag in option_value_flags):
|
|
4014
|
+
continue
|
|
4015
|
+
if arg == "--":
|
|
4016
|
+
continue
|
|
4017
|
+
if arg.startswith("-"):
|
|
4018
|
+
continue
|
|
4019
|
+
positional.append(arg)
|
|
4020
|
+
if pattern_from_option:
|
|
4021
|
+
targets = positional
|
|
4022
|
+
elif len(positional) >= 2:
|
|
4023
|
+
targets = positional[1:]
|
|
4024
|
+
else:
|
|
4025
|
+
return False
|
|
4026
|
+
return bool(targets) and all(_codex_search_target_is_source_like(target, cwd=cwd) for target in targets)
|
|
4027
|
+
|
|
4028
|
+
|
|
4029
|
+
def _codex_search_target_is_source_like(target: str, *, cwd: Path | None) -> bool:
|
|
4030
|
+
stripped = target.strip().strip("'\"")
|
|
4031
|
+
if not stripped:
|
|
4032
|
+
return False
|
|
4033
|
+
if stripped.startswith(("~", "/")):
|
|
4034
|
+
return False
|
|
4035
|
+
target_path = Path(stripped)
|
|
4036
|
+
base_dir = (cwd or Path.cwd()).resolve()
|
|
4037
|
+
unresolved_candidate = base_dir / target_path
|
|
4038
|
+
if _path_contains_symlink(unresolved_candidate, base_dir=base_dir):
|
|
4039
|
+
return False
|
|
4040
|
+
try:
|
|
4041
|
+
candidate = unresolved_candidate.resolve(strict=False)
|
|
4042
|
+
except RuntimeError:
|
|
4043
|
+
return False
|
|
4044
|
+
if candidate.exists():
|
|
4045
|
+
try:
|
|
4046
|
+
relative_candidate = candidate.relative_to(base_dir)
|
|
4047
|
+
except ValueError:
|
|
4048
|
+
return False
|
|
4049
|
+
parts = [part for part in relative_candidate.parts if part not in {"", "."}]
|
|
4050
|
+
else:
|
|
4051
|
+
parts = [part for part in target_path.parts if part not in {"", "."}]
|
|
4052
|
+
if not parts:
|
|
4053
|
+
return False
|
|
4054
|
+
lowered_parts = [part.lower() for part in parts]
|
|
4055
|
+
if any(part in _CODEX_SENSITIVE_SEARCH_BASENAMES for part in lowered_parts):
|
|
4056
|
+
return False
|
|
4057
|
+
if any(part.startswith(".") for part in parts):
|
|
4058
|
+
return False
|
|
4059
|
+
normalized = "/".join(parts)
|
|
4060
|
+
if normalized in {prefix.rstrip("/") for prefix in _CODEX_SOURCE_SEARCH_PREFIXES}:
|
|
4061
|
+
return True
|
|
4062
|
+
if any(normalized.startswith(prefix) for prefix in _CODEX_SOURCE_SEARCH_PREFIXES):
|
|
4063
|
+
return True
|
|
4064
|
+
return Path(stripped).suffix.lower() in _CODEX_SOURCE_SEARCH_EXTENSIONS
|
|
4065
|
+
|
|
4066
|
+
|
|
4067
|
+
def _path_contains_symlink(path: Path, *, base_dir: Path) -> bool:
|
|
4068
|
+
candidate = base_dir
|
|
4069
|
+
try:
|
|
4070
|
+
relative_parts = path.relative_to(base_dir).parts
|
|
4071
|
+
except ValueError:
|
|
4072
|
+
return True
|
|
4073
|
+
for part in relative_parts:
|
|
4074
|
+
if part in {"", "."}:
|
|
4075
|
+
continue
|
|
4076
|
+
candidate /= part
|
|
4077
|
+
try:
|
|
4078
|
+
if candidate.is_symlink():
|
|
4079
|
+
return True
|
|
4080
|
+
except OSError:
|
|
4081
|
+
return True
|
|
4082
|
+
return False
|
|
4083
|
+
|
|
4084
|
+
|
|
3780
4085
|
def _collect_codex_tool_response_text(value: object, *, depth: int = 0) -> str:
|
|
3781
4086
|
if depth > _CODEX_TOOL_RESPONSE_MAX_DEPTH:
|
|
3782
4087
|
return ""
|
|
@@ -3850,6 +4155,7 @@ def _codex_prompt_credential_file_artifact(
|
|
|
3850
4155
|
sort_keys=True,
|
|
3851
4156
|
).encode("utf-8")
|
|
3852
4157
|
).hexdigest()[:_CODEX_PROMPT_FILE_FINGERPRINT_LENGTH]
|
|
4158
|
+
prompt_display = _codex_prompt_display_text(prompt_text, requested_path=requested_path)
|
|
3853
4159
|
return GuardArtifact(
|
|
3854
4160
|
artifact_id=f"codex:project:prompt-file:{fingerprint}",
|
|
3855
4161
|
name=f"credential-looking local file {path.name}",
|
|
@@ -3861,9 +4167,11 @@ def _codex_prompt_credential_file_artifact(
|
|
|
3861
4167
|
"prompt_signals": ["requested file content contains credential-looking material"],
|
|
3862
4168
|
"prompt_summary": "Prompt asks Codex to read a credential-looking local file.",
|
|
3863
4169
|
"prompt_matched_text": requested_path,
|
|
4170
|
+
"prompt_display_text": prompt_display,
|
|
3864
4171
|
"prompt_request_class": "secret_read",
|
|
3865
4172
|
"prompt_request_classes": ["secret_read"],
|
|
3866
|
-
"
|
|
4173
|
+
"request_summary": prompt_display,
|
|
4174
|
+
"runtime_request_summary": prompt_display,
|
|
3867
4175
|
"runtime_request_reason": (
|
|
3868
4176
|
"Guard scanned a small local dotfile before Codex read it and found credential-looking text."
|
|
3869
4177
|
),
|
|
@@ -3873,6 +4181,72 @@ def _codex_prompt_credential_file_artifact(
|
|
|
3873
4181
|
return None
|
|
3874
4182
|
|
|
3875
4183
|
|
|
4184
|
+
def _with_codex_prompt_display_metadata(artifact: GuardArtifact, *, prompt_text: str) -> GuardArtifact:
|
|
4185
|
+
matched_text = artifact.metadata.get("prompt_matched_text")
|
|
4186
|
+
display = _codex_prompt_display_text(
|
|
4187
|
+
prompt_text,
|
|
4188
|
+
requested_path=matched_text if isinstance(matched_text, str) else None,
|
|
4189
|
+
)
|
|
4190
|
+
metadata = {
|
|
4191
|
+
**artifact.metadata,
|
|
4192
|
+
"prompt_display_text": display,
|
|
4193
|
+
"request_summary": display,
|
|
4194
|
+
"runtime_request_summary": display,
|
|
4195
|
+
}
|
|
4196
|
+
return replace(artifact, metadata=metadata)
|
|
4197
|
+
|
|
4198
|
+
|
|
4199
|
+
def _codex_prompt_display_text(prompt_text: str, *, requested_path: str | None = None) -> str:
|
|
4200
|
+
sanitized_prompt = _sanitize_codex_display_text(prompt_text)
|
|
4201
|
+
path_suffix = ""
|
|
4202
|
+
if requested_path is not None and requested_path.strip():
|
|
4203
|
+
path_suffix = f" for `{_sanitize_codex_display_text(requested_path.strip())}`"
|
|
4204
|
+
return f"Codex prompt{path_suffix}: {_truncate_codex_display_text(sanitized_prompt, limit=320)}"
|
|
4205
|
+
|
|
4206
|
+
|
|
4207
|
+
def _sanitize_codex_display_text(value: str) -> str:
|
|
4208
|
+
collapsed = " ".join(value.strip().split())
|
|
4209
|
+
redacted = _redact_codex_prompt_secret_assignments(collapsed)
|
|
4210
|
+
sanitized = re.sub(r"/(?:Users|home)/[^/\s]+", "~", redacted)
|
|
4211
|
+
return re.sub(r"[A-Za-z]:\\Users\\[^\\\s]+", "~", sanitized)
|
|
4212
|
+
|
|
4213
|
+
|
|
4214
|
+
def _redact_codex_prompt_secret_assignments(value: str) -> str:
|
|
4215
|
+
output: list[str] = []
|
|
4216
|
+
index = 0
|
|
4217
|
+
while index < len(value):
|
|
4218
|
+
equals_index = value.find("=", index)
|
|
4219
|
+
if equals_index == -1:
|
|
4220
|
+
output.append(value[index:])
|
|
4221
|
+
break
|
|
4222
|
+
key_start = equals_index - 1
|
|
4223
|
+
while key_start >= index and value[key_start] not in {" ", "\t", "\n", "\r", ",", ";"}:
|
|
4224
|
+
key_start -= 1
|
|
4225
|
+
key_start += 1
|
|
4226
|
+
key = value[key_start:equals_index].strip()
|
|
4227
|
+
key_upper = key.upper()
|
|
4228
|
+
if key and any(marker in key_upper for marker in _CODEX_PROMPT_SECRET_KEY_MARKERS):
|
|
4229
|
+
value_start = equals_index + 1
|
|
4230
|
+
while value_start < len(value) and value[value_start].isspace():
|
|
4231
|
+
value_start += 1
|
|
4232
|
+
value_end = value_start
|
|
4233
|
+
while value_end < len(value) and value[value_end] not in {" ", "\t", "\n", "\r", ",", ";"}:
|
|
4234
|
+
value_end += 1
|
|
4235
|
+
output.append(value[index:value_start])
|
|
4236
|
+
output.append("[redacted]")
|
|
4237
|
+
index = value_end
|
|
4238
|
+
continue
|
|
4239
|
+
output.append(value[index : equals_index + 1])
|
|
4240
|
+
index = equals_index + 1
|
|
4241
|
+
return "".join(output)
|
|
4242
|
+
|
|
4243
|
+
|
|
4244
|
+
def _truncate_codex_display_text(value: str, *, limit: int) -> str:
|
|
4245
|
+
if len(value) <= limit:
|
|
4246
|
+
return value
|
|
4247
|
+
return f"{value[: limit - 1].rstrip()}…"
|
|
4248
|
+
|
|
4249
|
+
|
|
3876
4250
|
def _resolve_prompt_scan_path(requested_path: str, *, cwd: Path | None) -> Path | None:
|
|
3877
4251
|
stripped = requested_path.strip().strip("'\"").rstrip(".,;:!?)]}")
|
|
3878
4252
|
if not stripped:
|