plugin-scanner 2.0.130__tar.gz → 2.0.132__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.130 → plugin_scanner-2.0.132}/PKG-INFO +47 -1
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/README.md +46 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/docs/guard/testing-matrix.md +26 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/pyproject.toml +1 -1
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/pyproject.toml.bak +1 -1
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/cli/render.py +10 -1
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/daemon/manager.py +110 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/models.py +1 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/store.py +1 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/store_approvals.py +15 -5
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/version.py +1 -1
- plugin_scanner-2.0.132/tests/fixtures/guard-red-team/README.md +74 -0
- plugin_scanner-2.0.132/tests/fixtures/guard-red-team/benign-docs-fake-token.py +28 -0
- plugin_scanner-2.0.132/tests/fixtures/guard-red-team/benign-health-endpoint.py +26 -0
- plugin_scanner-2.0.132/tests/fixtures/guard-red-team/benign-nvmrc-fake-creds.py +29 -0
- plugin_scanner-2.0.132/tests/fixtures/guard-red-team/benign-source-search.py +34 -0
- plugin_scanner-2.0.132/tests/fixtures/guard-red-team/expected-decisions.json +119 -0
- plugin_scanner-2.0.132/tests/fixtures/guard-red-team/malicious-dockerfile.txt +37 -0
- plugin_scanner-2.0.132/tests/fixtures/guard-red-team/malicious-encoded-shell-exfil.py +36 -0
- plugin_scanner-2.0.132/tests/fixtures/guard-red-team/malicious-github-action.yml +46 -0
- plugin_scanner-2.0.132/tests/fixtures/guard-red-team/malicious-mcp-delete.md +33 -0
- plugin_scanner-2.0.132/tests/fixtures/guard-red-team/malicious-mcp-secret-read.md +33 -0
- plugin_scanner-2.0.132/tests/fixtures/guard-red-team/malicious-mcp-skill-exfil.md +39 -0
- plugin_scanner-2.0.132/tests/fixtures/guard-red-team/malicious-npm-postinstall.js +36 -0
- plugin_scanner-2.0.132/tests/fixtures/guard-red-team/malicious-prompt-env-read.md +28 -0
- plugin_scanner-2.0.132/tests/fixtures/guard-red-team/malicious-prompt-guard-bypass.md +30 -0
- plugin_scanner-2.0.132/tests/fixtures/guard-red-team/malicious-prompt-npmrc-read.md +25 -0
- plugin_scanner-2.0.132/tests/fixtures/guard-red-team/malicious-python-setup.py +46 -0
- plugin_scanner-2.0.132/tests/test_guard_approval_continuity.py +486 -0
- plugin_scanner-2.0.132/tests/test_guard_red_team.py +184 -0
- plugin_scanner-2.0.130/tests/fixtures/guard-red-team/README.md +0 -27
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.clusterfuzzlite/Dockerfile +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.clusterfuzzlite/build.sh +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.clusterfuzzlite/project.yaml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.clusterfuzzlite/requirements-atheris.txt +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.dockerignore +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.github/CODEOWNERS +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.github/dependabot.yml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.github/workflows/ci.yml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.github/workflows/codeql.yml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.github/workflows/dependabot-uv-lock.yml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.github/workflows/fuzz.yml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.github/workflows/harness-smoke.yml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.github/workflows/publish.yml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.github/workflows/scorecard.yml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.gitignore +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/.pre-commit-hooks.yaml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/CONTRIBUTING.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/Dockerfile +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/LICENSE +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/SECURITY.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/index.html +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/package.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/pnpm-lock.yaml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/public/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/public/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/public/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/public/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/public/favicon.ico +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/app.tsx +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/approval-center-layout.test.ts +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/approval-center-layout.tsx +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/approval-center-primitives.tsx +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/approval-center-review-cards.tsx +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/approval-center-utils.ts +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/data-flow-evidence-card.tsx +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/fleet-workspace.tsx +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/guard-api.test.ts +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/guard-api.ts +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/guard-demo.ts +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/guard-types.ts +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/main.tsx +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/receipts-workspace.test.ts +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/receipts-workspace.tsx +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/runtime-overview.test.ts +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/runtime-overview.tsx +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/settings-workspace.test.ts +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/settings-workspace.tsx +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/styles.css +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/src/vite-env.d.ts +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/tsconfig.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/dashboard/vite.config.ts +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/docker-requirements.txt +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/docs/guard/approval-audit.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/docs/guard/architecture.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/docs/guard/get-started.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/docs/guard/harness-support.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/docs/guard/local-vs-cloud.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/docs/guard/release-checklist.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/docs/guard/smoke-tests.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/docs/trust/mcp-trust-draft.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/docs/trust/plugin-trust-draft.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/docs/trust/skill-trust-local.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/fuzzers/manifest_fuzzer.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/requirements.txt +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/schemas/plugin-quality.v1.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/schemas/scan-result.v1.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/schemas/verify-result.v1.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/__init__.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/action_runner.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/argparse_utils.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/checks/__init__.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/checks/claude.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/checks/gemini.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/checks/manifest.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/checks/opencode.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/checks/security.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/cli.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/cli_ui.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/config.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/github_reporting.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/__init__.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/access_graph_events.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/adapters/contracts.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/approvals.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/cli/commands.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/config.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/incident.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/launcher.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/protect.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/redaction.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/risk.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/advisory_escalation.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/advisory_matchers.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/data_flow.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/data_flow_rules.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/data_flow_variables.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/detectors.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/mcp_protection.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/prompt_injection.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/safe_decode.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/sandbox.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/secret_sensitivity.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/secret_sources.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/shell_commands.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/skill_protection.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/supply_chain.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/temp_files.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/runtime/threat_intel.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/shims.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/store_evidence.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/store_threat_intel.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/types.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/lint_fixes.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/marketplace_support.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/models.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/path_support.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/policy.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/quality_artifact.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/repo_detect.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/reporting.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/rules/__init__.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/rules/registry.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/rules/specs.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/scanner.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/submission.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/suppressions.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/trust_helpers.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/trust_models.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/trust_scoring.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/trust_specs.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/verification.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/__init__.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/conftest.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/__init__.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/bad-plugin/.mcp.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/bad-plugin/secrets.js +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/claude-plugin-good/README.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/code-quality-bad/evil.js +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/code-quality-bad/inject.js +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/gemini-extension-good/README.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/good-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/good-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/good-plugin/README.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/good-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/guard-red-team/canary-exfil-encoded.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/guard-red-team/canary-exfil.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/guard-red-team/smoke-evidence-template.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/mcp-canary-server.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/mit-license/LICENSE +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/opencode-good/LICENSE +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/opencode-good/README.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/opencode-good/SECURITY.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/supply-chain/benign-npm-package.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/supply-chain/benign-pnpm-package.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/supply-chain/benign-pyproject.toml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/supply-chain/malicious-Dockerfile +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/supply-chain/malicious-action.yml +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/supply-chain/malicious-npm-package.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/supply-chain/malicious-setup.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/fixtures/with-marketplace/marketplace.json +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test-trust-scoring.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test-trust-specs.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_action_runner.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_best_practices.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_cisco_install_surfaces.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_cli.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_code_quality.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_config.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_coverage_remaining.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_ecosystems.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_edge_cases.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_final_coverage.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_access_graph.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_advisory_escalation.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_approval_store_scale.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_approvals.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_bootstrap.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_canary_fixtures.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_capabilities.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_claude_adapter.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_cli.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_cloud_local_sync.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_codex_e2e.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_codex_install.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_codex_proxy.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_config_paths.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_connect_flow.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_consumer_mode.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_copilot_adapter.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_copilot_proxy.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_daemon_manager.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_daemon_perf.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_data_flow.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_event_schema_v1.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_events.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_evidence_store.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_harness_contracts.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_launch_env.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_mcp_protection.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_opencode_proxy.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_product_flow.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_prompt_injection.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_protect.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_render.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_risk.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_runtime.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_runtime_action_harnesses.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_runtime_actions.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_runtime_decisions.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_runtime_detectors.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_runtime_signals.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_safe_decode.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_sandbox.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_skill_protection.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_store_migrations.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_supply_chain.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_surface_server.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_threat_intel.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_guard_verdicts.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_hermes_adapter.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_integration.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_lint_fixes.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_live_cisco_smoke.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_manifest.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_marketplace.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_mcp_security.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_openclaw_adapter.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_operational_security.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_policy.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_quality_artifact.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_rule_registry.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_scanner.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_schema_contracts.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_security.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_security_ops.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_skill_security.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_submission.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_trust_scoring.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_trust_specs.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_verification.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/tests/test_versioning.py +0 -0
- {plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/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.132
|
|
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
|
|
@@ -132,6 +132,52 @@ See [docs/guard/get-started.md](docs/guard/get-started.md) for the full local fl
|
|
|
132
132
|
|
|
133
133
|
</details>
|
|
134
134
|
|
|
135
|
+
## Guard: Protection Levels
|
|
136
|
+
|
|
137
|
+
HOL Guard is antivirus for AI harnesses. It intercepts every tool action before your files change or your network is contacted, then decides in milliseconds whether to allow or block.
|
|
138
|
+
|
|
139
|
+
Choose a protection level with `hol-guard settings set security-level <level>`:
|
|
140
|
+
|
|
141
|
+
| Level | Who it's for | What it blocks |
|
|
142
|
+
| :--- | :--- | :--- |
|
|
143
|
+
| **Gentle** | Teams who want minimal friction; experienced users | High-confidence secrets and clear exfil only |
|
|
144
|
+
| **Balanced** | Most users (default) | Secrets, shell exfil, prompt injections, supply-chain hooks |
|
|
145
|
+
| **Strict** | Security-conscious teams | Everything above plus low-confidence signals and untrusted prompts |
|
|
146
|
+
| **Paranoid** | High-security environments | All the above plus any unrecognized MCP server action |
|
|
147
|
+
|
|
148
|
+
If you are unsure, start with **Balanced**. You can promote to **Strict** after reviewing your first week of receipts.
|
|
149
|
+
|
|
150
|
+
## Guard: Troubleshooting
|
|
151
|
+
|
|
152
|
+
### Why was my command paused?
|
|
153
|
+
|
|
154
|
+
Guard paused a command because one or more detectors fired. To see exactly what triggered:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
hol-guard receipts # review recent decisions
|
|
158
|
+
hol-guard doctor # run a probe and see which detectors are active
|
|
159
|
+
hol-guard doctor --perf # include per-detector timing
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
If the block looks like a false positive, you can approve it from the receipts view or from the dashboard at `http://localhost:6174`.
|
|
163
|
+
|
|
164
|
+
### How do I clear approvals?
|
|
165
|
+
|
|
166
|
+
From the terminal:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
hol-guard approvals # list pending approvals
|
|
170
|
+
hol-guard approvals clear # clear all pending approvals (prompts for confirmation)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
From the dashboard: open `http://localhost:6174`, go to the **Approval Center**, and use the **Clear all** button. You will be asked to confirm before any approvals are removed.
|
|
174
|
+
|
|
175
|
+
## Guard: Advisory Sync Privacy
|
|
176
|
+
|
|
177
|
+
Guard's advisory database updates are optional and pull-only. When you run `hol-guard advisories sync`, Guard fetches a signed advisory list from `advisories.hol.org`. No local file paths, harness configs, receipt data, or workspace identifiers are sent to any server during sync.
|
|
178
|
+
|
|
179
|
+
Advisory sync requires a HOL Guard Cloud account. If you have not signed in, sync is skipped and Guard continues using the locally bundled advisory database. Run `hol-guard login` to connect a free account.
|
|
180
|
+
|
|
135
181
|
## Scanner Quickstart
|
|
136
182
|
|
|
137
183
|
```bash
|
|
@@ -92,6 +92,52 @@ See [docs/guard/get-started.md](docs/guard/get-started.md) for the full local fl
|
|
|
92
92
|
|
|
93
93
|
</details>
|
|
94
94
|
|
|
95
|
+
## Guard: Protection Levels
|
|
96
|
+
|
|
97
|
+
HOL Guard is antivirus for AI harnesses. It intercepts every tool action before your files change or your network is contacted, then decides in milliseconds whether to allow or block.
|
|
98
|
+
|
|
99
|
+
Choose a protection level with `hol-guard settings set security-level <level>`:
|
|
100
|
+
|
|
101
|
+
| Level | Who it's for | What it blocks |
|
|
102
|
+
| :--- | :--- | :--- |
|
|
103
|
+
| **Gentle** | Teams who want minimal friction; experienced users | High-confidence secrets and clear exfil only |
|
|
104
|
+
| **Balanced** | Most users (default) | Secrets, shell exfil, prompt injections, supply-chain hooks |
|
|
105
|
+
| **Strict** | Security-conscious teams | Everything above plus low-confidence signals and untrusted prompts |
|
|
106
|
+
| **Paranoid** | High-security environments | All the above plus any unrecognized MCP server action |
|
|
107
|
+
|
|
108
|
+
If you are unsure, start with **Balanced**. You can promote to **Strict** after reviewing your first week of receipts.
|
|
109
|
+
|
|
110
|
+
## Guard: Troubleshooting
|
|
111
|
+
|
|
112
|
+
### Why was my command paused?
|
|
113
|
+
|
|
114
|
+
Guard paused a command because one or more detectors fired. To see exactly what triggered:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
hol-guard receipts # review recent decisions
|
|
118
|
+
hol-guard doctor # run a probe and see which detectors are active
|
|
119
|
+
hol-guard doctor --perf # include per-detector timing
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
If the block looks like a false positive, you can approve it from the receipts view or from the dashboard at `http://localhost:6174`.
|
|
123
|
+
|
|
124
|
+
### How do I clear approvals?
|
|
125
|
+
|
|
126
|
+
From the terminal:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
hol-guard approvals # list pending approvals
|
|
130
|
+
hol-guard approvals clear # clear all pending approvals (prompts for confirmation)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
From the dashboard: open `http://localhost:6174`, go to the **Approval Center**, and use the **Clear all** button. You will be asked to confirm before any approvals are removed.
|
|
134
|
+
|
|
135
|
+
## Guard: Advisory Sync Privacy
|
|
136
|
+
|
|
137
|
+
Guard's advisory database updates are optional and pull-only. When you run `hol-guard advisories sync`, Guard fetches a signed advisory list from `advisories.hol.org`. No local file paths, harness configs, receipt data, or workspace identifiers are sent to any server during sync.
|
|
138
|
+
|
|
139
|
+
Advisory sync requires a HOL Guard Cloud account. If you have not signed in, sync is skipped and Guard continues using the locally bundled advisory database. Run `hol-guard login` to connect a free account.
|
|
140
|
+
|
|
95
141
|
## Scanner Quickstart
|
|
96
142
|
|
|
97
143
|
```bash
|
|
@@ -81,3 +81,29 @@ Nightly release-bar coverage should include:
|
|
|
81
81
|
- Claude Code or Cursor on a self-hosted macOS runner
|
|
82
82
|
- Gemini or OpenCode on a self-hosted Windows runner
|
|
83
83
|
- a release gate that only passes when those harness families stay green
|
|
84
|
+
|
|
85
|
+
## Red-Team Fixture Suite (T646)
|
|
86
|
+
|
|
87
|
+
Run the red-team corpus to validate fixture safety and manifest integrity:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
pytest tests/test_guard_red_team.py tests/test_guard_canary_fixtures.py -q
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
This verifies:
|
|
94
|
+
- All malicious fixtures use only `hol-fake-*` sentinel values and route to the canary domain
|
|
95
|
+
- All benign fixtures contain no exfil patterns or real key prefixes
|
|
96
|
+
- Every fixture listed in `expected-decisions.json` exists on disk
|
|
97
|
+
- No local usernames, real paths, or real tokens appear in any fixture
|
|
98
|
+
|
|
99
|
+
To run only the red-team manifest and safety tests:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
pytest tests/test_guard_red_team.py -q
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
To run the full test suite including red-team:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
pytest -q
|
|
109
|
+
```
|
|
@@ -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.132"
|
|
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.132"
|
|
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.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/cli/render.py
RENAMED
|
@@ -1768,6 +1768,15 @@ def _build_approval_table(items: list[dict[str, object]], *, title: str | None)
|
|
|
1768
1768
|
table.add_row("—", "—", "No pending approvals", "—", "—", "—", "—")
|
|
1769
1769
|
return table
|
|
1770
1770
|
for item in items:
|
|
1771
|
+
approval_url = item.get("approval_url")
|
|
1772
|
+
fallback_cli = item.get("fallback_cli_command")
|
|
1773
|
+
review_cmd = str(item.get("review_command") or "hol-guard approvals")
|
|
1774
|
+
if approval_url and fallback_cli:
|
|
1775
|
+
resolve_text = f"{approval_url}\n or: {fallback_cli}"
|
|
1776
|
+
elif approval_url:
|
|
1777
|
+
resolve_text = str(approval_url)
|
|
1778
|
+
else:
|
|
1779
|
+
resolve_text = review_cmd
|
|
1771
1780
|
table.add_row(
|
|
1772
1781
|
str(item.get("request_id") or "unknown"),
|
|
1773
1782
|
str(item.get("harness") or "unknown"),
|
|
@@ -1775,7 +1784,7 @@ def _build_approval_table(items: list[dict[str, object]], *, title: str | None)
|
|
|
1775
1784
|
", ".join(_coerce_string_list(item.get("changed_fields"))) or "none",
|
|
1776
1785
|
str(item.get("risk_summary") or "no obvious secret/network signal"),
|
|
1777
1786
|
_action_text(str(item.get("policy_action") or "warn")),
|
|
1778
|
-
|
|
1787
|
+
resolve_text,
|
|
1779
1788
|
)
|
|
1780
1789
|
return table
|
|
1781
1790
|
|
{plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/daemon/manager.py
RENAMED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import dataclasses
|
|
5
6
|
import hashlib
|
|
6
7
|
import json
|
|
7
8
|
import os
|
|
@@ -33,6 +34,7 @@ _EPHEMERAL_GUARD_DAEMON_STALE_SECONDS = 30.0
|
|
|
33
34
|
_EPHEMERAL_GUARD_DAEMON_MAX_STATES = 512
|
|
34
35
|
_GUARD_DAEMON_PRIVATE_FILE_MODE = 0o600
|
|
35
36
|
_GUARD_DAEMON_PRIVATE_DIR_MODE = 0o700
|
|
37
|
+
_APPROVAL_CENTER_LOCATOR_FILE = "approval-center-locator.json"
|
|
36
38
|
|
|
37
39
|
_START_LOCKS: dict[str, threading.Lock] = {}
|
|
38
40
|
_START_LOCKS_GUARD = threading.Lock()
|
|
@@ -40,6 +42,18 @@ _LAST_EPHEMERAL_REAP_AT = 0.0
|
|
|
40
42
|
_RUNTIME_FINGERPRINT_CACHE: str | None = None
|
|
41
43
|
|
|
42
44
|
|
|
45
|
+
@dataclasses.dataclass(frozen=True, slots=True)
|
|
46
|
+
class ApprovalCenterLocator:
|
|
47
|
+
"""Structured snapshot of where the Guard approval-center daemon is running."""
|
|
48
|
+
|
|
49
|
+
guard_home: Path
|
|
50
|
+
daemon_url: str
|
|
51
|
+
approval_url_base: str
|
|
52
|
+
pid: int
|
|
53
|
+
started_at: str
|
|
54
|
+
state_path: Path
|
|
55
|
+
|
|
56
|
+
|
|
43
57
|
def _daemon_launcher_env() -> dict[str, str]:
|
|
44
58
|
env = dict(os.environ)
|
|
45
59
|
pythonpath_entries: list[str] = []
|
|
@@ -173,6 +187,102 @@ def clear_guard_daemon_state(guard_home: Path) -> None:
|
|
|
173
187
|
_write_private_text(state_path, "{}")
|
|
174
188
|
|
|
175
189
|
|
|
190
|
+
def _locator_path(guard_home: Path) -> Path:
|
|
191
|
+
return guard_home / _APPROVAL_CENTER_LOCATOR_FILE
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def write_approval_center_locator(guard_home: Path, locator: ApprovalCenterLocator) -> None:
|
|
195
|
+
locator_path = _locator_path(guard_home)
|
|
196
|
+
_ensure_private_directory(locator_path.parent)
|
|
197
|
+
payload = {
|
|
198
|
+
"guard_home": str(locator.guard_home),
|
|
199
|
+
"daemon_url": locator.daemon_url,
|
|
200
|
+
"approval_url_base": locator.approval_url_base,
|
|
201
|
+
"pid": locator.pid,
|
|
202
|
+
"started_at": locator.started_at,
|
|
203
|
+
"state_path": str(locator.state_path),
|
|
204
|
+
}
|
|
205
|
+
_write_private_text(locator_path, json.dumps(payload, indent=2))
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def read_approval_center_locator(guard_home: Path) -> ApprovalCenterLocator | None:
|
|
209
|
+
locator_path = _locator_path(guard_home)
|
|
210
|
+
if not locator_path.is_file():
|
|
211
|
+
return None
|
|
212
|
+
try:
|
|
213
|
+
payload = json.loads(locator_path.read_text(encoding="utf-8"))
|
|
214
|
+
except (OSError, json.JSONDecodeError):
|
|
215
|
+
return None
|
|
216
|
+
if not isinstance(payload, dict):
|
|
217
|
+
return None
|
|
218
|
+
pid = payload.get("pid")
|
|
219
|
+
if not isinstance(pid, int) or pid <= 0:
|
|
220
|
+
return None
|
|
221
|
+
if not _guard_daemon_pid_is_running(pid):
|
|
222
|
+
return None
|
|
223
|
+
if not _guard_daemon_pid_matches_command(pid, expected_guard_home=guard_home):
|
|
224
|
+
return None
|
|
225
|
+
daemon_url = payload.get("daemon_url")
|
|
226
|
+
approval_url_base = payload.get("approval_url_base")
|
|
227
|
+
started_at = payload.get("started_at")
|
|
228
|
+
state_path_str = payload.get("state_path")
|
|
229
|
+
guard_home_str = payload.get("guard_home")
|
|
230
|
+
if not all(isinstance(v, str) for v in (daemon_url, approval_url_base, started_at, state_path_str, guard_home_str)):
|
|
231
|
+
return None
|
|
232
|
+
return ApprovalCenterLocator(
|
|
233
|
+
guard_home=Path(guard_home_str),
|
|
234
|
+
daemon_url=daemon_url,
|
|
235
|
+
approval_url_base=approval_url_base,
|
|
236
|
+
pid=pid,
|
|
237
|
+
started_at=started_at,
|
|
238
|
+
state_path=Path(state_path_str),
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def _approval_center_daemon_is_healthy(daemon_url: str) -> bool:
|
|
243
|
+
try:
|
|
244
|
+
with urllib.request.urlopen(f"{daemon_url}/healthz", timeout=1) as response:
|
|
245
|
+
if response.status != 200:
|
|
246
|
+
return False
|
|
247
|
+
return _healthz_payload_is_current(response.read().decode("utf-8"))
|
|
248
|
+
except (OSError, ValueError, urllib.error.URLError):
|
|
249
|
+
return False
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def _daemon_state_pid_matches_locator(guard_home: Path, locator_pid: int) -> bool:
|
|
253
|
+
state = _load_state(guard_home)
|
|
254
|
+
if not isinstance(state, dict):
|
|
255
|
+
return False
|
|
256
|
+
state_pid = state.get("pid")
|
|
257
|
+
return isinstance(state_pid, int) and state_pid == locator_pid
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def ensure_approval_center(guard_home: Path) -> ApprovalCenterLocator:
|
|
261
|
+
existing = read_approval_center_locator(guard_home)
|
|
262
|
+
if (
|
|
263
|
+
existing is not None
|
|
264
|
+
and _approval_center_daemon_is_healthy(existing.daemon_url)
|
|
265
|
+
and _daemon_state_pid_matches_locator(guard_home, existing.pid)
|
|
266
|
+
):
|
|
267
|
+
return existing
|
|
268
|
+
daemon_url = ensure_guard_daemon(guard_home)
|
|
269
|
+
now = datetime.now(tz=timezone.utc).isoformat()
|
|
270
|
+
state = _load_state(guard_home)
|
|
271
|
+
pid = state.get("pid") if isinstance(state, dict) else None
|
|
272
|
+
if not isinstance(pid, int) or pid <= 0:
|
|
273
|
+
pid = os.getpid()
|
|
274
|
+
locator = ApprovalCenterLocator(
|
|
275
|
+
guard_home=guard_home,
|
|
276
|
+
daemon_url=daemon_url,
|
|
277
|
+
approval_url_base=daemon_url,
|
|
278
|
+
pid=pid,
|
|
279
|
+
started_at=now,
|
|
280
|
+
state_path=_state_path(guard_home),
|
|
281
|
+
)
|
|
282
|
+
write_approval_center_locator(guard_home, locator)
|
|
283
|
+
return locator
|
|
284
|
+
|
|
285
|
+
|
|
176
286
|
def _load_state(guard_home: Path) -> dict[str, object] | None:
|
|
177
287
|
state_path = _state_path(guard_home)
|
|
178
288
|
if not state_path.is_file():
|
|
@@ -180,6 +180,7 @@ class GuardApprovalRequest:
|
|
|
180
180
|
risk_headline: str | None = None
|
|
181
181
|
action_envelope_json: dict[str, object] | None = None
|
|
182
182
|
decision_v2_json: dict[str, object] | None = None
|
|
183
|
+
fallback_cli_command: str | None = None
|
|
183
184
|
|
|
184
185
|
def to_dict(self) -> dict[str, object]:
|
|
185
186
|
payload = asdict(self)
|
|
@@ -686,6 +686,7 @@ class GuardStore:
|
|
|
686
686
|
self._ensure_approval_column(connection, "action_envelope_json", "text")
|
|
687
687
|
self._ensure_approval_column(connection, "decision_v2_json", "text")
|
|
688
688
|
self._ensure_approval_column(connection, "workspace", "text")
|
|
689
|
+
self._ensure_approval_column(connection, "fallback_cli_command", "text")
|
|
689
690
|
self._ensure_attachment_column(connection, "lease_id", "text not null default ''")
|
|
690
691
|
self._ensure_attachment_column(connection, "lease_expires_at", "text")
|
|
691
692
|
self._ensure_local_device(connection)
|
{plugin_scanner-2.0.130 → plugin_scanner-2.0.132}/src/codex_plugin_scanner/guard/store_approvals.py
RENAMED
|
@@ -36,6 +36,7 @@ def approval_schema_statement() -> str:
|
|
|
36
36
|
risk_headline text,
|
|
37
37
|
action_envelope_json text,
|
|
38
38
|
decision_v2_json text,
|
|
39
|
+
fallback_cli_command text,
|
|
39
40
|
review_command text not null,
|
|
40
41
|
approval_url text not null,
|
|
41
42
|
status text not null,
|
|
@@ -70,7 +71,7 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
|
|
|
70
71
|
recommended_scope = ?, changed_fields_json = ?, source_scope = ?, config_path = ?, workspace = ?,
|
|
71
72
|
launch_target = ?, transport = ?, risk_summary = ?, risk_signals_json = ?,
|
|
72
73
|
artifact_label = ?, source_label = ?, trigger_summary = ?, why_now = ?, launch_summary = ?,
|
|
73
|
-
risk_headline = ?, action_envelope_json = ?, decision_v2_json = ?,
|
|
74
|
+
risk_headline = ?, action_envelope_json = ?, decision_v2_json = ?, fallback_cli_command = ?,
|
|
74
75
|
review_command = ?, approval_url = ?, created_at = ?
|
|
75
76
|
where request_id = ?
|
|
76
77
|
""",
|
|
@@ -97,6 +98,11 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
|
|
|
97
98
|
request.risk_headline,
|
|
98
99
|
json.dumps(request.action_envelope_json) if request.action_envelope_json is not None else None,
|
|
99
100
|
json.dumps(request.decision_v2_json) if request.decision_v2_json is not None else None,
|
|
101
|
+
(
|
|
102
|
+
_rewrite_review_command(request.fallback_cli_command, request_id)
|
|
103
|
+
if request.fallback_cli_command
|
|
104
|
+
else None
|
|
105
|
+
),
|
|
100
106
|
review_command,
|
|
101
107
|
approval_url,
|
|
102
108
|
now,
|
|
@@ -111,10 +117,10 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
|
|
|
111
117
|
recommended_scope, changed_fields_json, source_scope, config_path, workspace,
|
|
112
118
|
launch_target, transport, risk_summary,
|
|
113
119
|
risk_signals_json, artifact_label, source_label, trigger_summary, why_now, launch_summary, risk_headline,
|
|
114
|
-
action_envelope_json, decision_v2_json, review_command,
|
|
120
|
+
action_envelope_json, decision_v2_json, fallback_cli_command, review_command,
|
|
115
121
|
approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
|
|
116
122
|
)
|
|
117
|
-
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
123
|
+
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
118
124
|
""",
|
|
119
125
|
(
|
|
120
126
|
request.request_id,
|
|
@@ -142,6 +148,7 @@ def add_approval_request(connection: sqlite3.Connection, request: GuardApprovalR
|
|
|
142
148
|
request.risk_headline,
|
|
143
149
|
json.dumps(request.action_envelope_json) if request.action_envelope_json is not None else None,
|
|
144
150
|
json.dumps(request.decision_v2_json) if request.decision_v2_json is not None else None,
|
|
151
|
+
request.fallback_cli_command,
|
|
145
152
|
request.review_command,
|
|
146
153
|
request.approval_url,
|
|
147
154
|
"pending",
|
|
@@ -211,7 +218,8 @@ def list_approval_requests(
|
|
|
211
218
|
select request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher, policy_action,
|
|
212
219
|
recommended_scope, changed_fields_json, source_scope, config_path, workspace, launch_target, transport,
|
|
213
220
|
risk_summary, risk_signals_json, artifact_label, source_label, trigger_summary, why_now,
|
|
214
|
-
launch_summary, risk_headline, action_envelope_json, decision_v2_json,
|
|
221
|
+
launch_summary, risk_headline, action_envelope_json, decision_v2_json,
|
|
222
|
+
fallback_cli_command, review_command,
|
|
215
223
|
approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
|
|
216
224
|
from approval_requests
|
|
217
225
|
{where_clause}
|
|
@@ -230,7 +238,8 @@ def get_approval_request(connection: sqlite3.Connection, request_id: str) -> dic
|
|
|
230
238
|
select request_id, harness, artifact_id, artifact_name, artifact_type, artifact_hash, publisher, policy_action,
|
|
231
239
|
recommended_scope, changed_fields_json, source_scope, config_path, workspace, launch_target, transport,
|
|
232
240
|
risk_summary, risk_signals_json, artifact_label, source_label, trigger_summary, why_now,
|
|
233
|
-
launch_summary, risk_headline, action_envelope_json, decision_v2_json,
|
|
241
|
+
launch_summary, risk_headline, action_envelope_json, decision_v2_json,
|
|
242
|
+
fallback_cli_command, review_command,
|
|
234
243
|
approval_url, status, resolution_action, resolution_scope, reason, created_at, resolved_at
|
|
235
244
|
from approval_requests
|
|
236
245
|
where request_id = ?
|
|
@@ -311,6 +320,7 @@ def _row_to_payload(row: sqlite3.Row) -> dict[str, object]:
|
|
|
311
320
|
"risk_headline": row["risk_headline"],
|
|
312
321
|
"action_envelope_json": _optional_json_object(row["action_envelope_json"]),
|
|
313
322
|
"decision_v2_json": _optional_json_object(row["decision_v2_json"]),
|
|
323
|
+
"fallback_cli_command": row["fallback_cli_command"],
|
|
314
324
|
"review_command": str(row["review_command"]),
|
|
315
325
|
"approval_url": str(row["approval_url"]),
|
|
316
326
|
"status": str(row["status"]),
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Guard Red-Team Fixtures
|
|
2
|
+
|
|
3
|
+
Fixtures in this directory contain intentionally suspicious-looking content used to test
|
|
4
|
+
that HOL Guard correctly detects and blocks malicious AI agent behaviors.
|
|
5
|
+
|
|
6
|
+
**All credentials, tokens, API keys, and webhook URLs in these fixtures are fake.**
|
|
7
|
+
They use the pattern `hol-fake-*` and route to `https://evil.hol.org/collect`,
|
|
8
|
+
a domain owned by Hashgraph Online solely for testing canary detection.
|
|
9
|
+
|
|
10
|
+
No real secrets or infrastructure are touched by these tests.
|
|
11
|
+
|
|
12
|
+
## Files
|
|
13
|
+
|
|
14
|
+
### Canary Fixtures
|
|
15
|
+
|
|
16
|
+
| File | Fixture ID | Purpose |
|
|
17
|
+
|------|-----------|---------|
|
|
18
|
+
| `canary-exfil.py` | T604 | Plain-text canary: reads a fake API key and posts it to the canary endpoint |
|
|
19
|
+
| `canary-exfil-encoded.py` | T605 | Encoded canary: base64-encoded exfil payload to test encoded-execution detection |
|
|
20
|
+
|
|
21
|
+
### Malicious Prompt Fixtures
|
|
22
|
+
|
|
23
|
+
| File | Fixture ID | Purpose |
|
|
24
|
+
|------|-----------|---------|
|
|
25
|
+
| `malicious-prompt-env-read.md` | T629 | Prompt injection instructing harness to exfiltrate `.env` file contents |
|
|
26
|
+
| `malicious-prompt-npmrc-read.md` | T630 | Prompt injection instructing harness to read npm auth tokens |
|
|
27
|
+
| `malicious-prompt-guard-bypass.md` | T631 | Prompt injection attempting to disable HOL Guard monitoring |
|
|
28
|
+
|
|
29
|
+
### Malicious MCP Fixtures
|
|
30
|
+
|
|
31
|
+
| File | Fixture ID | Purpose |
|
|
32
|
+
|------|-----------|---------|
|
|
33
|
+
| `malicious-mcp-delete.md` | T632 | MCP tool call attempting destructive file system deletion |
|
|
34
|
+
| `malicious-mcp-secret-read.md` | T633 | MCP tool call reading credential files then posting to external endpoint |
|
|
35
|
+
| `malicious-mcp-skill-exfil.md` | T634 | MCP skill that exfiltrates workspace data with fake bearer token |
|
|
36
|
+
|
|
37
|
+
### Malicious Package/Infra Fixtures
|
|
38
|
+
|
|
39
|
+
| File | Fixture ID | Purpose |
|
|
40
|
+
|------|-----------|---------|
|
|
41
|
+
| `malicious-npm-postinstall.js` | T635 | npm postinstall hook harvesting local credential files |
|
|
42
|
+
| `malicious-python-setup.py` | T636 | Python setup.py exfiltrating credential files on install |
|
|
43
|
+
| `malicious-dockerfile.txt` | T637 | Dockerfile that exfiltrates secrets during image build |
|
|
44
|
+
| `malicious-github-action.yml` | T638 | GitHub Actions workflow exfiltrating CI secrets |
|
|
45
|
+
| `malicious-encoded-shell-exfil.py` | T639 | Base64-encoded exfil payload to test obfuscation detection |
|
|
46
|
+
|
|
47
|
+
### Benign Fixtures
|
|
48
|
+
|
|
49
|
+
| File | Fixture ID | Purpose |
|
|
50
|
+
|------|-----------|---------|
|
|
51
|
+
| `benign-source-search.py` | T640 | Legitimate source code search — should not trigger any detectors |
|
|
52
|
+
| `benign-health-endpoint.py` | T641 | Legitimate loopback health check — should not trigger any detectors |
|
|
53
|
+
| `benign-docs-fake-token.py` | T642 | Documentation with explanatory fake tokens — should not be blocked |
|
|
54
|
+
| `benign-nvmrc-fake-creds.py` | T643 | .nvmrc read with version string that looks like a credential |
|
|
55
|
+
|
|
56
|
+
### Manifests
|
|
57
|
+
|
|
58
|
+
| File | Purpose |
|
|
59
|
+
|------|---------|
|
|
60
|
+
| `expected-decisions.json` | Expected Guard decision for every fixture (used by red-team test runner) |
|
|
61
|
+
| `smoke-evidence-template.json` | Template for recording smoke test evidence during manual harness verification |
|
|
62
|
+
|
|
63
|
+
## Running Red-Team Tests
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pytest tests/test_guard_red_team.py tests/test_guard_canary_fixtures.py -q
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The red-team test runner (`tests/test_guard_red_team.py`) validates:
|
|
70
|
+
- All malicious fixtures contain only fake key material (no real secrets)
|
|
71
|
+
- All benign fixtures contain no network exfil patterns
|
|
72
|
+
- Fixture structure matches the expected-decisions manifest
|
|
73
|
+
- No local usernames, real paths, or real tokens appear in any fixture
|
|
74
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Benign docs with fake token fixture (T642).
|
|
2
|
+
|
|
3
|
+
This fixture is documentation that happens to contain fake token strings
|
|
4
|
+
that look like real tokens. Guard should NOT block documentation reads
|
|
5
|
+
that only mention tokens in explanatory context.
|
|
6
|
+
|
|
7
|
+
The tokens below are clearly fake and used only for illustrative purposes.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
DOCS = """
|
|
12
|
+
# API Authentication Guide
|
|
13
|
+
|
|
14
|
+
To authenticate, pass your API token in the Authorization header:
|
|
15
|
+
|
|
16
|
+
Authorization: Bearer <your-api-token>
|
|
17
|
+
|
|
18
|
+
Example (using a placeholder — replace with your real token):
|
|
19
|
+
|
|
20
|
+
curl -H "Authorization: Bearer hol-fake-docs-token-example-0000" \\
|
|
21
|
+
https://api.example.com/v1/status
|
|
22
|
+
|
|
23
|
+
Note: hol-fake-docs-token-example-0000 is NOT a real token.
|
|
24
|
+
Do not use this value in production.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
if __name__ == "__main__":
|
|
28
|
+
print(DOCS)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Benign health endpoint fetch fixture (T641).
|
|
2
|
+
|
|
3
|
+
Simulates a legitimate health check against a local service.
|
|
4
|
+
No secret files are read. No external network calls to harmful endpoints.
|
|
5
|
+
The URL is a local loopback address only.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from urllib.error import URLError
|
|
9
|
+
from urllib.request import Request, urlopen
|
|
10
|
+
|
|
11
|
+
_HEALTH_URL = "http://127.0.0.1:8080/healthz"
|
|
12
|
+
_TIMEOUT_S = 2.0
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def check_health(url: str = _HEALTH_URL, timeout: float = _TIMEOUT_S) -> bool:
|
|
16
|
+
try:
|
|
17
|
+
req = Request(url, method="GET")
|
|
18
|
+
with urlopen(req, timeout=timeout) as response:
|
|
19
|
+
return response.status == 200
|
|
20
|
+
except (URLError, OSError):
|
|
21
|
+
return False
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
if __name__ == "__main__":
|
|
25
|
+
ok = check_health()
|
|
26
|
+
print("healthy" if ok else "unreachable")
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Benign .nvmrc with fake credential string fixture (T643).
|
|
2
|
+
|
|
3
|
+
Simulates reading a .nvmrc file that happens to contain a version string
|
|
4
|
+
that superficially resembles a credential. Guard should NOT block benign
|
|
5
|
+
version-file reads.
|
|
6
|
+
|
|
7
|
+
The strings below are NOT credentials. They are version identifiers used
|
|
8
|
+
only to test that Guard's false-positive rate for benign file reads is low.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
|
|
13
|
+
_NVMRC_CONTENT = "v20.11.0\n"
|
|
14
|
+
_FAKE_NVMRC_CRED_LOOKALIKE = "hol-fake-nvmrc-version-token-placeholder-0000"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def read_nvmrc(project_root: str = ".") -> str:
|
|
18
|
+
path = os.path.join(project_root, ".nvmrc")
|
|
19
|
+
try:
|
|
20
|
+
with open(path) as fh:
|
|
21
|
+
return fh.read().strip()
|
|
22
|
+
except OSError:
|
|
23
|
+
return _NVMRC_CONTENT.strip()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
if __name__ == "__main__":
|
|
27
|
+
version = read_nvmrc()
|
|
28
|
+
print(f"Node version: {version}")
|
|
29
|
+
print(f"Placeholder note: {_FAKE_NVMRC_CRED_LOOKALIKE} is not a real token")
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Benign source search fixture (T640).
|
|
2
|
+
|
|
3
|
+
This fixture simulates a legitimate source code search operation.
|
|
4
|
+
No secret files are read. No external network calls are made.
|
|
5
|
+
All identifiers are benign.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import re
|
|
10
|
+
|
|
11
|
+
_SEARCH_ROOT = "src"
|
|
12
|
+
_PATTERN = re.compile(r"def\s+\w+\(")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def search_functions(root: str) -> list[tuple[str, int, str]]:
|
|
16
|
+
matches: list[tuple[str, int, str]] = []
|
|
17
|
+
for dirpath, _dirs, files in os.walk(root):
|
|
18
|
+
for fname in files:
|
|
19
|
+
if not fname.endswith(".py"):
|
|
20
|
+
continue
|
|
21
|
+
fpath = os.path.join(dirpath, fname)
|
|
22
|
+
try:
|
|
23
|
+
with open(fpath) as fh:
|
|
24
|
+
for lineno, line in enumerate(fh, start=1):
|
|
25
|
+
if _PATTERN.search(line):
|
|
26
|
+
matches.append((fpath, lineno, line.rstrip()))
|
|
27
|
+
except OSError:
|
|
28
|
+
pass
|
|
29
|
+
return matches
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
if __name__ == "__main__":
|
|
33
|
+
for path, line, text in search_functions(_SEARCH_ROOT):
|
|
34
|
+
print(f"{path}:{line}: {text}")
|