runlayer 0.31.2__tar.gz → 0.31.3__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.
- {runlayer-0.31.2 → runlayer-0.31.3}/AGENTS.md +1 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/PKG-INFO +1 -1
- {runlayer-0.31.2 → runlayer-0.31.3}/pyproject.toml +1 -1
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/aiwatch_config.py +22 -1
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/scan.py +41 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/setup.py +1 -1
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/error_classification.py +4 -16
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/flow_contract.py +19 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/clients.py +2 -2
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/dispatch.py +55 -23
- runlayer-0.31.3/runlayer_cli/hook/failure.py +205 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/messages.py +102 -12
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/plugin_context.py +6 -5
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/relay.py +18 -3
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/clients.py +1 -1
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/main.py +36 -2
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/launcher_inspection.py +1 -1
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/service.py +150 -9
- runlayer-0.31.3/tests/fixtures/managed_secret_display_cases.json +26 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_aiwatch_config_command.py +65 -15
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_cli.py +168 -8
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_daemon_runtime.py +28 -9
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_credential_rejection.py +144 -20
- runlayer-0.31.3/tests/test_hook_failure_origin.py +168 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_flow.py +33 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_install_module.py +18 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_messages.py +92 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_plugin_context.py +32 -16
- runlayer-0.31.3/tests/test_main_stdio_env.py +112 -0
- runlayer-0.31.3/tests/test_main_stdio_env_spawn.py +70 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_scan_service.py +167 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_scan_skills.py +93 -3
- runlayer-0.31.2/runlayer_cli/hook/failure.py +0 -80
- {runlayer-0.31.2 → runlayer-0.31.3}/.gitignore +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/.python-version +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/CLAUDE.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/LICENSE +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/Makefile +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/README.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/development.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/hooks/README.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/hooks/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/hooks/debug_hook_binary.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/hooks/runlayer-hook.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/DEPLOYMENT.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/README.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/_version_file.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/aiwatch.spec +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/aiwatch_uninstall.spec +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/assets/aiwatch-icon-512.png +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/assets/aiwatch.ico +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/container/Dockerfile +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/container/Dockerfile.dockerignore +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/container/k8s/README.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/container/k8s/configmap.yaml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/container/k8s/cronjob.yaml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/container/k8s/daemonset.yaml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/container/k8s/kustomization.yaml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/container/k8s/namespace.yaml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/container/k8s/secret.example.yaml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/container/scan-host-users.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/container/tests/README.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/container/tests/assert_inside_container.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/container/tests/run_smoke_test.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/container/tests/stub-aiwatch.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/install/install.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/install/install.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/install/tests/Install.Tests.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/install/tests/Invoke-Tests.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/install/tests/fixtures/targets-glibc2.17.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/install/tests/fixtures/targets.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/install/tests/test_install_sh.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/aiwatch-config.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/aiwatch-credentials.example +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/build_aiwatch_packages.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/build_onedir_manylinux.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/build_packages.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/cron.d-runlayer-aiwatch +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/cron.d-runlayer-cli +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/nfpm-aiwatch.yaml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/nfpm.yaml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/run-aiwatch-scan.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/run-aiwatch-update.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/run-cli-schedule.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/run-cli-update.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/salt/README.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/salt/pillar.example.sls +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/salt/runlayer-aiwatch/init.sls +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/salt/runlayer-aiwatch/templates/config.json.jinja +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/salt/runlayer-aiwatch/templates/credentials.jinja +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/tests/README.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/tests/assert_inside_container.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/tests/build_stub_packages.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/tests/check_package_markers.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/tests/ensure_host_nfpm.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/tests/run_smoke_tests.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/linux/tests/test_variant_suffix.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/adopt_keychain.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/build_pkg.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/build_pkg_runlayer.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/build_uninstall_pkg.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/com.runlayer.aiwatch.bootstrap.plist +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/com.runlayer.aiwatch.daemon.plist +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/com.runlayer.aiwatch.enroll.plist +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/com.runlayer.aiwatch.firefox-native-messaging-host.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/com.runlayer.aiwatch.jamf.schema.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/com.runlayer.aiwatch.mobileconfig +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/com.runlayer.aiwatch.native-messaging-host.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/com.runlayer.aiwatch.plist +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/com.runlayer.aiwatch.update.plist +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/com.runlayer.aiwatch.ws1.mobileconfig +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/com.runlayer.cli.mobileconfig +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/com.runlayer.cli.schedule.plist +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/com.runlayer.cli.update.plist +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/distribution.runlayer.xml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/distribution.xml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/entitlements.plist +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/scripts/postinstall +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/scripts/postinstall-runlayer +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/scripts/preinstall +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/scripts/preinstall-runlayer +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/uninstall-pkg/postinstall +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/uninstall-runlayer.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/macos/uninstall.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/py2exe/setup_py2exe.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/runlayer.spec +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/aiwatch-native-messaging-host.bat +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/aiwatch.wxs +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/build_hook_shim.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/build_intunewin.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/build_intunewin_runlayer.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/build_msi.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/build_msi_runlayer.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/cli-schedule-task/register-tasks.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/cli-schedule-task/unregister-tasks.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/cli-update-task/register-tasks.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/cli-update-task/unregister-tasks.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/custom-detection/detect-install.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/custom-detection/tests/DetectInstall.Tests.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/custom-detection/tests/Invoke-Tests.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/handoff-exec-test/emit_handoff_script.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/handoff-exec-test/run-handoff-exec-test.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/native-host-chromium.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/native-host-firefox.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/runlayer.wxs +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/scheduled-task/RunlayerTaskCommon.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/scheduled-task/register-tasks.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/scheduled-task/remove-hooks.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/scheduled-task/tests/CliScheduleTasks.Tests.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/scheduled-task/tests/CliUpdateTasks.Tests.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/scheduled-task/tests/Invoke-Tests.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/scheduled-task/tests/RemoveHooks.Tests.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/scheduled-task/tests/ScheduledTasks.Tests.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/scheduled-task/unregister-tasks.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/packaging/windows/scripts/bootstrap.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/regex-engine-allowlist.txt +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/aiwatch.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/aiwatch_checkin.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/aiwatch_config_cache.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/aiwatch_config_sync.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/aiwatch_credential.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/aiwatch_uninstall.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/api.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/catalog_client.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/catalog_enrichment.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/cli_persistence.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/command_contract.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/command_metrics.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/aiwatch_setup.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/aiwatch_update.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/auth.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/bootstrap.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/cache.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/catalog/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/catalog/commands.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/catalog/display.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/catalog/kinds.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/catalog/resolve.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/cli_update.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/credentials.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/decide_approval.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/deploy.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/doctor.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/enroll.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/hooks.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/interactive_find.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/keychain.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/logs.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/org_api_key.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/plugins.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/reconnect_account.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/reject_access_request.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/schedule.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/skills.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/status.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/terraform.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/update.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/update_privilege.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/update_scheduler.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/commands/url_handler.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/config.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/console.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/credential_store.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/daemon/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/daemon/runtime.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/daemon/server.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/daemon/status.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/daemon/windows_pipe.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/daemon/windows_scm.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/daemon/windows_service.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/deploy/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/deploy/config.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/deploy/docker_builder.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/deploy/schema_validation.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/deploy/service.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/enrollment.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/env_substitution.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/flow_delivery.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/flow_spool.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/flow_summary.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/flow_trace.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/__main__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/_transcript_stream_worker.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/copilot_cli_mcp_lookup.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/credential_state.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/daemon_client.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/daemon_protocol.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/file_policy.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/hook_io.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/host_override.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/log_silence.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/mcp_lookup.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/mcp_types.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/transcript_stream.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook/windsurf_payload.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/artifact_paths.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/browser_extension.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/browser_extensions.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/browser_policy.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/check.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/chromium_profile_health.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/config_backup.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/console_user.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/credential_gate.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/daemon_lifecycle.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/edge_extension.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/firefox_extension.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/llm_routing.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/paths.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/presence.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/safe_fs.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/hook_install/windows_browser_policy.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/http_error_utils.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/identity_forward.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/index.html +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/install_window.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/installer_common.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/linux_installer.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/logging.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/macos_installer.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/macos_test_device_config.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/managed_policy_publication.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/mdm_config.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/metrics.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/metrics_flush.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/middleware.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/models.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/models_api.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/models_mcp.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/native_messaging.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/oauth.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/oauth_callback.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/oauth_guidance.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/paths.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/platform_installers.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/plugins/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/plugins/claude_manifest.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/plugins/constants.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/plugins/discovery.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/plugins/installer.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/plugins/layouts.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/plugins/models.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/plugins/sync_engine.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/product.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/regex_safe.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/runtime.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/safe_parse.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agent_definition_scanner.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agent_scan.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agents/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agents/detect.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agents/discover.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agents/install.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agents/languages.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agents/manifests/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agents/manifests/_common.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agents/manifests/cargo.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agents/manifests/dotnet.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agents/manifests/go.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agents/manifests/jvm.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agents/manifests/npm.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agents/manifests/python.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agents/openclaw_detector.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agents/redact.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agents/registry.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agents/report.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/agents/signatures.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/artifact_cache.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/bin_shims.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/claude_code_plugins.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/cli_binaries.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/client_presence.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/clients.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/codex_plugins.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/completeness.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/concurrency.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/config_parser.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/config_redact.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/container_command.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/container_limits.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/containers/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/containers/collect.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/containers/collector.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/containers/docker_cli.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/containers/docker_socket.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/containers/inspect_parse.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/containers/k3s_cli.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/containers/proc_walk.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/containers/tar_walk.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/containers/windows_named_pipe.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/copilot_plugins.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/cursor_plugins.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/device.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/disguised_skills.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/file_collector.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/gemini_extensions.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/hidden_space_sweep.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/jetbrains_plugins.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/npm_global.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/opencode_plugins.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/orchestrator.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/pip_global.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/plugin_scanner.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/processes/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/processes/classify.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/processes/enumerate.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/processes/models.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/processes/probes.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/processes/redact.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/processes/settings_override.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/processes/windows_owner.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/project_scanner.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/project_tree_match.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/renamed_plugin_caches.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/resource_governor.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/run_lock.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/scan_state.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/scanner_primitives.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/skill_presence.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/skill_scanner.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/skip_dirs.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/symlink_follow.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/symlink_identity.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/timing.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/vscode_extensions.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/warp_sqlite.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/windows_users.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/wsl_exec.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/wsl_limits.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/wsl_paths.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/wsl_presence.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/wsl_projects.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/scan/wsl_runtime_signals.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skill_identifier/AGENTS.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skill_identifier/CLAUDE.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skill_identifier/README.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skill_identifier/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skill_identifier/hashing.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skill_identifier/merkle.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skill_identifier/skill_id.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skill_identifier/types.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skills/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skills/device_sync.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skills/discovery.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skills/frontmatter.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skills/installer.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skills/installer_core.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skills/marker.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skills/models.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skills/names.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skills/scan_summary.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/skills/sync_engine.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/symbols.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/sync.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/telemetry.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/terraform_export.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/tls.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/tolerant_json.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/truststore_init.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/update_contract.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/update_source.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/updater.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/uuid_utils.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/uv_tool_cleanup.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/variant.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/verified_local_proxy/README.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/verified_local_proxy/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/verified_local_proxy/config.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/verified_local_proxy/exceptions.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/verified_local_proxy/proxy.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/verified_local_proxy/verification/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/verified_local_proxy/verification/base.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/verified_local_proxy/verification/macos.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/verified_local_proxy/verification/windows.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/windows_installer.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/windows_installer_verifier.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/runlayer_cli/windows_update_handoff.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/scripts/check_published_hook_transport.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/scripts/check_regex_engine.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/scripts/smoke_installed_hooks.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/conftest.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/daemon_frame_helpers.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/cache/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/cache/test_cache.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/conftest.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/credentials/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/credentials/test_credentials.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/deploy/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/deploy/test_lifecycle.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/deploy/test_validate.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/client_specs/antigravity.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/client_specs/claude_code.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/client_specs/claude_desktop.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/client_specs/cline.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/client_specs/cline_cli.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/client_specs/codex.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/client_specs/cursor.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/client_specs/gemini_cli.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/client_specs/github_copilot_cli.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/client_specs/goose.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/client_specs/opencode.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/client_specs/vscode.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/client_specs/windsurf.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/client_specs/zed.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/.claude-plugin/marketplace.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/.claude-plugin/plugin.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/.lsp.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/.mcp.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/README.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/agents/README.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/agents/code-reviewer.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/commands/review.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/config.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/hooks/hooks.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/hooks/validate.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/notes.txt +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/scripts/deploy.sh +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/settings.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/skills/code-review/SKILL.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/skills/code-review/prompts.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/skills/ticket-triage/SKILL.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/skills/ticket-triage/helper.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/skills-v2/notes.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/skillsets/reference.md +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/fixtures/full_plugin/tool.ts +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/hooks/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/hooks/test_install_hooks.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/hooks/test_relay.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/org_api_key/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/org_api_key/test_org_api_key.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/plugins/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/plugins/test_add.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/plugins/test_mcp_fallback.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/plugins/test_push.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/run/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/run/test_run.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/scan/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/scan/conftest.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/scan/test_scan.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/scan/test_scan_lock_isolation.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/scan/test_scan_submit.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/setup/test_install_opencode.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/skills/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/skills/test_lifecycle.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/terraform/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/test_help_matrix.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/version/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/e2e/version/test_version.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/labels.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/non_agent/debug_adapter/adapter.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/non_agent/debug_adapter/pyproject.toml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/non_agent/flask_api/app.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/non_agent/flask_api/requirements.txt +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/non_agent/go_cli/go.mod +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/non_agent/go_cli/main.go +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/non_agent/node_web/package.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/non_agent/node_web/server.js +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_01/agent.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_01/pyproject.toml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_02/agent.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_02/pyproject.toml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_03/agent.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_03/pyproject.toml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_04/agent.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_04/pyproject.toml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_05/agent.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_05/pyproject.toml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_06/agent.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_06/pyproject.toml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_07/agent.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_07/pyproject.toml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_08/agent.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_08/pyproject.toml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_09/agent.ts +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_09/package.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_10/agent.ts +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_10/package.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_11/agent.ts +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_11/package.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_12/agent.ts +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_12/package.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_13/Cargo.toml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_13/main.rs +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_14/go.mod +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_14/main.go +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_15/Main.java +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_15/pom.xml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_16/Main.java +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_16/pom.xml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_17/Program.cs +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_17/SemanticKernelAgent.csproj +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_18/package.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/agent_detection/samples/sample_18/server.ts +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/claude_code_config.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/claude_desktop_config.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/container_command_cases.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/container_label_normalization_cases.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/cursor_config.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/devin_cli_config.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/empty_config.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/goose_config.yaml +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_dispatch/devin_cli/imported_claude_hook_guard.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_dispatch/devin_cli/lifecycle_events.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_dispatch/devin_cli/pre_tool_use_exec.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_dispatch/devin_cli/pre_tool_use_file_tools.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_dispatch/devin_cli/pre_tool_use_mcp.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/claude_code/event_hooks_matrix.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/claude_code/post_tool_failure_allow.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/claude_code/post_tool_failure_output_block.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/claude_code/post_tool_output_allow.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/claude_code/post_tool_output_block.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/claude_code/pre_tool_mcp_local_stdio_deny.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/claude_code/pre_tool_mcp_managed_proxy_allow.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/claude_code/pre_tool_native_bash_allow.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/claude_code/pre_tool_native_bash_deny.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/claude_code/pre_tool_read_env_deny.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/claude_code/user_prompt_submit_event.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/codex/event_hooks_matrix.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/codex/permission_request_allow.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/codex/permission_request_env_deny.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/codex/post_tool_event_allow.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/codex/post_tool_failure_allow.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/codex/post_tool_failure_output_block.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/codex/post_tool_output_block.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/codex/pre_tool_mcp_local_stdio_deny.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/codex/pre_tool_mcp_managed_proxy_allow.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/codex/pre_tool_native_bash_allow.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/codex/pre_tool_native_bash_deny.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/cursor/after_file_edit_event.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/cursor/before_mcp_direct_url_allow.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/cursor/before_mcp_local_stdio_deny.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/cursor/before_mcp_managed_proxy_allow.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/cursor/before_read_file_allow.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/cursor/before_read_file_env_deny.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/cursor/before_shell_execution_allow.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/cursor/before_shell_execution_env_deny.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/cursor/before_tab_file_read_allow.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/cursor/before_tab_file_read_mcp_config_deny.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/cursor/event_hooks_matrix.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/cursor/post_tool_use_allow.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/cursor/post_tool_use_failure_allow.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/cursor/post_tool_use_failure_output_block.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/cursor/post_tool_use_output_block.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/cursor/pre_tool_native_bash_allow_modified.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/cursor/pre_tool_native_bash_deny.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/hook_replay/cursor/stop_session_end_event.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/invalid_json.txt +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/junie_config.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/kilo_code_config.jsonc +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/kimi_code_config.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/macos_policy_reader.c +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/pi_config.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/roo_code_config.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/sse_server_config.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/vscode_config.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/fixtures/warp_config.json +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/frozen/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/frozen/conftest.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/frozen/test_frozen_credential.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/frozen/test_frozen_install.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/frozen/test_frozen_policy_publication.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/frozen/test_frozen_runlayer.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/hostile_inputs.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/macos_installer_helpers.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/platform_installer_helpers.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/plugin_installer_helpers.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/agents/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/agents/harness.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/agents/test_agent_scan.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/agents/test_detect.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/agents/test_discover.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/agents/test_eval.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/agents/test_manifests.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/agents/test_redact.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/agents/test_registry.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/agents/test_report.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/conftest.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/processes/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/processes/test_classify.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/processes/test_discovery.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/processes/test_enumerate.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/processes/test_probes.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/processes/test_redact.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/processes/test_settings_override.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/test_agent_definition_scanner.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/test_agent_scan.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/test_completeness.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/test_config_redact.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/test_container_command.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/test_containers.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/test_docker_socket.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/test_k3s.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/test_phase_isolation.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/test_presence_decode_hardening.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/test_runtime_decode_hardening.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/test_skip_dirs.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/test_windows_named_pipe.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/test_wsl_exec.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/test_wsl_paths.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/test_wsl_presence.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/test_wsl_projects.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/scan/test_wsl_runtime_signals.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/sign_shards_smoke.ps1 +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/skill_identifier/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/skill_identifier/test_merkle.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/skill_identifier/test_skill_id.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_aiwatch_basename_dispatch.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_aiwatch_bootstrap.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_aiwatch_checkin.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_aiwatch_checkin_batch.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_aiwatch_config_cache.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_aiwatch_config_isolation.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_aiwatch_config_sync.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_aiwatch_credential.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_aiwatch_daemon_dispatch.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_aiwatch_hook_shim_packaging.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_aiwatch_hook_version.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_aiwatch_imports.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_aiwatch_setup_hooks.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_aiwatch_uninstall.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_aiwatch_uninstall_packaging.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_aiwatch_update_command.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_api.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_artifact_cache.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_auth.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_backwards_compatibility.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_bin_shims.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_browser_extension_install.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_browser_extensions.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_cache.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_catalog_commands.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_catalog_enrichment.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_chromium_profile_health.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_claude_code_plugins.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_claude_json_integration.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_claude_output_replacement.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_cli_backwards_compat.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_cli_binaries.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_cli_linux_schedule_assets.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_cli_update_schedule_assets.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_client_presence.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_client_presence_evasion.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_command_contract.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_command_metrics.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_config.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_config_backup.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_container_label_contract.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_copilot_plugins.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_credential_store.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_credential_store_macos.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_credentials_commands.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_cursor_plugins.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_daemon_client.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_daemon_lifecycle.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_daemon_protocol.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_daemon_server.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_daemon_status.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_daemon_windows_pipe.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_debug_hook_binary.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_decide_approval.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_deploy_service.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_desktop_release_workflow.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_disguised_skills.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_dispatch_decode_hardening.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_docker_builder.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_docs_client_sync.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_doctor.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_edge_extension_install.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_endpoint_modes.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_enroll_checkins.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_enroll_command.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_enrollment.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_env_substitution.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_error_classification.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_firefox_extension_install.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_flow_contract.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_flow_delivery.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_flow_spool.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_flow_trace.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_gemini_extensions.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hidden_space_sweep.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_binary_convergence.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_dispatch_replay.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_flow_departed_harness.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_flow_harness_closed_stdout.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_flow_operations.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_host_override.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_install_console_user.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_install_mdm_scope.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_install_safe_fs.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_install_windows_safe_fs.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_io.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_python.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_replay_fixtures.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_script.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hook_shim_protocol.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_hooks_relay.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_identity_forward.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_install_window.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_interactive_find.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_jetbrains_plugins.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_keychain_adopt.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_keychain_guard.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_launcher_inspection.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_lazy_enrollment.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_legacy_re2_tag_coupling.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_linux_cron_assets.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_linux_installer.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_llm_routing.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_llm_routing_probe.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_llm_routing_reconcile.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_logging.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_logs.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_macos_config_profile_assets.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_macos_installer.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_macos_managed_policy_publication.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_macos_mdm_mode_compatibility.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_macos_plists.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_main_hook_dispatch.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_managed_policy_publication.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_manual_oauth.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_manylinux2014_lock_floor.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_mcp_lookup_decode_hardening.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_mdm_config.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_metrics.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_middleware.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_native_messaging.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_npm_global.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_oauth_browser_lock.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_oauth_callback_lifecycle.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_oauth_callback_port.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_oauth_error_guidance.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_oauth_sibling_wait.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_oauth_token_storage.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_opencode_plugins.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_org_api_key_commands.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_pip_global.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_platform_installers.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_plugin_layouts.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_plugin_scanner.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_plugins_commands.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_plugins_discovery.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_plugins_installer.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_plugins_installer_cursor_layout.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_plugins_sync.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_product.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_published_hook_transport.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_py310_compat.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_regex_parity.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_regex_safe_mirror_drift.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_renamed_plugin_caches.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_resource_governor.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_safe_parse.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_scan_clients.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_scan_concurrency.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_scan_detect_error_checkin.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_scan_device.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_scan_memory_caps.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_scan_no_findings.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_scan_openclaw.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_scan_parser.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_scan_project.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_scan_run_lock.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_scan_summary.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_scan_timing.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_scan_verbose.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_scan_windows_profile.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_scanner_primitives.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_schedule_command.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_setup_hooks.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_setup_install_claude_desktop.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_setup_install_config_formats.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_setup_install_local_servers.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_setup_sync.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_skill_names.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_skill_presence.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_skill_sync_credentials.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_skills_commands.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_skills_device_sync.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_skills_discovery.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_skills_installer.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_skills_installer_core.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_skills_marker.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_skills_sync.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_skills_sync_command.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_status.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_symbols.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_sync.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_telemetry.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_terraform_commands.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_test_device_config.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_tls.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_transcript_decode_hardening.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_truststore_init.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_update_commands.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_update_contract.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_update_privilege.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_update_source.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_updater.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_url_handler.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_uv_tool_cleanup.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_variant.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_variant_packaging_contract.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_version_file.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_vscode_extensions.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_warp_sqlite.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_windows_browser_policy.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_windows_daemon_service.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_windows_installer.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_windows_installer_verifier.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_windows_msi_sequencing.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_windows_native_messaging_packaging.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_windows_ps1_gates.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_windows_scan_all_users.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_windows_sign_shards.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/test_windows_update_handoff.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/verified_local_proxy/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/verified_local_proxy/test_config.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/verified_local_proxy/test_proxy.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/verified_local_proxy/test_verification/__init__.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/verified_local_proxy/test_verification/test_base.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/verified_local_proxy/test_verification/test_macos.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/verified_local_proxy/test_verification/test_windows.py +0 -0
- {runlayer-0.31.2 → runlayer-0.31.3}/tests/windows_installer_helpers.py +0 -0
|
@@ -342,6 +342,7 @@ uv run runlayer run test_uuid --secret test_key --host http://localhost:8000
|
|
|
342
342
|
|
|
343
343
|
- Never log API keys or tokens
|
|
344
344
|
- Validate all inputs
|
|
345
|
+
- `runlayer run` stdio children get a minimal environment (`main.py:_build_stdio_env`): the backend-configured `env` plus a short proxy/TLS/locale allowlist, on top of mcp's platform base set. Never pass `os.environ` through — the AI client's env carries cloud credentials.
|
|
345
346
|
- Use HTTPS by default
|
|
346
347
|
- Provide clear security guidance in docs
|
|
347
348
|
|
|
@@ -48,12 +48,33 @@ def _config_callback(ctx: typer.Context) -> None:
|
|
|
48
48
|
raise typer.Exit()
|
|
49
49
|
|
|
50
50
|
|
|
51
|
+
_UNRECOGNIZED_SECRET = "set (unrecognized format)"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _redact_secret(field: str, value: str) -> str:
|
|
55
|
+
# Recognized keys render the way the dashboard shows that key type, so an
|
|
56
|
+
# operator can match a device to a key by eye (pinned by
|
|
57
|
+
# tests/fixtures/managed_secret_display_cases.json). Anything else is
|
|
58
|
+
# masked outright: `config show` output gets pasted into tickets, and a
|
|
59
|
+
# wrong-type or truncated value must not echo more than the old
|
|
60
|
+
# `****<last4>` did.
|
|
61
|
+
if field == "enrollment_key":
|
|
62
|
+
if value.startswith("rl_enroll_") and len(value) > 14:
|
|
63
|
+
return f"{value[:10]}...{value[-4:]}"
|
|
64
|
+
return _UNRECOGNIZED_SECRET
|
|
65
|
+
if value.startswith("rl_org_") and len(value) > 14:
|
|
66
|
+
return f"{value[:14]}..."
|
|
67
|
+
return _UNRECOGNIZED_SECRET
|
|
68
|
+
|
|
69
|
+
|
|
51
70
|
def _redact_config(config: mdm_config.ManagedConfig) -> dict[str, object]:
|
|
52
71
|
redacted: dict[str, object] = {}
|
|
53
72
|
for key, value in config.items():
|
|
54
73
|
if key in mdm_config.SECRET_FIELDS:
|
|
55
74
|
redacted[key] = (
|
|
56
|
-
|
|
75
|
+
_redact_secret(key, value)
|
|
76
|
+
if isinstance(value, str) and value
|
|
77
|
+
else "not set"
|
|
57
78
|
)
|
|
58
79
|
else:
|
|
59
80
|
redacted[key] = value
|
|
@@ -737,6 +737,47 @@ def _run_scan(
|
|
|
737
737
|
fg=typer.colors.YELLOW,
|
|
738
738
|
)
|
|
739
739
|
|
|
740
|
+
if submission.manifest_regressed:
|
|
741
|
+
scopes = ", ".join(
|
|
742
|
+
scope for scope, _last_accepted_at in submission.manifest_regressed
|
|
743
|
+
)
|
|
744
|
+
# ISO-8601 UTC strings from one backend sort lexicographically.
|
|
745
|
+
last_accepted_at = max(
|
|
746
|
+
accepted_at for _scope, accepted_at in submission.manifest_regressed
|
|
747
|
+
)
|
|
748
|
+
typer.secho(
|
|
749
|
+
f"{WARN} Scan manifest rejected: {scopes} predate the last "
|
|
750
|
+
f"accepted scan (started {last_accepted_at})",
|
|
751
|
+
fg=typer.colors.YELLOW,
|
|
752
|
+
)
|
|
753
|
+
|
|
754
|
+
if submission.manifest_superseded and not quiet:
|
|
755
|
+
scopes = ", ".join(
|
|
756
|
+
scope for scope, _last_accepted_at in submission.manifest_superseded
|
|
757
|
+
)
|
|
758
|
+
last_accepted_at = max(
|
|
759
|
+
accepted_at for _scope, accepted_at in submission.manifest_superseded
|
|
760
|
+
)
|
|
761
|
+
typer.echo(
|
|
762
|
+
f"Manifest superseded by a newer scan (started {last_accepted_at}) "
|
|
763
|
+
f"for {scopes}"
|
|
764
|
+
)
|
|
765
|
+
|
|
766
|
+
if submission.positives_superseded and not quiet:
|
|
767
|
+
identifiers = [
|
|
768
|
+
identifier for _kind, identifier in submission.positives_superseded
|
|
769
|
+
]
|
|
770
|
+
shown = ", ".join(identifiers[:5])
|
|
771
|
+
if len(identifiers) > 5:
|
|
772
|
+
shown += f", +{len(identifiers) - 5} more"
|
|
773
|
+
count = len(identifiers)
|
|
774
|
+
noun = "finding" if count == 1 else "findings"
|
|
775
|
+
typer.secho(
|
|
776
|
+
f"{WARN} {count} device-scoped {noun} superseded by a newer scan "
|
|
777
|
+
f"on this device and not recorded: {shown}",
|
|
778
|
+
fg=typer.colors.YELLOW,
|
|
779
|
+
)
|
|
780
|
+
|
|
740
781
|
# The WARN lines above already told the user what happened; here we only
|
|
741
782
|
# act on the exit-code policy the orchestrator computed.
|
|
742
783
|
exit_code = submission.exit_code
|
|
@@ -29,6 +29,8 @@ from collections.abc import Iterator
|
|
|
29
29
|
|
|
30
30
|
import httpx
|
|
31
31
|
|
|
32
|
+
from runlayer_cli.flow_contract import status_category
|
|
33
|
+
|
|
32
34
|
if sys.version_info >= (3, 11):
|
|
33
35
|
import builtins
|
|
34
36
|
|
|
@@ -92,20 +94,6 @@ def iter_exception_tree(
|
|
|
92
94
|
queue.extend(link for link in links if id(link) not in seen)
|
|
93
95
|
|
|
94
96
|
|
|
95
|
-
def _status_category(status_code: int) -> str:
|
|
96
|
-
if status_code == 401:
|
|
97
|
-
return "http_401"
|
|
98
|
-
if status_code == 403:
|
|
99
|
-
return "http_403"
|
|
100
|
-
if status_code == 404:
|
|
101
|
-
return "http_404"
|
|
102
|
-
if 400 <= status_code < 500:
|
|
103
|
-
return "http_4xx"
|
|
104
|
-
if 500 <= status_code < 600:
|
|
105
|
-
return "http_5xx"
|
|
106
|
-
return "other"
|
|
107
|
-
|
|
108
|
-
|
|
109
97
|
def _classify_single(exc: BaseException) -> tuple[str, int | None]:
|
|
110
98
|
"""Classify exactly one exception object (no chain or group walking)."""
|
|
111
99
|
# OAuth first: these subclass generic errors (OAuthCallbackTimeoutError is
|
|
@@ -121,7 +109,7 @@ def _classify_single(exc: BaseException) -> tuple[str, int | None]:
|
|
|
121
109
|
return ("other", None)
|
|
122
110
|
if 400 <= status_code < 500:
|
|
123
111
|
return ("oauth_registration_rejected", status_code)
|
|
124
|
-
return (
|
|
112
|
+
return (status_category(status_code), status_code)
|
|
125
113
|
if isinstance(exc, OAuthCallbackTimeoutError):
|
|
126
114
|
return ("oauth_flow_timeout", None)
|
|
127
115
|
# Device-local listener failures (occupied cached port, loopback policy)
|
|
@@ -138,7 +126,7 @@ def _classify_single(exc: BaseException) -> tuple[str, int | None]:
|
|
|
138
126
|
|
|
139
127
|
if isinstance(exc, httpx.HTTPStatusError):
|
|
140
128
|
status_code = exc.response.status_code
|
|
141
|
-
return (
|
|
129
|
+
return (status_category(status_code), status_code)
|
|
142
130
|
|
|
143
131
|
if isinstance(exc, httpx.ConnectTimeout):
|
|
144
132
|
return ("connect_timeout", None)
|
|
@@ -144,6 +144,25 @@ CLIENT_FLOW_HOOK_EVENTS: frozenset[str] = frozenset(
|
|
|
144
144
|
)
|
|
145
145
|
|
|
146
146
|
|
|
147
|
+
def status_category(status_code: int) -> str:
|
|
148
|
+
"""Map an HTTP status to its ``CLIENT_FLOW_ERROR_CATEGORIES`` member. Lives
|
|
149
|
+
here (stdlib-only, already inside the hook import closure) rather than in
|
|
150
|
+
``error_classification`` so the relay's non-2xx path does not drag the MCP
|
|
151
|
+
client stack into the packaged hook."""
|
|
152
|
+
category = "other"
|
|
153
|
+
if status_code == 401:
|
|
154
|
+
category = "http_401"
|
|
155
|
+
elif status_code == 403:
|
|
156
|
+
category = "http_403"
|
|
157
|
+
elif status_code == 404:
|
|
158
|
+
category = "http_404"
|
|
159
|
+
elif 400 <= status_code < 500:
|
|
160
|
+
category = "http_4xx"
|
|
161
|
+
elif 500 <= status_code < 600:
|
|
162
|
+
category = "http_5xx"
|
|
163
|
+
return category
|
|
164
|
+
|
|
165
|
+
|
|
147
166
|
def build_envelope(flows: list[dict[str, Any]], dropped: int) -> dict[str, Any]:
|
|
148
167
|
"""Wire envelope attached to existing request bodies as ``client_flows``.
|
|
149
168
|
|
|
@@ -124,7 +124,7 @@ def normalize_event_name(event: str) -> str:
|
|
|
124
124
|
_POST_TOOL_EVENTS = frozenset({"PostToolUse", "PostToolUseFailure"})
|
|
125
125
|
|
|
126
126
|
# Session events whose hook output may add model-visible context.
|
|
127
|
-
_CONTEXT_EVENTS = frozenset({"SessionStart"
|
|
127
|
+
_CONTEXT_EVENTS = frozenset({"SessionStart"})
|
|
128
128
|
_CONTEXT_CLIENTS = frozenset({Client.CLAUDE_CODE, Client.CODEX})
|
|
129
129
|
|
|
130
130
|
# Cline parses stdout by scanning for lines prefixed ``HOOK_CONTROL\t`` (last one
|
|
@@ -762,7 +762,7 @@ class HookResponse:
|
|
|
762
762
|
"""Allow a session event and add model-visible context.
|
|
763
763
|
|
|
764
764
|
Claude Code and Codex share the ``hookSpecificOutput.additionalContext``
|
|
765
|
-
contract on session start
|
|
765
|
+
contract on session start.
|
|
766
766
|
"""
|
|
767
767
|
if self._client in _CONTEXT_CLIENTS and self._event in _CONTEXT_EVENTS:
|
|
768
768
|
return json.dumps(
|
|
@@ -9,7 +9,7 @@ import time
|
|
|
9
9
|
from collections.abc import Callable
|
|
10
10
|
from dataclasses import dataclass
|
|
11
11
|
from pathlib import Path
|
|
12
|
-
from typing import Any, NoReturn, cast
|
|
12
|
+
from typing import Any, NoReturn, cast, Literal
|
|
13
13
|
|
|
14
14
|
from runlayer_cli import __version__, flow_spool, flow_trace, regex_safe
|
|
15
15
|
from runlayer_cli.hook import credential_state, hook_io, host_override, messages
|
|
@@ -52,6 +52,7 @@ from runlayer_cli.hook.mcp_lookup import (
|
|
|
52
52
|
resolve_hermes_mcp_tool,
|
|
53
53
|
)
|
|
54
54
|
from runlayer_cli.hook.failure import FailureContext
|
|
55
|
+
from runlayer_cli.flow_contract import status_category
|
|
55
56
|
from runlayer_cli.hook.relay import (
|
|
56
57
|
RelayError,
|
|
57
58
|
check_tool_lifecycle,
|
|
@@ -173,18 +174,52 @@ def _policy_violation(check: Callable[[], None]) -> FilePolicyViolation | None:
|
|
|
173
174
|
return None
|
|
174
175
|
|
|
175
176
|
|
|
176
|
-
def
|
|
177
|
-
"""
|
|
177
|
+
def _device_deny_kwargs(failure: FailureContext | None) -> dict[str, Any]:
|
|
178
|
+
"""Device context for denies that name the device: hostname + credential
|
|
179
|
+
kind for Runlayer's 401, hostname alone for a network rejection (the block
|
|
180
|
+
is per device, so IT needs the hostname; no credential was judged)."""
|
|
181
|
+
kwargs: dict[str, Any] = {}
|
|
182
|
+
if failure is not None and failure.kind == "http":
|
|
183
|
+
if failure.is_network_rejection:
|
|
184
|
+
kwargs = {"hostname": device_hostname()}
|
|
185
|
+
elif failure.status_code == credential_state.CREDENTIAL_REJECTED_STATUS:
|
|
186
|
+
kwargs = {
|
|
187
|
+
"hostname": device_hostname(),
|
|
188
|
+
"managed_credential": uses_managed_credential(),
|
|
189
|
+
}
|
|
190
|
+
return kwargs
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
_InfraDenyErrorType = Literal["HookNetworkDeny", "HookInfraDeny"]
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _mark_infra_deny(failure: FailureContext | None, *, override: bool) -> None:
|
|
197
|
+
"""Mark the flow for a fail-closed relay deny. This is where the flow
|
|
198
|
+
learns the HTTP category of a deny. The relay marks only Runlayer's own
|
|
199
|
+
401 (the credential verdict, see ``relay._note_credential_rejection``);
|
|
200
|
+
every other non-2xx is left unmarked there because some are recovered
|
|
201
|
+
(gzip identity retry) or swallowed by best-effort callers and must not
|
|
202
|
+
count as failed flows in the hook-reliability alerts."""
|
|
203
|
+
kwargs: dict[str, Any] = {}
|
|
178
204
|
if (
|
|
179
|
-
failure is None
|
|
180
|
-
|
|
181
|
-
|
|
205
|
+
failure is not None
|
|
206
|
+
and failure.kind == "http"
|
|
207
|
+
and failure.status_code is not None
|
|
182
208
|
):
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
209
|
+
kwargs = {
|
|
210
|
+
"category": status_category(failure.status_code),
|
|
211
|
+
"http_status": failure.status_code,
|
|
212
|
+
}
|
|
213
|
+
flow_trace.mark_error(_infra_deny_error_type(failure), override=override, **kwargs)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _infra_deny_error_type(failure: FailureContext | None) -> _InfraDenyErrorType:
|
|
217
|
+
"""Flow error type for a fail-closed relay deny: ``HookNetworkDeny`` when
|
|
218
|
+
an intermediary rejected the request (nothing reached Runlayer), else
|
|
219
|
+
``HookInfraDeny``. Log-only labels (see the hook-reliability alert rules),
|
|
220
|
+
so per-customer triage can split "our 4xx" from "their edge 4xx"."""
|
|
221
|
+
is_network = failure is not None and failure.is_network_rejection
|
|
222
|
+
return "HookNetworkDeny" if is_network else "HookInfraDeny"
|
|
188
223
|
|
|
189
224
|
|
|
190
225
|
# Flow error type for "Monitor device, credentials rejected, call allowed".
|
|
@@ -790,11 +825,11 @@ def _check_tool_lifecycle(
|
|
|
790
825
|
flow_trace.mark_error("HookAuthRequired", override=True)
|
|
791
826
|
u, a = messages.tool_auth_required(tool_name=tool_name)
|
|
792
827
|
else:
|
|
793
|
-
|
|
828
|
+
_mark_infra_deny(e.failure, override=True)
|
|
794
829
|
u, a = messages.tool_api_unreachable(
|
|
795
830
|
tool_name=tool_name,
|
|
796
831
|
failure=e.failure,
|
|
797
|
-
**
|
|
832
|
+
**_device_deny_kwargs(e.failure),
|
|
798
833
|
)
|
|
799
834
|
if target == "tool-post":
|
|
800
835
|
_write(
|
|
@@ -1149,15 +1184,12 @@ _PLUGIN_CONTEXT_CLIENTS = frozenset({Client.CLAUDE_CODE, Client.CODEX})
|
|
|
1149
1184
|
|
|
1150
1185
|
|
|
1151
1186
|
def _plugin_context_output(ctx: _DispatchCtx) -> str | None:
|
|
1152
|
-
"""Session
|
|
1187
|
+
"""Session-start output carrying Runlayer Plugin routing rules.
|
|
1153
1188
|
|
|
1154
|
-
None when the client
|
|
1155
|
-
|
|
1189
|
+
None when the client has no context slot, or the built-in plugin is not
|
|
1190
|
+
configured for this session, so the caller falls back to plain output.
|
|
1156
1191
|
"""
|
|
1157
|
-
if ctx.client not in _PLUGIN_CONTEXT_CLIENTS
|
|
1158
|
-
"SessionStart",
|
|
1159
|
-
"UserPromptSubmit",
|
|
1160
|
-
):
|
|
1192
|
+
if ctx.client not in _PLUGIN_CONTEXT_CLIENTS:
|
|
1161
1193
|
return None
|
|
1162
1194
|
cwd = ctx.input_data.get("cwd", "") or hook_io.getcwd()
|
|
1163
1195
|
context = build_plugin_context(ctx.client, cwd)
|
|
@@ -1182,7 +1214,7 @@ def _handle_session_event(ctx: _DispatchCtx) -> None:
|
|
|
1182
1214
|
forward_event(
|
|
1183
1215
|
ctx.client.value, ctx.original_hook_type, ctx.input_data, debug=ctx.debug
|
|
1184
1216
|
)
|
|
1185
|
-
_write(
|
|
1217
|
+
_write(ctx.resp.allow())
|
|
1186
1218
|
|
|
1187
1219
|
|
|
1188
1220
|
def _handle_post_tool_use(ctx: _DispatchCtx) -> None:
|
|
@@ -1557,7 +1589,7 @@ def _mcp_enforce_and_respond(
|
|
|
1557
1589
|
elif mode is AIWatchMode.PROTECT:
|
|
1558
1590
|
flow_trace.mark_error("HookInfraFailOpen")
|
|
1559
1591
|
else:
|
|
1560
|
-
|
|
1592
|
+
_mark_infra_deny(e.failure, override=False)
|
|
1561
1593
|
if mode is AIWatchMode.PROTECT:
|
|
1562
1594
|
return _allow_protect_failure()
|
|
1563
1595
|
if e.exit_code == 1:
|
|
@@ -1566,7 +1598,7 @@ def _mcp_enforce_and_respond(
|
|
|
1566
1598
|
u, a = messages.api_unreachable(
|
|
1567
1599
|
tool_name=tool_name,
|
|
1568
1600
|
failure=e.failure,
|
|
1569
|
-
**
|
|
1601
|
+
**_device_deny_kwargs(e.failure),
|
|
1570
1602
|
)
|
|
1571
1603
|
_deny_and_exit(resp, u, a)
|
|
1572
1604
|
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"""Relay failure classification shared by the relay and deny-message rendering.
|
|
2
|
+
|
|
3
|
+
Extracted from ``hook/relay.py`` (ENG-5365) so ``messages.py`` can import the
|
|
4
|
+
context type at runtime without pulling the whole relay module. Keep this
|
|
5
|
+
module stdlib + httpx only.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from typing import Any, Literal, NamedTuple
|
|
13
|
+
|
|
14
|
+
import httpx
|
|
15
|
+
|
|
16
|
+
# Closed vocabulary for FailureContext.kind. messages._unreachable_cause has a
|
|
17
|
+
# rendering branch per kind (contract-tested); a kind added here without one
|
|
18
|
+
# falls back to the generic legacy message.
|
|
19
|
+
FailureKind = Literal["connect", "upload_timeout", "upload_failed", "timeout", "http"]
|
|
20
|
+
|
|
21
|
+
# Who answered a non-2xx. ``"runlayer"``: the Runlayer application (its error
|
|
22
|
+
# responses carry ``X-Runlayer-Origin`` and ``X-Request-ID`` and a JSON
|
|
23
|
+
# ``{"detail": ...}`` body). ``"intermediary"``: something in front of it — an
|
|
24
|
+
# AWS WAF IP-allowlist block, an ALB error page, a corporate proxy — which
|
|
25
|
+
# returns the same status codes with an HTML body and neither header. The
|
|
26
|
+
# distinction decides both wording (a WAF 403 is a network rejection, not a
|
|
27
|
+
# Runlayer policy decision) and whether a 401 may touch the credential caches
|
|
28
|
+
# (an intermediary 401 says nothing about the Runlayer credential).
|
|
29
|
+
ResponseOrigin = Literal["runlayer", "intermediary"]
|
|
30
|
+
|
|
31
|
+
# Header names the backend stamps on every error response it answers. The
|
|
32
|
+
# origin header's value is a fixed literal; only its presence is inspected.
|
|
33
|
+
ORIGIN_HEADER_NAME = "X-Runlayer-Origin"
|
|
34
|
+
REQUEST_ID_HEADER_NAME = "X-Request-ID"
|
|
35
|
+
|
|
36
|
+
# Statuses an intermediary can answer that would otherwise read as a Runlayer
|
|
37
|
+
# credential (401) or policy (403) decision. Other intermediary statuses (an
|
|
38
|
+
# ALB 5xx with no healthy target, a proxy 429) keep the generic
|
|
39
|
+
# answered-request wording, which blames the request, not Runlayer.
|
|
40
|
+
NETWORK_REJECT_STATUSES = frozenset({401, 403})
|
|
41
|
+
|
|
42
|
+
# Server-supplied text is rendered into the deny reason, so it is bounded and
|
|
43
|
+
# reduced to printable characters; a request id is only echoed when it looks
|
|
44
|
+
# like one.
|
|
45
|
+
_MAX_DETAIL_CHARS = 200
|
|
46
|
+
_MAX_REQUEST_ID_CHARS = 64
|
|
47
|
+
_REQUEST_ID_CHARS = frozenset(
|
|
48
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._:-"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dataclass(frozen=True, slots=True)
|
|
53
|
+
class FailureContext:
|
|
54
|
+
"""What a failed relay POST knew at the moment it failed (ENG-5197).
|
|
55
|
+
|
|
56
|
+
``kind``: ``"connect"`` (no connection acquired — includes pool
|
|
57
|
+
exhaustion), ``"upload_timeout"`` (body still uploading when the write
|
|
58
|
+
timed out), ``"upload_failed"`` (connection dropped while the body was
|
|
59
|
+
uploading), ``"timeout"`` (request sent, no response in time), ``"http"``
|
|
60
|
+
(non-2xx, see ``status_code``), or ``None`` (unclassified). ``payload_bytes``
|
|
61
|
+
is the UTF-8 wire size of the request body; ``elapsed_s`` is time spent in
|
|
62
|
+
the POST before it failed (all attempts, retries included);
|
|
63
|
+
``attempts`` is how many attempts ran before giving up (1 = no retry).
|
|
64
|
+
Carried whole on ``RelayError`` so new fields never need re-threading
|
|
65
|
+
through call sites.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
kind: FailureKind | None = None
|
|
69
|
+
payload_bytes: int | None = None
|
|
70
|
+
elapsed_s: float | None = None
|
|
71
|
+
status_code: int | None = None
|
|
72
|
+
attempts: int = 1
|
|
73
|
+
# ``kind == "http"`` only. ``None`` = unclassified (a transport without
|
|
74
|
+
# headers, or callers that predate classification): status-only wording,
|
|
75
|
+
# treated as Runlayer.
|
|
76
|
+
origin: ResponseOrigin | None = None
|
|
77
|
+
# Echoed only for a Runlayer-origin response, so support can find the
|
|
78
|
+
# server-side log line. Already shape-checked and bounded.
|
|
79
|
+
request_id: str | None = None
|
|
80
|
+
# The backend's ``detail`` string, sanitized and bounded; never set for an
|
|
81
|
+
# intermediary (its body is untrusted HTML and is not rendered).
|
|
82
|
+
detail: str | None = None
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def is_network_rejection(self) -> bool:
|
|
86
|
+
"""An HTTP 401/403 attributed to an intermediary: worded as a network
|
|
87
|
+
rejection, and no credential state may be touched."""
|
|
88
|
+
return (
|
|
89
|
+
self.kind == "http"
|
|
90
|
+
and self.origin == "intermediary"
|
|
91
|
+
and self.status_code in NETWORK_REJECT_STATUSES
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class ResponseOriginInfo(NamedTuple):
|
|
96
|
+
origin: ResponseOrigin | None
|
|
97
|
+
request_id: str | None
|
|
98
|
+
detail: str | None
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
_UNCLASSIFIED = ResponseOriginInfo(None, None, None)
|
|
102
|
+
_INTERMEDIARY = ResponseOriginInfo("intermediary", None, None)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _sanitize_detail(value: Any) -> str | None:
|
|
106
|
+
if not isinstance(value, str):
|
|
107
|
+
return None
|
|
108
|
+
printable = "".join(c if c.isprintable() else " " for c in value)
|
|
109
|
+
cleaned = " ".join(printable.split())
|
|
110
|
+
if len(cleaned) > _MAX_DETAIL_CHARS:
|
|
111
|
+
cleaned = cleaned[: _MAX_DETAIL_CHARS - 1].rstrip() + "…"
|
|
112
|
+
return cleaned or None
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _request_id(headers: Any) -> str | None:
|
|
116
|
+
value = headers.get(REQUEST_ID_HEADER_NAME)
|
|
117
|
+
if not isinstance(value, str):
|
|
118
|
+
return None
|
|
119
|
+
value = value.strip()
|
|
120
|
+
is_token = (
|
|
121
|
+
0 < len(value) <= _MAX_REQUEST_ID_CHARS and set(value) <= _REQUEST_ID_CHARS
|
|
122
|
+
)
|
|
123
|
+
return value if is_token else None
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _error_envelope(text: Any) -> dict[str, Any] | None:
|
|
127
|
+
"""The backend's ``{"detail": ...}`` body, or ``None`` for anything else
|
|
128
|
+
(HTML, non-object JSON, unparseable). ``detail`` may be a list (422); the
|
|
129
|
+
envelope shape is what proves the origin, the caller decides what to
|
|
130
|
+
render. ``json.loads`` can raise more than ``ValueError`` on hostile input
|
|
131
|
+
(``RecursionError`` on deep nesting), so anything it raises means "not an
|
|
132
|
+
envelope"."""
|
|
133
|
+
if not isinstance(text, str) or not text:
|
|
134
|
+
return None
|
|
135
|
+
try:
|
|
136
|
+
body = json.loads(text)
|
|
137
|
+
except Exception:
|
|
138
|
+
return None
|
|
139
|
+
return body if isinstance(body, dict) and "detail" in body else None
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def classify_response_origin(resp: Any) -> ResponseOriginInfo:
|
|
143
|
+
"""Decide who produced a non-2xx response.
|
|
144
|
+
|
|
145
|
+
Runlayer when the origin header is present, or — for backends predating
|
|
146
|
+
it — when the response carries a request id *and* the JSON error envelope
|
|
147
|
+
(both come from the same handler, so either alone is not enough: proxies
|
|
148
|
+
add request-id headers of their own, and any hop can answer JSON).
|
|
149
|
+
Anything else with headers is an intermediary; a response object without
|
|
150
|
+
headers at all is unclassified. Never raises: classification is garnish
|
|
151
|
+
on a deny that must still be emitted, so any failure inside it also
|
|
152
|
+
yields "unclassified" (the pre-classification behaviour).
|
|
153
|
+
"""
|
|
154
|
+
headers = getattr(resp, "headers", None)
|
|
155
|
+
if headers is None:
|
|
156
|
+
return _UNCLASSIFIED
|
|
157
|
+
try:
|
|
158
|
+
request_id = _request_id(headers)
|
|
159
|
+
envelope = _error_envelope(getattr(resp, "text", None))
|
|
160
|
+
marked = headers.get(ORIGIN_HEADER_NAME) is not None
|
|
161
|
+
except Exception:
|
|
162
|
+
return _UNCLASSIFIED
|
|
163
|
+
if marked or (request_id is not None and envelope is not None):
|
|
164
|
+
detail = _sanitize_detail(envelope.get("detail")) if envelope else None
|
|
165
|
+
return ResponseOriginInfo("runlayer", request_id, detail)
|
|
166
|
+
return _INTERMEDIARY
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _safe_wire_size(payload: str | bytes) -> int | None:
|
|
170
|
+
"""Byte size of the body as sent (UTF-8, post-compression when compressed),
|
|
171
|
+
or ``None`` if the encode itself fails.
|
|
172
|
+
|
|
173
|
+
A compressed body is already bytes, so sizing it is O(1). The str encode
|
|
174
|
+
allocates a full copy of a potentially multi-MB body; under memory
|
|
175
|
+
pressure it can raise. Size is diagnostic garnish — it must never be the
|
|
176
|
+
reason a deny path stops denying (fail-closed depends on ``RelayError``
|
|
177
|
+
actually being raised).
|
|
178
|
+
"""
|
|
179
|
+
try:
|
|
180
|
+
if isinstance(payload, bytes):
|
|
181
|
+
return len(payload)
|
|
182
|
+
return len(payload.encode("utf-8"))
|
|
183
|
+
except Exception:
|
|
184
|
+
return None
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _classify_network_failure(exc: Exception) -> FailureKind | None:
|
|
188
|
+
"""Map an httpx transport exception to a ``FailureContext.kind``.
|
|
189
|
+
|
|
190
|
+
``WriteTimeout``/``WriteError`` both prove the body was still in flight
|
|
191
|
+
(timed out vs connection dropped — the latter is the signature of the
|
|
192
|
+
stalled uploads the ALB reaps). ``PoolTimeout`` means no connection was
|
|
193
|
+
ever acquired (shared-client saturation), so it is "connect", not
|
|
194
|
+
"timeout": only read timeouts mean the request was sent with no response
|
|
195
|
+
in time. Non-httpx exceptions stay unclassified rather than guessing.
|
|
196
|
+
"""
|
|
197
|
+
if isinstance(exc, httpx.WriteTimeout):
|
|
198
|
+
return "upload_timeout"
|
|
199
|
+
if isinstance(exc, httpx.WriteError):
|
|
200
|
+
return "upload_failed"
|
|
201
|
+
if isinstance(exc, httpx.ConnectError | httpx.ConnectTimeout | httpx.PoolTimeout):
|
|
202
|
+
return "connect"
|
|
203
|
+
if isinstance(exc, httpx.TimeoutException):
|
|
204
|
+
return "timeout"
|
|
205
|
+
return None
|