plugin-scanner 2.0.107__tar.gz → 2.0.108__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.107 → plugin_scanner-2.0.108}/PKG-INFO +1 -1
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/pyproject.toml +1 -1
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/pyproject.toml.bak +1 -1
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/cli/commands.py +47 -8
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/runtime/secret_sensitivity.py +124 -2
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/version.py +1 -1
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_risk.py +56 -1
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_runtime.py +169 -3
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_runtime_detectors.py +3 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.clusterfuzzlite/Dockerfile +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.clusterfuzzlite/build.sh +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.clusterfuzzlite/project.yaml +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.clusterfuzzlite/requirements-atheris.txt +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.dockerignore +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.github/CODEOWNERS +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.github/dependabot.yml +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.github/workflows/ci.yml +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.github/workflows/codeql.yml +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.github/workflows/dependabot-uv-lock.yml +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.github/workflows/fuzz.yml +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.github/workflows/harness-smoke.yml +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.github/workflows/publish.yml +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.github/workflows/scorecard.yml +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.gitignore +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.pre-commit-hooks.yaml +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/CONTRIBUTING.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/Dockerfile +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/LICENSE +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/README.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/SECURITY.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/index.html +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/package.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/pnpm-lock.yaml +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/public/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/public/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/public/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/public/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/public/favicon.ico +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/src/app.tsx +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/src/approval-center-layout.tsx +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/src/approval-center-primitives.tsx +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/src/approval-center-utils.ts +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/src/fleet-workspace.tsx +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/src/guard-api.test.ts +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/src/guard-api.ts +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/src/guard-demo.ts +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/src/guard-types.ts +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/src/main.tsx +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/src/receipts-workspace.tsx +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/src/runtime-overview.tsx +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/src/settings-workspace.tsx +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/src/styles.css +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/src/vite-env.d.ts +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/tsconfig.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/dashboard/vite.config.ts +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/docker-requirements.txt +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/docs/guard/approval-audit.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/docs/guard/architecture.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/docs/guard/get-started.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/docs/guard/harness-support.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/docs/guard/local-vs-cloud.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/docs/guard/testing-matrix.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/docs/trust/mcp-trust-draft.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/docs/trust/plugin-trust-draft.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/docs/trust/skill-trust-local.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/fuzzers/manifest_fuzzer.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/requirements.txt +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/schemas/plugin-quality.v1.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/schemas/scan-result.v1.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/schemas/verify-result.v1.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/__init__.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/action_runner.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/argparse_utils.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/checks/__init__.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/checks/claude.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/checks/gemini.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/checks/manifest.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/checks/opencode.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/checks/security.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/cli.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/cli_ui.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/config.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/github_reporting.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/__init__.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/approvals.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/config.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/incident.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/launcher.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/models.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/protect.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/redaction.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/risk.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/runtime/detectors.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/shims.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/store.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/types.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/lint_fixes.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/marketplace_support.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/models.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/path_support.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/policy.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/quality_artifact.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/repo_detect.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/reporting.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/rules/__init__.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/rules/registry.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/rules/specs.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/scanner.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/submission.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/suppressions.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/trust_helpers.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/trust_models.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/trust_scoring.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/trust_specs.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/verification.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/__init__.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/conftest.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/__init__.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/bad-plugin/.mcp.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/bad-plugin/secrets.js +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/claude-plugin-good/README.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/code-quality-bad/evil.js +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/code-quality-bad/inject.js +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/gemini-extension-good/README.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/good-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/good-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/good-plugin/README.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/good-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/mcp-canary-server.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/mit-license/LICENSE +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/opencode-good/LICENSE +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/opencode-good/README.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/opencode-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/fixtures/with-marketplace/marketplace.json +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test-trust-scoring.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test-trust-specs.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_action_runner.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_best_practices.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_cisco_install_surfaces.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_cli.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_code_quality.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_config.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_coverage_remaining.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_ecosystems.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_edge_cases.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_final_coverage.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_access_graph.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_approvals.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_bootstrap.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_capabilities.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_claude_adapter.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_cli.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_codex_e2e.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_codex_install.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_codex_proxy.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_config_paths.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_connect_flow.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_consumer_mode.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_copilot_adapter.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_copilot_proxy.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_daemon_manager.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_event_schema_v1.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_events.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_launch_env.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_opencode_proxy.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_product_flow.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_protect.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_render.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_runtime_action_harnesses.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_runtime_actions.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_runtime_decisions.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_runtime_signals.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_store_migrations.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_surface_server.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_guard_verdicts.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_hermes_adapter.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_integration.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_lint_fixes.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_live_cisco_smoke.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_manifest.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_marketplace.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_mcp_security.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_openclaw_adapter.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_operational_security.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_policy.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_quality_artifact.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_rule_registry.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_scanner.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_schema_contracts.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_security.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_security_ops.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_skill_security.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_submission.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_trust_scoring.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_trust_specs.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_verification.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/tests/test_versioning.py +0 -0
- {plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/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.108
|
|
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.108"
|
|
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.108"
|
|
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.107 → plugin_scanner-2.0.108}/src/codex_plugin_scanner/guard/cli/commands.py
RENAMED
|
@@ -97,6 +97,7 @@ from ..runtime.secret_file_requests import (
|
|
|
97
97
|
extract_sensitive_tool_action_request,
|
|
98
98
|
is_explicitly_benign_tool_action_request,
|
|
99
99
|
)
|
|
100
|
+
from ..runtime.secret_sensitivity import SecretContentMatch, classify_secret_content
|
|
100
101
|
from ..runtime.surface_server import GuardSurfaceRuntime
|
|
101
102
|
from ..store import GuardStore
|
|
102
103
|
from .approval_commands import add_approval_parser, run_approval_command
|
|
@@ -3962,10 +3963,6 @@ def _hook_runtime_artifact(
|
|
|
3962
3963
|
)
|
|
3963
3964
|
|
|
3964
3965
|
|
|
3965
|
-
_CODEX_SECRET_OUTPUT_PATTERN = re.compile(
|
|
3966
|
-
r"(?i)(?:fake[_-]?credential|fake[_-]?secret|"
|
|
3967
|
-
r"(?:api[_-]?key|auth[_-]?token|credential|npm[_-]?token|private[_-]?key|secret|token|password)\s*[:=])"
|
|
3968
|
-
)
|
|
3969
3966
|
_CODEX_PROMPT_SECRET_KEY_MARKERS = ("TOKEN", "SECRET", "PASSWORD", "PASS", "API_KEY", "API-KEY", "AUTH", "CREDENTIAL")
|
|
3970
3967
|
_CODEX_TOOL_RESPONSE_MAX_DEPTH = 5
|
|
3971
3968
|
_CODEX_TOOL_RESPONSE_TEXT_LIMIT = 20000
|
|
@@ -3980,13 +3977,19 @@ def _codex_post_tool_output_artifact(
|
|
|
3980
3977
|
cwd: Path | None,
|
|
3981
3978
|
) -> GuardArtifact | None:
|
|
3982
3979
|
response_text = _collect_codex_tool_response_text(payload.get("tool_response"))
|
|
3983
|
-
|
|
3980
|
+
content_matches = classify_secret_content(response_text)
|
|
3981
|
+
if not content_matches:
|
|
3984
3982
|
return None
|
|
3985
3983
|
tool_name = _coalesce_string(payload.get("tool_name"), "Bash")
|
|
3986
3984
|
command_text = _codex_post_tool_command_text(payload)
|
|
3987
3985
|
if not command_text:
|
|
3988
3986
|
command_text = tool_name
|
|
3989
|
-
if
|
|
3987
|
+
if _codex_source_inspection_can_skip_secret_output(
|
|
3988
|
+
command_text=command_text,
|
|
3989
|
+
response_text=response_text,
|
|
3990
|
+
content_matches=content_matches,
|
|
3991
|
+
cwd=cwd,
|
|
3992
|
+
):
|
|
3990
3993
|
return None
|
|
3991
3994
|
fingerprint = hashlib.sha256(
|
|
3992
3995
|
json.dumps(
|
|
@@ -4109,6 +4112,10 @@ _CODEX_SOURCE_SEARCH_EXTENSIONS = frozenset(
|
|
|
4109
4112
|
".yml",
|
|
4110
4113
|
}
|
|
4111
4114
|
)
|
|
4115
|
+
_CODEX_BENIGN_SOURCE_DOTFILES = frozenset({".nvmrc"})
|
|
4116
|
+
_CODEX_BENIGN_SECRET_FIXTURE_ASSIGNMENT_PATTERN = re.compile(
|
|
4117
|
+
r"(?i)\s*fake[_-]?(?:credential|secret|token)\s*[:=]\s*(?:\"[^\r\n\"]+\"|'[^\r\n']+'|[^\s\"',}]+)\s*"
|
|
4118
|
+
)
|
|
4112
4119
|
_CODEX_SENSITIVE_SEARCH_BASENAMES = frozenset(
|
|
4113
4120
|
{
|
|
4114
4121
|
".aws",
|
|
@@ -4127,6 +4134,35 @@ _CODEX_SENSITIVE_SEARCH_BASENAMES = frozenset(
|
|
|
4127
4134
|
_CODEX_SED_PRINT_SCRIPT_PATTERN = re.compile(r"^\s*(?:\$|\d+)?(?:\s*,\s*(?:\$|\d+))?p\s*$")
|
|
4128
4135
|
|
|
4129
4136
|
|
|
4137
|
+
def _codex_source_inspection_can_skip_secret_output(
|
|
4138
|
+
*,
|
|
4139
|
+
command_text: str,
|
|
4140
|
+
response_text: str,
|
|
4141
|
+
content_matches: tuple[SecretContentMatch, ...],
|
|
4142
|
+
cwd: Path | None,
|
|
4143
|
+
) -> bool:
|
|
4144
|
+
if not _codex_command_is_read_only_source_inspection(command_text, cwd=cwd):
|
|
4145
|
+
return False
|
|
4146
|
+
if any(match.sensitivity != "medium" for match in content_matches):
|
|
4147
|
+
return False
|
|
4148
|
+
if _codex_command_references_benign_source_dotfile(command_text):
|
|
4149
|
+
return _codex_output_is_only_benign_secret_fixture(response_text)
|
|
4150
|
+
return True
|
|
4151
|
+
|
|
4152
|
+
|
|
4153
|
+
def _codex_output_is_only_benign_secret_fixture(response_text: str) -> bool:
|
|
4154
|
+
lines = [line for line in response_text.splitlines() if line.strip()]
|
|
4155
|
+
return bool(lines) and all(_CODEX_BENIGN_SECRET_FIXTURE_ASSIGNMENT_PATTERN.fullmatch(line) for line in lines)
|
|
4156
|
+
|
|
4157
|
+
|
|
4158
|
+
def _codex_command_references_benign_source_dotfile(command_text: str) -> bool:
|
|
4159
|
+
try:
|
|
4160
|
+
parts = shlex.split(command_text)
|
|
4161
|
+
except ValueError:
|
|
4162
|
+
return False
|
|
4163
|
+
return any(Path(part).name.lower() in _CODEX_BENIGN_SOURCE_DOTFILES for part in parts)
|
|
4164
|
+
|
|
4165
|
+
|
|
4130
4166
|
def _codex_command_is_read_only_source_inspection(command_text: str, *, cwd: Path | None) -> bool:
|
|
4131
4167
|
command = command_text.strip()
|
|
4132
4168
|
if not command:
|
|
@@ -4644,13 +4680,16 @@ def _codex_search_target_is_source_like(target: str, *, cwd: Path | None) -> boo
|
|
|
4644
4680
|
lowered_parts = [part.lower() for part in parts]
|
|
4645
4681
|
if any(part in _CODEX_SENSITIVE_SEARCH_BASENAMES for part in lowered_parts):
|
|
4646
4682
|
return False
|
|
4647
|
-
if
|
|
4683
|
+
hidden_parts = [part for part in lowered_parts if part.startswith(".")]
|
|
4684
|
+
if hidden_parts and not all(part in _CODEX_BENIGN_SOURCE_DOTFILES for part in hidden_parts):
|
|
4648
4685
|
return False
|
|
4649
4686
|
normalized = "/".join(parts)
|
|
4650
4687
|
if normalized in {prefix.rstrip("/") for prefix in _CODEX_SOURCE_SEARCH_PREFIXES}:
|
|
4651
4688
|
return True
|
|
4652
4689
|
if any(normalized.startswith(prefix) for prefix in _CODEX_SOURCE_SEARCH_PREFIXES):
|
|
4653
4690
|
return True
|
|
4691
|
+
if Path(stripped).name.lower() in _CODEX_BENIGN_SOURCE_DOTFILES:
|
|
4692
|
+
return True
|
|
4654
4693
|
return Path(stripped).suffix.lower() in _CODEX_SOURCE_SEARCH_EXTENSIONS
|
|
4655
4694
|
|
|
4656
4695
|
|
|
@@ -4745,7 +4784,7 @@ def _codex_prompt_credential_file_artifact(
|
|
|
4745
4784
|
content = handle.read(_PROMPT_CONTENT_SCAN_MAX_BYTES).decode("utf-8", errors="ignore")
|
|
4746
4785
|
except OSError:
|
|
4747
4786
|
continue
|
|
4748
|
-
if
|
|
4787
|
+
if not classify_secret_content(content):
|
|
4749
4788
|
continue
|
|
4750
4789
|
normalized_path = str(path)
|
|
4751
4790
|
fingerprint = hashlib.sha256(
|
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
|
+
import re
|
|
6
7
|
from dataclasses import dataclass
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
from typing import Literal
|
|
9
10
|
|
|
10
11
|
SecretSensitivity = Literal["high", "critical"]
|
|
12
|
+
SecretContentSensitivity = Literal["medium", "high", "critical"]
|
|
11
13
|
|
|
12
14
|
_AWS_CREDENTIALS_MARKER = "/".join((".aws", "credentials"))
|
|
13
15
|
_DOCKER_CONFIG_MARKER = "/".join((".docker", "config.json"))
|
|
@@ -42,8 +44,12 @@ _SENSITIVE_BASENAME_LABELS = {
|
|
|
42
44
|
".netrc": "netrc credentials",
|
|
43
45
|
".git-credentials": "Git credential store",
|
|
44
46
|
".terraform.tfvars": "Terraform variable secrets",
|
|
47
|
+
"private-key.pem": "wallet/private-key file",
|
|
48
|
+
"private.key": "wallet/private-key file",
|
|
49
|
+
"wallet.key": "wallet/private-key file",
|
|
45
50
|
"terraform.tfvars": "Terraform variable secrets",
|
|
46
51
|
}
|
|
52
|
+
_SENSITIVE_BASENAME_KEYWORDS = ("private-key", "private_key", "wallet-key", "wallet_key")
|
|
47
53
|
_REDACTED_BASENAME_LABELS = {
|
|
48
54
|
"id_rsa": "SSH private key",
|
|
49
55
|
"id_ed25519": "SSH private key",
|
|
@@ -80,7 +86,86 @@ _SENSITIVE_PATH_REASONS = {
|
|
|
80
86
|
"Terraform variable secrets": (
|
|
81
87
|
"Guard treats Terraform variable files as sensitive because they often contain secrets."
|
|
82
88
|
),
|
|
89
|
+
"wallet/private-key file": (
|
|
90
|
+
"Guard treats wallet and private-key files as sensitive because they can authorize account control."
|
|
91
|
+
),
|
|
83
92
|
}
|
|
93
|
+
_SECRET_ASSIGNMENT_VALUE_PATTERN = r"(?:\"[^\"\r\n]+\"|'[^'\r\n]+'|[^ \t\r\n\"',}]+)"
|
|
94
|
+
_HEDERA_PRIVATE_KEY_VALUE_PATTERN = r"(?:\"(?:0x)?[0-9a-f]{64,96}\"|'(?:0x)?[0-9a-f]{64,96}'|(?:0x)?[0-9a-f]{64,96}\b)"
|
|
95
|
+
_SECRET_CONTENT_PATTERNS: tuple[tuple[str, str, SecretContentSensitivity, re.Pattern[str], str], ...] = (
|
|
96
|
+
(
|
|
97
|
+
"npm-auth-token",
|
|
98
|
+
"npm auth token",
|
|
99
|
+
"high",
|
|
100
|
+
re.compile(
|
|
101
|
+
r"(?im)[\"']?\b[A-Za-z0-9_-]*(?:_authToken|npm[_-]?token)\b[\"']?\s*[:=]\s*"
|
|
102
|
+
+ _SECRET_ASSIGNMENT_VALUE_PATTERN
|
|
103
|
+
),
|
|
104
|
+
"Guard found an npm registry token pattern.",
|
|
105
|
+
),
|
|
106
|
+
(
|
|
107
|
+
"github-token",
|
|
108
|
+
"GitHub token",
|
|
109
|
+
"high",
|
|
110
|
+
re.compile(r"\b(?:gh[pousr]_[A-Za-z0-9_]{20,}|github_pat_[A-Za-z0-9_]{20,}_[A-Za-z0-9_]{20,})\b"),
|
|
111
|
+
"Guard found a GitHub token pattern.",
|
|
112
|
+
),
|
|
113
|
+
(
|
|
114
|
+
"aws-access-key",
|
|
115
|
+
"AWS access key",
|
|
116
|
+
"high",
|
|
117
|
+
re.compile(r"\b(?:AKIA|ASIA)[0-9A-Z]{16}\b"),
|
|
118
|
+
"Guard found an AWS access key pattern.",
|
|
119
|
+
),
|
|
120
|
+
(
|
|
121
|
+
"openai-api-key",
|
|
122
|
+
"OpenAI API key",
|
|
123
|
+
"high",
|
|
124
|
+
re.compile(r"\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}\b"),
|
|
125
|
+
"Guard found an OpenAI API key pattern.",
|
|
126
|
+
),
|
|
127
|
+
(
|
|
128
|
+
"anthropic-api-key",
|
|
129
|
+
"Anthropic API key",
|
|
130
|
+
"high",
|
|
131
|
+
re.compile(r"\bsk-ant-api03-[A-Za-z0-9_-]{20,}\b"),
|
|
132
|
+
"Guard found an Anthropic API key pattern.",
|
|
133
|
+
),
|
|
134
|
+
(
|
|
135
|
+
"hedera-private-key",
|
|
136
|
+
"Hedera private key",
|
|
137
|
+
"critical",
|
|
138
|
+
re.compile(
|
|
139
|
+
r"(?im)[\"']?\b[A-Za-z0-9_-]*(?:hedera[_-]?)?(?:operator[_-]?)?private[_-]?key\b[\"']?\s*[:=]\s*"
|
|
140
|
+
+ _HEDERA_PRIVATE_KEY_VALUE_PATTERN
|
|
141
|
+
),
|
|
142
|
+
"Guard found a Hedera private-key-like value.",
|
|
143
|
+
),
|
|
144
|
+
(
|
|
145
|
+
"pem-private-key",
|
|
146
|
+
"PEM private key",
|
|
147
|
+
"critical",
|
|
148
|
+
re.compile(r"-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----", re.MULTILINE),
|
|
149
|
+
"Guard found a PEM private key header.",
|
|
150
|
+
),
|
|
151
|
+
(
|
|
152
|
+
"credential-marker",
|
|
153
|
+
"credential assignment",
|
|
154
|
+
"medium",
|
|
155
|
+
re.compile(r"(?i)(?:^|[^a-z0-9])fake[_-]?(?:credential|secret)\b"),
|
|
156
|
+
"Guard found credential-looking marker text.",
|
|
157
|
+
),
|
|
158
|
+
(
|
|
159
|
+
"credential-assignment",
|
|
160
|
+
"credential assignment",
|
|
161
|
+
"medium",
|
|
162
|
+
re.compile(
|
|
163
|
+
r"(?im)[\"']?\b[A-Za-z0-9_-]*(?:api[_-]?key|auth[_-]?token|credential|credentials|npm[_-]?token|"
|
|
164
|
+
r"private[_-]?key|secret|token|password)\b[\"']?\s*[:=]\s*" + _SECRET_ASSIGNMENT_VALUE_PATTERN
|
|
165
|
+
),
|
|
166
|
+
"Guard found credential-looking assignment text.",
|
|
167
|
+
),
|
|
168
|
+
)
|
|
84
169
|
|
|
85
170
|
|
|
86
171
|
@dataclass(frozen=True, slots=True)
|
|
@@ -100,6 +185,14 @@ class SecretPathMatch:
|
|
|
100
185
|
return self.family
|
|
101
186
|
|
|
102
187
|
|
|
188
|
+
@dataclass(frozen=True, slots=True)
|
|
189
|
+
class SecretContentMatch:
|
|
190
|
+
classifier: str
|
|
191
|
+
family: str
|
|
192
|
+
sensitivity: SecretContentSensitivity
|
|
193
|
+
reason: str
|
|
194
|
+
|
|
195
|
+
|
|
103
196
|
def classify_secret_path(
|
|
104
197
|
path: str | None,
|
|
105
198
|
*,
|
|
@@ -125,11 +218,20 @@ def classify_secret_path(
|
|
|
125
218
|
sensitivity="critical",
|
|
126
219
|
)
|
|
127
220
|
if basename in _SENSITIVE_BASENAME_LABELS:
|
|
221
|
+
family = _SENSITIVE_BASENAME_LABELS[basename]
|
|
222
|
+
sensitivity: SecretSensitivity = "critical" if family == "wallet/private-key file" else "high"
|
|
223
|
+
return _match(
|
|
224
|
+
requested_path=requested_path,
|
|
225
|
+
normalized_path=normalized_path,
|
|
226
|
+
family=family,
|
|
227
|
+
sensitivity=sensitivity,
|
|
228
|
+
)
|
|
229
|
+
if any(keyword in basename for keyword in _SENSITIVE_BASENAME_KEYWORDS):
|
|
128
230
|
return _match(
|
|
129
231
|
requested_path=requested_path,
|
|
130
232
|
normalized_path=normalized_path,
|
|
131
|
-
family=
|
|
132
|
-
sensitivity="
|
|
233
|
+
family="wallet/private-key file",
|
|
234
|
+
sensitivity="critical",
|
|
133
235
|
)
|
|
134
236
|
if "..." in lowered_segments and basename in _REDACTED_BASENAME_LABELS:
|
|
135
237
|
family = _REDACTED_BASENAME_LABELS[basename]
|
|
@@ -170,6 +272,26 @@ def classify_legacy_secret_path_families(text: str) -> set[str]:
|
|
|
170
272
|
return {family for marker, family in LEGACY_SECRET_PATH_TEXT_MARKERS if marker in lowered}
|
|
171
273
|
|
|
172
274
|
|
|
275
|
+
def classify_secret_content(text: str | None) -> tuple[SecretContentMatch, ...]:
|
|
276
|
+
if not isinstance(text, str) or not text.strip():
|
|
277
|
+
return ()
|
|
278
|
+
matches: list[SecretContentMatch] = []
|
|
279
|
+
seen: set[str] = set()
|
|
280
|
+
for classifier, family, sensitivity, pattern, reason in _SECRET_CONTENT_PATTERNS:
|
|
281
|
+
if pattern.search(text) is None or classifier in seen:
|
|
282
|
+
continue
|
|
283
|
+
seen.add(classifier)
|
|
284
|
+
matches.append(
|
|
285
|
+
SecretContentMatch(
|
|
286
|
+
classifier=classifier,
|
|
287
|
+
family=family,
|
|
288
|
+
sensitivity=sensitivity,
|
|
289
|
+
reason=reason,
|
|
290
|
+
)
|
|
291
|
+
)
|
|
292
|
+
return tuple(matches)
|
|
293
|
+
|
|
294
|
+
|
|
173
295
|
def redacted_secret_path_context(path: str) -> str | None:
|
|
174
296
|
segments = tuple(segment for segment in path.replace("\\", "/").split("/") if segment)
|
|
175
297
|
lowered_segments = tuple(segment.lower() for segment in segments)
|
|
@@ -44,7 +44,12 @@ from codex_plugin_scanner.guard.runtime.secret_file_requests import (
|
|
|
44
44
|
is_explicitly_benign_tool_action_request,
|
|
45
45
|
is_file_read_tool_name,
|
|
46
46
|
)
|
|
47
|
-
from codex_plugin_scanner.guard.runtime.secret_sensitivity import
|
|
47
|
+
from codex_plugin_scanner.guard.runtime.secret_sensitivity import (
|
|
48
|
+
SecretContentMatch,
|
|
49
|
+
SecretPathMatch,
|
|
50
|
+
classify_secret_content,
|
|
51
|
+
classify_secret_path,
|
|
52
|
+
)
|
|
48
53
|
from codex_plugin_scanner.guard.store import GuardStore
|
|
49
54
|
|
|
50
55
|
|
|
@@ -384,6 +389,56 @@ def test_secret_sensitivity_module_classifies_planned_secret_path_families(tmp_p
|
|
|
384
389
|
assert match.reason
|
|
385
390
|
|
|
386
391
|
|
|
392
|
+
@pytest.mark.parametrize(
|
|
393
|
+
("path", "family"),
|
|
394
|
+
[
|
|
395
|
+
("wallet.key", "wallet/private-key file"),
|
|
396
|
+
("private-key.pem", "wallet/private-key file"),
|
|
397
|
+
("operator-private-key.txt", "wallet/private-key file"),
|
|
398
|
+
],
|
|
399
|
+
)
|
|
400
|
+
def test_secret_sensitivity_module_classifies_wallet_private_key_filenames(tmp_path, path, family):
|
|
401
|
+
match = classify_secret_path(path, home_dir=tmp_path)
|
|
402
|
+
|
|
403
|
+
assert isinstance(match, SecretPathMatch)
|
|
404
|
+
assert match.family == family
|
|
405
|
+
assert match.sensitivity == "critical"
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
@pytest.mark.parametrize(
|
|
409
|
+
("content", "family"),
|
|
410
|
+
[
|
|
411
|
+
("//registry.npmjs.org/:_authToken=" + "n" * 36, "npm auth token"),
|
|
412
|
+
('//registry.npmjs.org/:_authToken="' + "n" * 36 + '"', "npm auth token"),
|
|
413
|
+
('MY_NPM_TOKEN="' + "n" * 36 + '"', "npm auth token"),
|
|
414
|
+
("token=" + "ghp_" + "A" * 36, "GitHub token"),
|
|
415
|
+
("token=" + "github_pat_" + "A" * 22 + "_" + "B" * 59, "GitHub token"),
|
|
416
|
+
("aws_access_key_id=" + "AKIA" + "A" * 16, "AWS access key"),
|
|
417
|
+
("OPENAI_API_KEY=" + "sk-" + "A" * 32, "OpenAI API key"),
|
|
418
|
+
("ANTHROPIC_API_KEY=" + "sk-ant-api03-" + "A" * 60, "Anthropic API key"),
|
|
419
|
+
("HEDERA_PRIVATE_KEY=" + "a" * 64, "Hedera private key"),
|
|
420
|
+
('HEDERA_PRIVATE_KEY="' + "a" * 64 + '"', "Hedera private key"),
|
|
421
|
+
("-----BEGIN " + "PRIVATE KEY-----\nredacted\n-----END " + "PRIVATE KEY-----", "PEM private key"),
|
|
422
|
+
('TOKEN="' + "A" * 24 + '"', "credential assignment"),
|
|
423
|
+
("auth_token='" + "B" * 24 + "'", "credential assignment"),
|
|
424
|
+
('{"password": "' + "C" * 24 + '"}', "credential assignment"),
|
|
425
|
+
("MY_TOKEN=fixture-token", "credential assignment"),
|
|
426
|
+
('MY_NPM_TOKEN="fixture-token"', "credential assignment"),
|
|
427
|
+
('{"OPENAI_API_KEY": "fixture-key"}', "credential assignment"),
|
|
428
|
+
],
|
|
429
|
+
)
|
|
430
|
+
def test_secret_content_classifier_detects_planned_secret_content(content, family):
|
|
431
|
+
matches = classify_secret_content(content)
|
|
432
|
+
|
|
433
|
+
assert any(isinstance(match, SecretContentMatch) and match.family == family for match in matches)
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
def test_secret_content_classifier_does_not_upgrade_npm_token_prose():
|
|
437
|
+
matches = classify_secret_content("Docs say npm token: use an environment variable instead.")
|
|
438
|
+
|
|
439
|
+
assert not any(match.family == "npm auth token" for match in matches)
|
|
440
|
+
|
|
441
|
+
|
|
387
442
|
def test_file_read_request_classifier_is_argument_aware(tmp_path):
|
|
388
443
|
env_request = extract_sensitive_file_read_request("read_file", {"path": ".env.local"})
|
|
389
444
|
claude_request = extract_sensitive_file_read_request("Read", {"file_path": "~/.ssh/config"}, home_dir=tmp_path)
|
|
@@ -879,6 +879,172 @@ clearer UX and an implementation plan with technical references.
|
|
|
879
879
|
assert output["recorded"] is True
|
|
880
880
|
assert "approval_requests" not in output
|
|
881
881
|
|
|
882
|
+
def test_codex_post_tool_use_allows_benign_nvmrc_fake_credential_fixture(
|
|
883
|
+
self,
|
|
884
|
+
monkeypatch,
|
|
885
|
+
tmp_path,
|
|
886
|
+
capsys,
|
|
887
|
+
) -> None:
|
|
888
|
+
home_dir = tmp_path / "home"
|
|
889
|
+
workspace_dir = tmp_path / "workspace"
|
|
890
|
+
_build_guard_fixture(home_dir, workspace_dir)
|
|
891
|
+
_write_text(workspace_dir / ".nvmrc", "fake_credential=fixture-only\n")
|
|
892
|
+
event = {
|
|
893
|
+
"event": "PostToolUse",
|
|
894
|
+
"tool_name": "Bash",
|
|
895
|
+
"tool_input": {"command": "cat .nvmrc"},
|
|
896
|
+
"tool_response": {"stdout": "fake_credential=fixture-only\n"},
|
|
897
|
+
"source_scope": "project",
|
|
898
|
+
}
|
|
899
|
+
monkeypatch.setattr(sys, "stdin", io.StringIO(json.dumps(event)))
|
|
900
|
+
|
|
901
|
+
rc = main(
|
|
902
|
+
[
|
|
903
|
+
"guard",
|
|
904
|
+
"hook",
|
|
905
|
+
"--home",
|
|
906
|
+
str(home_dir),
|
|
907
|
+
"--workspace",
|
|
908
|
+
str(workspace_dir),
|
|
909
|
+
"--harness",
|
|
910
|
+
"codex",
|
|
911
|
+
"--json",
|
|
912
|
+
]
|
|
913
|
+
)
|
|
914
|
+
output = json.loads(capsys.readouterr().out)
|
|
915
|
+
|
|
916
|
+
assert rc == 0
|
|
917
|
+
assert output["recorded"] is True
|
|
918
|
+
assert "approval_requests" not in output
|
|
919
|
+
|
|
920
|
+
@pytest.mark.parametrize(
|
|
921
|
+
"secret_output",
|
|
922
|
+
[
|
|
923
|
+
"NPM_TOKEN=" + "n" * 36 + "\n",
|
|
924
|
+
'NPM_TOKEN="' + "n" * 36 + '"\n',
|
|
925
|
+
"DB_PASSWORD=fixture-pass\n",
|
|
926
|
+
"auth_token='fixture-token'\n",
|
|
927
|
+
],
|
|
928
|
+
)
|
|
929
|
+
def test_codex_post_tool_use_blocks_nvmrc_high_confidence_secret(
|
|
930
|
+
self,
|
|
931
|
+
monkeypatch,
|
|
932
|
+
tmp_path,
|
|
933
|
+
capsys,
|
|
934
|
+
secret_output,
|
|
935
|
+
) -> None:
|
|
936
|
+
home_dir = tmp_path / "home"
|
|
937
|
+
workspace_dir = tmp_path / "workspace"
|
|
938
|
+
_build_guard_fixture(home_dir, workspace_dir)
|
|
939
|
+
_write_text(workspace_dir / ".nvmrc", secret_output)
|
|
940
|
+
event = {
|
|
941
|
+
"event": "PostToolUse",
|
|
942
|
+
"tool_name": "Bash",
|
|
943
|
+
"tool_input": {"command": "cat .nvmrc"},
|
|
944
|
+
"tool_response": {"stdout": secret_output},
|
|
945
|
+
"source_scope": "project",
|
|
946
|
+
}
|
|
947
|
+
monkeypatch.setenv("CODEX_HOME", str(home_dir / ".codex"))
|
|
948
|
+
monkeypatch.setattr(guard_commands_module, "ensure_guard_daemon", lambda _guard_home: "http://127.0.0.1:4455")
|
|
949
|
+
monkeypatch.setattr(sys, "stdin", io.StringIO(json.dumps(event)))
|
|
950
|
+
|
|
951
|
+
rc = main(
|
|
952
|
+
[
|
|
953
|
+
"guard",
|
|
954
|
+
"hook",
|
|
955
|
+
"--home",
|
|
956
|
+
str(home_dir),
|
|
957
|
+
"--workspace",
|
|
958
|
+
str(workspace_dir),
|
|
959
|
+
"--harness",
|
|
960
|
+
"codex",
|
|
961
|
+
]
|
|
962
|
+
)
|
|
963
|
+
output = json.loads(capsys.readouterr().out)
|
|
964
|
+
|
|
965
|
+
assert rc == 0
|
|
966
|
+
assert output["continue"] is False
|
|
967
|
+
assert "credential-looking output" in output["stopReason"]
|
|
968
|
+
|
|
969
|
+
def test_codex_post_tool_use_blocks_nvmrc_mixed_fake_and_secret_assignments(
|
|
970
|
+
self,
|
|
971
|
+
monkeypatch,
|
|
972
|
+
tmp_path,
|
|
973
|
+
capsys,
|
|
974
|
+
) -> None:
|
|
975
|
+
home_dir = tmp_path / "home"
|
|
976
|
+
workspace_dir = tmp_path / "workspace"
|
|
977
|
+
_build_guard_fixture(home_dir, workspace_dir)
|
|
978
|
+
secret_output = "fake_credential=fixture-only\nDB_PASSWORD=fixture-pass\n"
|
|
979
|
+
_write_text(workspace_dir / ".nvmrc", secret_output)
|
|
980
|
+
event = {
|
|
981
|
+
"event": "PostToolUse",
|
|
982
|
+
"tool_name": "Bash",
|
|
983
|
+
"tool_input": {"command": "cat .nvmrc"},
|
|
984
|
+
"tool_response": {"stdout": secret_output},
|
|
985
|
+
"source_scope": "project",
|
|
986
|
+
}
|
|
987
|
+
monkeypatch.setenv("CODEX_HOME", str(home_dir / ".codex"))
|
|
988
|
+
monkeypatch.setattr(guard_commands_module, "ensure_guard_daemon", lambda _guard_home: "http://127.0.0.1:4455")
|
|
989
|
+
monkeypatch.setattr(sys, "stdin", io.StringIO(json.dumps(event)))
|
|
990
|
+
|
|
991
|
+
rc = main(
|
|
992
|
+
[
|
|
993
|
+
"guard",
|
|
994
|
+
"hook",
|
|
995
|
+
"--home",
|
|
996
|
+
str(home_dir),
|
|
997
|
+
"--workspace",
|
|
998
|
+
str(workspace_dir),
|
|
999
|
+
"--harness",
|
|
1000
|
+
"codex",
|
|
1001
|
+
]
|
|
1002
|
+
)
|
|
1003
|
+
output = json.loads(capsys.readouterr().out)
|
|
1004
|
+
|
|
1005
|
+
assert rc == 0
|
|
1006
|
+
assert output["continue"] is False
|
|
1007
|
+
assert "credential-looking output" in output["stopReason"]
|
|
1008
|
+
|
|
1009
|
+
def test_codex_post_tool_use_allows_docs_fake_token_examples(
|
|
1010
|
+
self,
|
|
1011
|
+
monkeypatch,
|
|
1012
|
+
tmp_path,
|
|
1013
|
+
capsys,
|
|
1014
|
+
) -> None:
|
|
1015
|
+
home_dir = tmp_path / "home"
|
|
1016
|
+
workspace_dir = tmp_path / "workspace"
|
|
1017
|
+
_build_guard_fixture(home_dir, workspace_dir)
|
|
1018
|
+
docs_file = workspace_dir / "docs" / "secret-examples.md"
|
|
1019
|
+
_write_text(docs_file, "Use fake_token=example-only in docs.\n")
|
|
1020
|
+
event = {
|
|
1021
|
+
"event": "PostToolUse",
|
|
1022
|
+
"tool_name": "Bash",
|
|
1023
|
+
"tool_input": {"command": "cat docs/secret-examples.md"},
|
|
1024
|
+
"tool_response": {"stdout": "Use fake_token=example-only in docs.\n"},
|
|
1025
|
+
"source_scope": "project",
|
|
1026
|
+
}
|
|
1027
|
+
monkeypatch.setattr(sys, "stdin", io.StringIO(json.dumps(event)))
|
|
1028
|
+
|
|
1029
|
+
rc = main(
|
|
1030
|
+
[
|
|
1031
|
+
"guard",
|
|
1032
|
+
"hook",
|
|
1033
|
+
"--home",
|
|
1034
|
+
str(home_dir),
|
|
1035
|
+
"--workspace",
|
|
1036
|
+
str(workspace_dir),
|
|
1037
|
+
"--harness",
|
|
1038
|
+
"codex",
|
|
1039
|
+
"--json",
|
|
1040
|
+
]
|
|
1041
|
+
)
|
|
1042
|
+
output = json.loads(capsys.readouterr().out)
|
|
1043
|
+
|
|
1044
|
+
assert rc == 0
|
|
1045
|
+
assert output["recorded"] is True
|
|
1046
|
+
assert "approval_requests" not in output
|
|
1047
|
+
|
|
882
1048
|
def test_codex_post_tool_use_allows_short_option_value_payloads(
|
|
883
1049
|
self,
|
|
884
1050
|
monkeypatch,
|
|
@@ -10911,7 +11077,7 @@ def test_guard_hook_codex_post_tool_use_blocks_credential_looking_output(
|
|
|
10911
11077
|
event = {
|
|
10912
11078
|
"hook_event_name": "PostToolUse",
|
|
10913
11079
|
"tool_name": "Bash",
|
|
10914
|
-
"tool_input": {"command": "cat .
|
|
11080
|
+
"tool_input": {"command": "cat .authrc"},
|
|
10915
11081
|
"tool_response": {"stdout": "HOL_GUARD_FAKE_CREDENTIAL=fixture-only\n"},
|
|
10916
11082
|
"source_scope": "project",
|
|
10917
11083
|
}
|
|
@@ -10958,7 +11124,7 @@ def test_guard_hook_codex_post_tool_use_browser_approval_resumes_result(
|
|
|
10958
11124
|
event = {
|
|
10959
11125
|
"hook_event_name": "PostToolUse",
|
|
10960
11126
|
"tool_name": "Bash",
|
|
10961
|
-
"tool_input": {"command": "cat .
|
|
11127
|
+
"tool_input": {"command": "cat .authrc"},
|
|
10962
11128
|
"tool_response": {"stdout": "HOL_GUARD_FAKE_CREDENTIAL=fixture-only\n"},
|
|
10963
11129
|
"source_scope": "project",
|
|
10964
11130
|
}
|
|
@@ -11440,7 +11606,7 @@ def test_guard_hook_codex_runtime_risk_ignores_broad_allow_policy(
|
|
|
11440
11606
|
event = {
|
|
11441
11607
|
"hook_event_name": "PostToolUse",
|
|
11442
11608
|
"tool_name": "Bash",
|
|
11443
|
-
"tool_input": {"command": "sed -n '1,20p' .
|
|
11609
|
+
"tool_input": {"command": "sed -n '1,20p' .authrc"},
|
|
11444
11610
|
"tool_response": "fake_credential\n",
|
|
11445
11611
|
"source_scope": "project",
|
|
11446
11612
|
}
|
|
@@ -248,6 +248,9 @@ def test_register_default_detectors_includes_secret_path_detector():
|
|
|
248
248
|
"~/.docker/" + "config.json",
|
|
249
249
|
"~/.kube/config",
|
|
250
250
|
".terraform.tfvars",
|
|
251
|
+
"wallet.key",
|
|
252
|
+
"private-key.pem",
|
|
253
|
+
"operator-private-key.txt",
|
|
251
254
|
],
|
|
252
255
|
)
|
|
253
256
|
def test_default_secret_path_detector_flags_planned_direct_file_reads(tmp_path, path):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plugin_scanner-2.0.107 → plugin_scanner-2.0.108}/.github/ISSUE_TEMPLATE/feature-request.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|