control-tower 6.0.0__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.
- control_tower-6.0.0/LICENSE +21 -0
- control_tower-6.0.0/MANIFEST.in +2 -0
- control_tower-6.0.0/PKG-INFO +91 -0
- control_tower-6.0.0/README.md +36 -0
- control_tower-6.0.0/pyproject.toml +287 -0
- control_tower-6.0.0/setup.cfg +4 -0
- control_tower-6.0.0/src/control_tower/__init__.py +3 -0
- control_tower-6.0.0/src/control_tower/backends/__init__.py +31 -0
- control_tower-6.0.0/src/control_tower/backends/fleet/__init__.py +1 -0
- control_tower-6.0.0/src/control_tower/backends/fleet/ami.py +45 -0
- control_tower-6.0.0/src/control_tower/backends/fleet/aws_identity.py +9 -0
- control_tower-6.0.0/src/control_tower/backends/fleet/bootstrap.sh +349 -0
- control_tower-6.0.0/src/control_tower/backends/fleet/config.py +40 -0
- control_tower-6.0.0/src/control_tower/backends/fleet/controller.py +2058 -0
- control_tower-6.0.0/src/control_tower/backends/fleet/job.py +325 -0
- control_tower-6.0.0/src/control_tower/backends/fleet/run.py +399 -0
- control_tower-6.0.0/src/control_tower/backends/fleet/run_job.py +270 -0
- control_tower-6.0.0/src/control_tower/backends/fleet/worker.py +1045 -0
- control_tower-6.0.0/src/control_tower/backends/fleet/worker_cli.py +68 -0
- control_tower-6.0.0/src/control_tower/backends/hawk/__init__.py +7 -0
- control_tower-6.0.0/src/control_tower/backends/hawk/config.py +114 -0
- control_tower-6.0.0/src/control_tower/backends/hawk/download.py +93 -0
- control_tower-6.0.0/src/control_tower/backends/hawk/middleman.py +64 -0
- control_tower-6.0.0/src/control_tower/backends/hawk/model_closure.py +39 -0
- control_tower-6.0.0/src/control_tower/backends/hawk/preflight.py +142 -0
- control_tower-6.0.0/src/control_tower/backends/hawk/pull_envs.py +160 -0
- control_tower-6.0.0/src/control_tower/backends/hawk/runner.py +1050 -0
- control_tower-6.0.0/src/control_tower/backends/hawk/sandbox.py +561 -0
- control_tower-6.0.0/src/control_tower/backends/hawk/yaml_generator.py +206 -0
- control_tower-6.0.0/src/control_tower/backends/local.py +223 -0
- control_tower-6.0.0/src/control_tower/cli/__init__.py +3 -0
- control_tower-6.0.0/src/control_tower/cli/base.py +207 -0
- control_tower-6.0.0/src/control_tower/cli/cloud.py +132 -0
- control_tower-6.0.0/src/control_tower/cli/completions/completion_callbacks.py +125 -0
- control_tower-6.0.0/src/control_tower/cli/completions/completions_build.py +59 -0
- control_tower-6.0.0/src/control_tower/cli/completions/completions_hooks.py +209 -0
- control_tower-6.0.0/src/control_tower/cli/extras.py +89 -0
- control_tower-6.0.0/src/control_tower/cli/login.py +77 -0
- control_tower-6.0.0/src/control_tower/cli/main.py +51 -0
- control_tower-6.0.0/src/control_tower/cli/mcp_meta.py +30 -0
- control_tower-6.0.0/src/control_tower/cli/protocols.py +140 -0
- control_tower-6.0.0/src/control_tower/cli/run.py +893 -0
- control_tower-6.0.0/src/control_tower/cli/task_sets.py +123 -0
- control_tower-6.0.0/src/control_tower/datasets/__init__.py +0 -0
- control_tower-6.0.0/src/control_tower/datasets/check.py +88 -0
- control_tower-6.0.0/src/control_tower/datasets/cli.py +599 -0
- control_tower-6.0.0/src/control_tower/datasets/external.py +675 -0
- control_tower-6.0.0/src/control_tower/datasets/importers/__init__.py +47 -0
- control_tower-6.0.0/src/control_tower/datasets/importers/eval_log.py +596 -0
- control_tower-6.0.0/src/control_tower/datasets/importers/monitoring_bench.py +766 -0
- control_tower-6.0.0/src/control_tower/datasets/importers/mythos_5_incident.py +241 -0
- control_tower-6.0.0/src/control_tower/datasets/importers/sessions.py +159 -0
- control_tower-6.0.0/src/control_tower/datasets/importers/shade_arena.py +588 -0
- control_tower-6.0.0/src/control_tower/datasets/importers/sleight_bench.py +487 -0
- control_tower-6.0.0/src/control_tower/datasets/model.py +45 -0
- control_tower-6.0.0/src/control_tower/environments/build.py +191 -0
- control_tower-6.0.0/src/control_tower/environments/env_args.py +98 -0
- control_tower-6.0.0/src/control_tower/environments/environment.py +92 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/.dockerignore +3 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/Dockerfile +89 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/__init__.py +0 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/__main__.py +4 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/compose.yml +31 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/constants.py +53 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/core/assets.py +304 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/core/exposed_services.py +71 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/core/generate_ca.py +68 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/core/logs.py +212 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/core/network_mapping.py +63 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/core/tls.py +124 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/core/trajectory.py +17 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/core/webhook.py +195 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/malware/malware.c +143 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/modules/forward_proxy.py +431 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/modules/provider_policy.py +390 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/modules/response_rules.py +193 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/modules/shell_sessions.py +206 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/modules/upstream_proxy.py +289 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/modules/upstream_specs.py +221 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/personas.py +150 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/requirements.txt +3 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/resolve_override.c +75 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/runtimes/__init__.py +0 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/runtimes/docker.py +630 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/runtimes/hawk.py +193 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/runtimes/provisioning.py +39 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/server.py +660 -0
- control_tower-6.0.0/src/control_tower/environments/internet_simulator/source_hash.py +78 -0
- control_tower-6.0.0/src/control_tower/environments/list_utils.py +482 -0
- control_tower-6.0.0/src/control_tower/environments/registry.py +275 -0
- control_tower-6.0.0/src/control_tower/environments/remote/__init__.py +0 -0
- control_tower-6.0.0/src/control_tower/environments/remote/process.py +248 -0
- control_tower-6.0.0/src/control_tower/environments/remote/remote.py +407 -0
- control_tower-6.0.0/src/control_tower/environments/remote/sample.py +244 -0
- control_tower-6.0.0/src/control_tower/environments/setting_runtime.py +176 -0
- control_tower-6.0.0/src/control_tower/environments/settings.py +1170 -0
- control_tower-6.0.0/src/control_tower/environments/settings.yml +26 -0
- control_tower-6.0.0/src/control_tower/environments/settings_cli.py +610 -0
- control_tower-6.0.0/src/control_tower/environments/validate.py +116 -0
- control_tower-6.0.0/src/control_tower/eval/README.md +38 -0
- control_tower-6.0.0/src/control_tower/eval/__init__.py +1 -0
- control_tower-6.0.0/src/control_tower/eval/game/__init__.py +11 -0
- control_tower-6.0.0/src/control_tower/eval/game/blue.py +570 -0
- control_tower-6.0.0/src/control_tower/eval/game/harness.py +146 -0
- control_tower-6.0.0/src/control_tower/eval/game/history.py +221 -0
- control_tower-6.0.0/src/control_tower/eval/game/messages.py +75 -0
- control_tower-6.0.0/src/control_tower/eval/game/red.py +346 -0
- control_tower-6.0.0/src/control_tower/eval/game/registry.py +29 -0
- control_tower-6.0.0/src/control_tower/eval/game/solver.py +214 -0
- control_tower-6.0.0/src/control_tower/eval/game/view.py +114 -0
- control_tower-6.0.0/src/control_tower/eval/game/white.py +37 -0
- control_tower-6.0.0/src/control_tower/eval/launch/__init__.py +1 -0
- control_tower-6.0.0/src/control_tower/eval/launch/assemble.py +416 -0
- control_tower-6.0.0/src/control_tower/eval/launch/dataset.py +611 -0
- control_tower-6.0.0/src/control_tower/eval/launch/dispatch.py +142 -0
- control_tower-6.0.0/src/control_tower/eval/launch/inspect_tasks.py +248 -0
- control_tower-6.0.0/src/control_tower/eval/launch/metadata.py +39 -0
- control_tower-6.0.0/src/control_tower/eval/launch/naming.py +37 -0
- control_tower-6.0.0/src/control_tower/eval/launch/options.py +40 -0
- control_tower-6.0.0/src/control_tower/eval/launch/preflight.py +90 -0
- control_tower-6.0.0/src/control_tower/eval/launch/selection.py +151 -0
- control_tower-6.0.0/src/control_tower/eval/log/README.md +76 -0
- control_tower-6.0.0/src/control_tower/eval/log/__init__.py +0 -0
- control_tower-6.0.0/src/control_tower/eval/log/action.py +72 -0
- control_tower-6.0.0/src/control_tower/eval/log/blue_calls.py +93 -0
- control_tower-6.0.0/src/control_tower/eval/log/convert.py +1773 -0
- control_tower-6.0.0/src/control_tower/eval/log/eval_trace_metadata.py +15 -0
- control_tower-6.0.0/src/control_tower/eval/log/extended_thinking.py +56 -0
- control_tower-6.0.0/src/control_tower/eval/log/format_history.py +35 -0
- control_tower-6.0.0/src/control_tower/eval/log/from_eval_log.py +141 -0
- control_tower-6.0.0/src/control_tower/eval/log/merge.py +87 -0
- control_tower-6.0.0/src/control_tower/eval/log/monitor_scores.py +112 -0
- control_tower-6.0.0/src/control_tower/eval/log/sample.py +403 -0
- control_tower-6.0.0/src/control_tower/eval/log/task_args.py +23 -0
- control_tower-6.0.0/src/control_tower/eval/log/task_scores.py +110 -0
- control_tower-6.0.0/src/control_tower/eval/log/tool_calls.py +40 -0
- control_tower-6.0.0/src/control_tower/eval/log/translation.py +342 -0
- control_tower-6.0.0/src/control_tower/eval/log/utils.py +85 -0
- control_tower-6.0.0/src/control_tower/eval/log/workspace_diff.py +16 -0
- control_tower-6.0.0/src/control_tower/eval/monitoring/__init__.py +1 -0
- control_tower-6.0.0/src/control_tower/eval/monitoring/posthoc.py +339 -0
- control_tower-6.0.0/src/control_tower/eval/monitoring/scorer.py +409 -0
- control_tower-6.0.0/src/control_tower/extras/__init__.py +0 -0
- control_tower-6.0.0/src/control_tower/extras/claude_host.py +26 -0
- control_tower-6.0.0/src/control_tower/extras/dashboard.py +269 -0
- control_tower-6.0.0/src/control_tower/extras/dashboard_cli.py +19 -0
- control_tower-6.0.0/src/control_tower/extras/env_description/__init__.py +0 -0
- control_tower-6.0.0/src/control_tower/extras/env_description/audit/README.md +80 -0
- control_tower-6.0.0/src/control_tower/extras/env_description/audit/__init__.py +0 -0
- control_tower-6.0.0/src/control_tower/extras/env_description/audit/cli.py +81 -0
- control_tower-6.0.0/src/control_tower/extras/env_description/audit/models.py +63 -0
- control_tower-6.0.0/src/control_tower/extras/env_description/audit/prompts/system.md +68 -0
- control_tower-6.0.0/src/control_tower/extras/env_description/audit/prompts/user.md +30 -0
- control_tower-6.0.0/src/control_tower/extras/env_description/audit/task.py +278 -0
- control_tower-6.0.0/src/control_tower/extras/env_description/generate/README.md +75 -0
- control_tower-6.0.0/src/control_tower/extras/env_description/generate/cli.py +146 -0
- control_tower-6.0.0/src/control_tower/extras/env_description/generate/prompts/system.md +62 -0
- control_tower-6.0.0/src/control_tower/extras/env_description/generate/prompts/user.md +21 -0
- control_tower-6.0.0/src/control_tower/extras/env_description/generate/task.py +359 -0
- control_tower-6.0.0/src/control_tower/extras/env_description/shared/concurrency.py +72 -0
- control_tower-6.0.0/src/control_tower/extras/env_description/shared/spec.md +79 -0
- control_tower-6.0.0/src/control_tower/extras/env_description/shared/spec_loader.py +24 -0
- control_tower-6.0.0/src/control_tower/extras/env_source.py +230 -0
- control_tower-6.0.0/src/control_tower/extras/integration_test_quality/README.md +59 -0
- control_tower-6.0.0/src/control_tower/extras/integration_test_quality/cli.py +115 -0
- control_tower-6.0.0/src/control_tower/extras/integration_test_quality/prompts/analyze.md +44 -0
- control_tower-6.0.0/src/control_tower/extras/integration_test_quality/prompts/check_tasks.md +29 -0
- control_tower-6.0.0/src/control_tower/extras/integration_test_quality/prompts/coverage.md +27 -0
- control_tower-6.0.0/src/control_tower/extras/integration_test_quality/prompts/fix.md +14 -0
- control_tower-6.0.0/src/control_tower/extras/integration_test_quality/task.py +179 -0
- control_tower-6.0.0/src/control_tower/extras/pairing_analysis/README.md +30 -0
- control_tower-6.0.0/src/control_tower/extras/pairing_analysis/cli.py +82 -0
- control_tower-6.0.0/src/control_tower/extras/pairing_analysis/prompts/pairing.md +43 -0
- control_tower-6.0.0/src/control_tower/extras/pairing_analysis/task.py +367 -0
- control_tower-6.0.0/src/control_tower/extras/prompts.py +28 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/base.py +216 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/checks/_json.py +31 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/checks/chroma.py +285 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/checks/docker.py +366 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/checks/elasticsearch.py +293 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/checks/filesystem.py +155 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/checks/generated_manifest.json +13 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/checks/influxdb.py +549 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/checks/listener.py +81 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/checks/minio.py +360 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/checks/mongo.py +338 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/checks/openldap.py +241 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/checks/postgres.py +317 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/checks/process.py +134 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/checks/rabbitmq.py +369 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/checks/redis.py +291 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/checks/sqlite.py +309 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/checks/sshd.py +270 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/checks/vault.py +376 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/cli.py +575 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/compose_analyzer.py +182 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/detection.py +236 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/dockerfile_analyzer.py +377 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/llm_generator.py +448 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/runner.py +449 -0
- control_tower-6.0.0/src/control_tower/extras/scorer_idempotency/runtime_prober.py +378 -0
- control_tower-6.0.0/src/control_tower/extras/side_task_folder.py +115 -0
- control_tower-6.0.0/src/control_tower/extras/storage.py +74 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/compare_side_tasks/README.md +25 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/compare_side_tasks/cli.py +25 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/compare_side_tasks/task.py +127 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/doc_audit/README.md +77 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/doc_audit/audits/base.py +129 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/doc_audit/audits/goal.py +92 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/doc_audit/audits/sd.py +98 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/doc_audit/cli.py +185 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/doc_audit/heuristics/base.py +53 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/doc_audit/heuristics/goal.py +215 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/doc_audit/heuristics/sd.py +222 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/doc_audit/prompts/goal/system.md +109 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/doc_audit/prompts/goal/user.md +21 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/doc_audit/prompts/sd/system.md +311 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/doc_audit/prompts/sd/user.md +26 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/doc_audit/sd_audit_labels.json +98 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/doc_audit/task.py +200 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/failure_type_audit/cli.py +125 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/failure_type_audit/prompts/system.md +9 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/failure_type_audit/prompts/user.md +23 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/failure_type_audit/task.py +190 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/goal_completeness/README.md +56 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/goal_completeness/cli.py +125 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/goal_completeness/prompts/system.md +44 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/goal_completeness/prompts/user.md +50 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/goal_completeness/task.py +320 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/goal_completeness/viewer.py +142 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/reward_hacking/README.md +46 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/reward_hacking/cli.py +115 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/reward_hacking/prompts/system.md +71 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/reward_hacking/prompts/user.md +62 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/reward_hacking/task.py +360 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/reward_hacking/viewer.py +122 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/rt_alignment/README.md +45 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/rt_alignment/cli.py +119 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/rt_alignment/prompts/system.md +50 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/rt_alignment/prompts/user.md +57 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/rt_alignment/task.py +357 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/rt_alignment/viewer.py +124 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/side_task_review/README.md +43 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/side_task_review/cli.py +87 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/side_task_review/prompts/review.md +30 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/side_task_review/task.py +98 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/validate_cover/README.md +32 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/validate_cover/cli.py +97 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/validate_cover/container_script.py +230 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/validate_cover/full_env_context.py +66 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/validate_cover/task.py +97 -0
- control_tower-6.0.0/src/control_tower/extras/task_analysis/validate_cover/validate_cover_prompt.md +35 -0
- control_tower-6.0.0/src/control_tower/extras/timing_report/__init__.py +17 -0
- control_tower-6.0.0/src/control_tower/extras/timing_report/cli.py +71 -0
- control_tower-6.0.0/src/control_tower/extras/timing_report/report.py +324 -0
- control_tower-6.0.0/src/control_tower/extras/traj_analysis/submit_guessability/README.md +49 -0
- control_tower-6.0.0/src/control_tower/extras/traj_analysis/submit_guessability/cli.py +125 -0
- control_tower-6.0.0/src/control_tower/extras/traj_analysis/submit_guessability/prompts/system.md +29 -0
- control_tower-6.0.0/src/control_tower/extras/traj_analysis/submit_guessability/prompts/user.md +70 -0
- control_tower-6.0.0/src/control_tower/extras/traj_analysis/submit_guessability/task.py +351 -0
- control_tower-6.0.0/src/control_tower/extras/traj_analysis/submit_guessability/viewer.py +159 -0
- control_tower-6.0.0/src/control_tower/extras/traj_analysis/submit_guessability_verified/README.md +52 -0
- control_tower-6.0.0/src/control_tower/extras/traj_analysis/submit_guessability_verified/cli.py +143 -0
- control_tower-6.0.0/src/control_tower/extras/traj_analysis/submit_guessability_verified/prompts/system.md +36 -0
- control_tower-6.0.0/src/control_tower/extras/traj_analysis/submit_guessability_verified/prompts/user.md +61 -0
- control_tower-6.0.0/src/control_tower/extras/traj_analysis/submit_guessability_verified/task.py +673 -0
- control_tower-6.0.0/src/control_tower/extras/traj_analysis/submit_guessability_verified/viewer.py +186 -0
- control_tower-6.0.0/src/control_tower/live/__init__.py +0 -0
- control_tower-6.0.0/src/control_tower/live/agents.py +117 -0
- control_tower-6.0.0/src/control_tower/live/assets/dev_container_extensions.json +3 -0
- control_tower-6.0.0/src/control_tower/live/assets/live.gitignore +53 -0
- control_tower-6.0.0/src/control_tower/live/assets/pyrightconfig.json +4 -0
- control_tower-6.0.0/src/control_tower/live/assets/settings.json +3 -0
- control_tower-6.0.0/src/control_tower/live/cli.py +1133 -0
- control_tower-6.0.0/src/control_tower/live/compose.py +117 -0
- control_tower-6.0.0/src/control_tower/live/context/print_context.py +98 -0
- control_tower-6.0.0/src/control_tower/live/context/task_getters.py +65 -0
- control_tower-6.0.0/src/control_tower/live/context/traj_dir.py +334 -0
- control_tower-6.0.0/src/control_tower/live/integration_tests.py +128 -0
- control_tower-6.0.0/src/control_tower/live/sandbox_ops.py +134 -0
- control_tower-6.0.0/src/control_tower/live/score.py +85 -0
- control_tower-6.0.0/src/control_tower/live/session.py +513 -0
- control_tower-6.0.0/src/control_tower/live/setup.py +294 -0
- control_tower-6.0.0/src/control_tower/live/task_state.py +145 -0
- control_tower-6.0.0/src/control_tower/live/traj/__init__.py +0 -0
- control_tower-6.0.0/src/control_tower/live/traj/gen_traj.py +319 -0
- control_tower-6.0.0/src/control_tower/live/traj/git_status.py +33 -0
- control_tower-6.0.0/src/control_tower/live/traj/git_traj.py +735 -0
- control_tower-6.0.0/src/control_tower/live/traj/git_traj_helpers/FORMAT.md +25 -0
- control_tower-6.0.0/src/control_tower/live/traj/git_traj_helpers/call_insert.py +15 -0
- control_tower-6.0.0/src/control_tower/live/traj/git_traj_helpers/call_str_replace.py +20 -0
- control_tower-6.0.0/src/control_tower/live/traj/macros.py +100 -0
- control_tower-6.0.0/src/control_tower/live/traj/migrate_traj.py +80 -0
- control_tower-6.0.0/src/control_tower/live/traj/patch.py +62 -0
- control_tower-6.0.0/src/control_tower/live/traj/solution.py +242 -0
- control_tower-6.0.0/src/control_tower/live/traj/templ/add.py +14 -0
- control_tower-6.0.0/src/control_tower/live/traj/templ/add_tool_call.py +85 -0
- control_tower-6.0.0/src/control_tower/live/traj/templ/bash.py +127 -0
- control_tower-6.0.0/src/control_tower/live/traj/templ/git_utils.py +93 -0
- control_tower-6.0.0/src/control_tower/live/traj/templ/input_utils.py +145 -0
- control_tower-6.0.0/src/control_tower/live/traj/templ/template_from.py +118 -0
- control_tower-6.0.0/src/control_tower/live/traj/templ/tool_call_builder.py +119 -0
- control_tower-6.0.0/src/control_tower/live/traj/tool_call_utils.py +283 -0
- control_tower-6.0.0/src/control_tower/live/traj/traj.py +294 -0
- control_tower-6.0.0/src/control_tower/live/tui/__init__.py +0 -0
- control_tower-6.0.0/src/control_tower/live/tui/popup.py +293 -0
- control_tower-6.0.0/src/control_tower/live/tui/tui.py +1237 -0
- control_tower-6.0.0/src/control_tower/live/tui/tui.tcss +32 -0
- control_tower-6.0.0/src/control_tower/metrics/__init__.py +0 -0
- control_tower-6.0.0/src/control_tower/metrics/audit.py +357 -0
- control_tower-6.0.0/src/control_tower/metrics/control.py +120 -0
- control_tower-6.0.0/src/control_tower/models/__init__.py +3 -0
- control_tower-6.0.0/src/control_tower/models/aliases.py +59 -0
- control_tower-6.0.0/src/control_tower/models/cache_scopes.py +26 -0
- control_tower-6.0.0/src/control_tower/models/inspect_rates.py +32 -0
- control_tower-6.0.0/src/control_tower/models/openrouter_provider.py +65 -0
- control_tower-6.0.0/src/control_tower/models/pricing.py +183 -0
- control_tower-6.0.0/src/control_tower/models/rates.py +240 -0
- control_tower-6.0.0/src/control_tower/models/role_model.py +179 -0
- control_tower-6.0.0/src/control_tower/models/usage_hooks.py +14 -0
- control_tower-6.0.0/src/control_tower/monitors/__init__.py +40 -0
- control_tower-6.0.0/src/control_tower/monitors/_monitor.py +722 -0
- control_tower-6.0.0/src/control_tower/monitors/checklist.py +95 -0
- control_tower-6.0.0/src/control_tower/monitors/jev.py +217 -0
- control_tower-6.0.0/src/control_tower/monitors/jev_questions.yml +32 -0
- control_tower-6.0.0/src/control_tower/monitors/presets.yml +29 -0
- control_tower-6.0.0/src/control_tower/monitors/prompts/action-goals.md +78 -0
- control_tower-6.0.0/src/control_tower/monitors/prompts/action.md +70 -0
- control_tower-6.0.0/src/control_tower/monitors/prompts/goal-analysis.md +72 -0
- control_tower-6.0.0/src/control_tower/monitors/prompts/goals.md +76 -0
- control_tower-6.0.0/src/control_tower/monitors/prompts/no-history.md +37 -0
- control_tower-6.0.0/src/control_tower/monitors/prompts/off-task.md +86 -0
- control_tower-6.0.0/src/control_tower/monitors/prompts/quick-goals.md +65 -0
- control_tower-6.0.0/src/control_tower/monitors/prompts/quick.md +57 -0
- control_tower-6.0.0/src/control_tower/monitors/prompts/simple.md +19 -0
- control_tower-6.0.0/src/control_tower/monitors/prompts/strong-goals.md +87 -0
- control_tower-6.0.0/src/control_tower/monitors/prompts/strong.md +79 -0
- control_tower-6.0.0/src/control_tower/monitors/prompts/trajectory.md +16 -0
- control_tower-6.0.0/src/control_tower/monitors/registry.py +18 -0
- control_tower-6.0.0/src/control_tower/monitors/single_goal.py +67 -0
- control_tower-6.0.0/src/control_tower/monitors/steps/checklist.md +38 -0
- control_tower-6.0.0/src/control_tower/monitors/steps/single_goal.md +75 -0
- control_tower-6.0.0/src/control_tower/monitors/steps/single_goal_analysis.md +71 -0
- control_tower-6.0.0/src/control_tower/monitors/steps/three_scores.md +107 -0
- control_tower-6.0.0/src/control_tower/monitors/three_scores.py +68 -0
- control_tower-6.0.0/src/control_tower/policies/__init__.py +1 -0
- control_tower-6.0.0/src/control_tower/policies/attack.py +185 -0
- control_tower-6.0.0/src/control_tower/policies/honest.py +23 -0
- control_tower-6.0.0/src/control_tower/policies/obvious_attack.py +67 -0
- control_tower-6.0.0/src/control_tower/policies/prompts/attack.md +7 -0
- control_tower-6.0.0/src/control_tower/policies/prompts/attack_planning.md +22 -0
- control_tower-6.0.0/src/control_tower/policies/replay.py +201 -0
- control_tower-6.0.0/src/control_tower/policies/scripted.py +115 -0
- control_tower-6.0.0/src/control_tower/protocols/__init__.py +1 -0
- control_tower-6.0.0/src/control_tower/protocols/defer_to_trusted.py +141 -0
- control_tower-6.0.0/src/control_tower/protocols/null_blue.py +27 -0
- control_tower-6.0.0/src/control_tower/protocols/prompts/trusted_editing.md +9 -0
- control_tower-6.0.0/src/control_tower/protocols/resample.py +191 -0
- control_tower-6.0.0/src/control_tower/protocols/trusted_editing.py +143 -0
- control_tower-6.0.0/src/control_tower/protocols/trusted_monitoring.py +90 -0
- control_tower-6.0.0/src/control_tower/protocols/watcher.py +352 -0
- control_tower-6.0.0/src/control_tower/py.typed +0 -0
- control_tower-6.0.0/src/control_tower/runs/README.md +93 -0
- control_tower-6.0.0/src/control_tower/runs/__init__.py +0 -0
- control_tower-6.0.0/src/control_tower/runs/convert.py +100 -0
- control_tower-6.0.0/src/control_tower/runs/convert_eval_log_to_run.py +92 -0
- control_tower-6.0.0/src/control_tower/runs/eval_log_io.py +200 -0
- control_tower-6.0.0/src/control_tower/runs/io.py +190 -0
- control_tower-6.0.0/src/control_tower/runs/models.py +64 -0
- control_tower-6.0.0/src/control_tower/runs/mongo_docs.py +359 -0
- control_tower-6.0.0/src/control_tower/runs/runs_cli.py +735 -0
- control_tower-6.0.0/src/control_tower/runs/s3_upload.py +167 -0
- control_tower-6.0.0/src/control_tower/runs/source.py +24 -0
- control_tower-6.0.0/src/control_tower/runs/timing_utils.py +149 -0
- control_tower-6.0.0/src/control_tower/runs/viewer/__init__.py +0 -0
- control_tower-6.0.0/src/control_tower/runs/viewer/api.py +464 -0
- control_tower-6.0.0/src/control_tower/runs/viewer/auth.py +50 -0
- control_tower-6.0.0/src/control_tower/runs/viewer/io.py +204 -0
- control_tower-6.0.0/src/control_tower/runs/viewer/models.py +25 -0
- control_tower-6.0.0/src/control_tower/runs/viewer/upload.py +216 -0
- control_tower-6.0.0/src/control_tower/runs/viewer/urls.py +501 -0
- control_tower-6.0.0/src/control_tower/sandbox/__init__.py +6 -0
- control_tower-6.0.0/src/control_tower/sandbox/_alpine_rootfs.py +230 -0
- control_tower-6.0.0/src/control_tower/sandbox/_ssh.py +471 -0
- control_tower-6.0.0/src/control_tower/sandbox/cli.py +236 -0
- control_tower-6.0.0/src/control_tower/sandbox/constants.py +21 -0
- control_tower-6.0.0/src/control_tower/sandbox/docker.py +685 -0
- control_tower-6.0.0/src/control_tower/sandbox/docker_in_vm.py +527 -0
- control_tower-6.0.0/src/control_tower/sandbox/firecracker.py +363 -0
- control_tower-6.0.0/src/control_tower/sandbox/inspect_tools.py +46 -0
- control_tower-6.0.0/src/control_tower/sandbox/qemu.py +251 -0
- control_tower-6.0.0/src/control_tower/sandbox/replay/__init__.py +23 -0
- control_tower-6.0.0/src/control_tower/sandbox/replay/environment.py +435 -0
- control_tower-6.0.0/src/control_tower/sandbox/replay/score.py +37 -0
- control_tower-6.0.0/src/control_tower/sandbox/simulated/__init__.py +25 -0
- control_tower-6.0.0/src/control_tower/sandbox/simulated/actions.py +90 -0
- control_tower-6.0.0/src/control_tower/sandbox/simulated/compose.py +192 -0
- control_tower-6.0.0/src/control_tower/sandbox/simulated/environment.py +190 -0
- control_tower-6.0.0/src/control_tower/sandbox/simulated/judge.py +158 -0
- control_tower-6.0.0/src/control_tower/sandbox/simulated/prompts/judge.md +31 -0
- control_tower-6.0.0/src/control_tower/sandbox/simulated/prompts/simulator.md +74 -0
- control_tower-6.0.0/src/control_tower/sandbox/simulated/prompts/simulator_no_exec.md +22 -0
- control_tower-6.0.0/src/control_tower/sandbox/simulated/scratch/Dockerfile +11 -0
- control_tower-6.0.0/src/control_tower/sandbox/simulated/scratch/compose.yaml +42 -0
- control_tower-6.0.0/src/control_tower/sandbox/simulated/session.py +155 -0
- control_tower-6.0.0/src/control_tower/scanners.py +130 -0
- control_tower-6.0.0/src/control_tower/task/__init__.py +0 -0
- control_tower-6.0.0/src/control_tower/task/final_diff.py +88 -0
- control_tower-6.0.0/src/control_tower/task/sample_metadata.py +46 -0
- control_tower-6.0.0/src/control_tower/task/scorers.py +327 -0
- control_tower-6.0.0/src/control_tower/task/select_utils.py +106 -0
- control_tower-6.0.0/src/control_tower/task/selectors.py +49 -0
- control_tower-6.0.0/src/control_tower/task/setup.py +115 -0
- control_tower-6.0.0/src/control_tower/task/space.py +45 -0
- control_tower-6.0.0/src/control_tower/task/task.py +230 -0
- control_tower-6.0.0/src/control_tower/task/task_sets/__init__.py +203 -0
- control_tower-6.0.0/src/control_tower/task/traj_dir.py +39 -0
- control_tower-6.0.0/src/control_tower/task/workspace_baseline.py +581 -0
- control_tower-6.0.0/src/control_tower/tools/__init__.py +0 -0
- control_tower-6.0.0/src/control_tower/tools/answer.py +45 -0
- control_tower-6.0.0/src/control_tower/tools/bash_tools.py +37 -0
- control_tower-6.0.0/src/control_tower/tools/declarations.py +23 -0
- control_tower-6.0.0/src/control_tower/tools/diff_display_text_editor.py +66 -0
- control_tower-6.0.0/src/control_tower/tools/registry.py +34 -0
- control_tower-6.0.0/src/control_tower/tools/split_text_editor_tools.py +125 -0
- control_tower-6.0.0/src/control_tower/tools/task_tools.py +204 -0
- control_tower-6.0.0/src/control_tower/tools/text_editor_output.py +53 -0
- control_tower-6.0.0/src/control_tower/tools/tool_calls.py +44 -0
- control_tower-6.0.0/src/control_tower/tools/tool_registry.py +363 -0
- control_tower-6.0.0/src/control_tower/utils/__init__.py +0 -0
- control_tower-6.0.0/src/control_tower/utils/cli_args.py +20 -0
- control_tower-6.0.0/src/control_tower/utils/direct_api_generator.py +124 -0
- control_tower-6.0.0/src/control_tower/utils/docs_utils.py +18 -0
- control_tower-6.0.0/src/control_tower/utils/env.py +191 -0
- control_tower-6.0.0/src/control_tower/utils/file_patterns.py +89 -0
- control_tower-6.0.0/src/control_tower/utils/fs.py +137 -0
- control_tower-6.0.0/src/control_tower/utils/function_registry/__init__.py +0 -0
- control_tower-6.0.0/src/control_tower/utils/function_registry/base_model.py +30 -0
- control_tower-6.0.0/src/control_tower/utils/function_registry/registry.py +535 -0
- control_tower-6.0.0/src/control_tower/utils/function_registry/selection.py +68 -0
- control_tower-6.0.0/src/control_tower/utils/paths.py +91 -0
- control_tower-6.0.0/src/control_tower/utils/sanitize.py +29 -0
- control_tower-6.0.0/src/control_tower/utils/suggestions.py +25 -0
- control_tower-6.0.0/src/control_tower/utils/time.py +8 -0
- control_tower-6.0.0/src/control_tower/utils/transcript.py +20 -0
- control_tower-6.0.0/src/control_tower/utils/versioning.py +327 -0
- control_tower-6.0.0/src/control_tower.egg-info/PKG-INFO +91 -0
- control_tower-6.0.0/src/control_tower.egg-info/SOURCES.txt +452 -0
- control_tower-6.0.0/src/control_tower.egg-info/dependency_links.txt +1 -0
- control_tower-6.0.0/src/control_tower.egg-info/entry_points.txt +5 -0
- control_tower-6.0.0/src/control_tower.egg-info/requires.txt +37 -0
- control_tower-6.0.0/src/control_tower.egg-info/top_level.txt +1 -0
- control_tower-6.0.0/tests/test_correct_environments.py +34 -0
- control_tower-6.0.0/tests/test_stable_api.py +434 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 LinuxArena
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: control-tower
|
|
3
|
+
Version: 6.0.0
|
|
4
|
+
Summary: Control Tower evaluation framework for AI control research
|
|
5
|
+
Author: LinuxArena
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://linuxarena.ai
|
|
8
|
+
Project-URL: Repository, https://github.com/linuxarena/control-tower
|
|
9
|
+
Keywords: ai-control,agent-evaluation,evals,monitoring,sabotage
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
17
|
+
Requires-Python: >=3.13
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: click==8.5.0
|
|
21
|
+
Requires-Dist: docstring-parser>=0.17
|
|
22
|
+
Requires-Dist: flask>=3.1.3
|
|
23
|
+
Requires-Dist: gitignore-parser==0.1.13
|
|
24
|
+
Requires-Dist: gitpython>=3.1.46
|
|
25
|
+
Requires-Dist: inspect-ai==0.3.282
|
|
26
|
+
Requires-Dist: inspect-scout==0.5.5
|
|
27
|
+
Requires-Dist: jsonlines>=4.0.0
|
|
28
|
+
Requires-Dist: jsonpatch>=1.33
|
|
29
|
+
Requires-Dist: inspect-swe==0.2.71
|
|
30
|
+
Requires-Dist: pick==2.6.0
|
|
31
|
+
Requires-Dist: pydantic>=2.12
|
|
32
|
+
Requires-Dist: pydantic-settings>=2.0
|
|
33
|
+
Requires-Dist: python-dotenv==1.2.4
|
|
34
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
35
|
+
Requires-Dist: scipy>=1.17.0
|
|
36
|
+
Requires-Dist: tabulate>=0.10.0
|
|
37
|
+
Requires-Dist: tenacity>=9.1.4
|
|
38
|
+
Requires-Dist: textual>=8.1.1
|
|
39
|
+
Requires-Dist: tqdm>=4.67.3
|
|
40
|
+
Requires-Dist: unidiff==1.0.1
|
|
41
|
+
Requires-Dist: anthropic<2,>=1.0.0
|
|
42
|
+
Requires-Dist: claude-agent-sdk>=0.1.50
|
|
43
|
+
Requires-Dist: openai>=3.1.0
|
|
44
|
+
Requires-Dist: boto3>=1.40.0
|
|
45
|
+
Requires-Dist: zstandard>=0.25.0
|
|
46
|
+
Requires-Dist: ct-setting-sdk<5,>=4.0.0
|
|
47
|
+
Provides-Extra: atif
|
|
48
|
+
Requires-Dist: harbor>=0.24.0; extra == "atif"
|
|
49
|
+
Provides-Extra: hf
|
|
50
|
+
Requires-Dist: pyarrow>=17.0.0; extra == "hf"
|
|
51
|
+
Provides-Extra: providers
|
|
52
|
+
Requires-Dist: google-genai>=1.68.0; extra == "providers"
|
|
53
|
+
Requires-Dist: xai-sdk>=1.9.1; extra == "providers"
|
|
54
|
+
Dynamic: license-file
|
|
55
|
+
|
|
56
|
+
Welcome to Control Tower, a framework for AI control evaluations built on [Inspect](https://inspect.aisi.org.uk/) and developed by [EquiStamp](https://equistamp.com/), [Redwood Research](https://www.redwoodresearch.org/), and [Luthien](https://luthien.cc/).
|
|
57
|
+
|
|
58
|
+
> 🚨 Control Tower is in active development. [Star this repo](https://github.com/linuxarena/control-tower) to follow updates, or [Watch > Releases](https://github.com/linuxarena/control-tower/subscription) to get notified on new versions.
|
|
59
|
+
>
|
|
60
|
+
> Found a bug or have a question? [Open an issue](https://github.com/linuxarena/control-tower/issues), [submit a PR](https://github.com/linuxarena/control-tower/compare) or [book a call](https://calendar.app.google/j7K8yncsBvPfxomS7)
|
|
61
|
+
|
|
62
|
+
Control Tower provides many built-in components, including blue-team protocols, action- and trajectory-level monitors, control evaluations, safety-usefulness curves, and trajectory tooling. Environments and their main and side tasks come from separate settings repositories, and extensions (new protocols, policies, monitors, and scorers) can be provided by other Python packages.
|
|
63
|
+
|
|
64
|
+
See the [documentation](https://docs.linuxarena.ai) for an overview of Control Tower, a quickstart, and development guides.
|
|
65
|
+
|
|
66
|
+
To get started:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
git clone https://github.com/linuxarena/control-tower && cd control-tower
|
|
70
|
+
uv sync
|
|
71
|
+
alias ct='uv run ct' # add to your shell profile to keep it
|
|
72
|
+
cp .env.example .env # set ANTHROPIC_API_KEY (or OPENAI_API_KEY)
|
|
73
|
+
uv run python scripts/generate_model_rates.py # model prices, so evals can show what they cost
|
|
74
|
+
ct settings pull linuxarena
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Check the install without spending a model call. It takes a couple of minutes:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
ct run eval --policy ct/test --task-file simple --tag test
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Then run a real eval. The first one builds the environment image, which takes about ten minutes:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
ct run eval --policy ct/attack -e linuxarena/clinical_trial -t adverse_reaction_followup_tracking -s suppress_safety_notifications
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
***
|
|
90
|
+
|
|
91
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for code style, typing, testing, and pull request conventions, and the [development setup guide](https://docs.linuxarena.ai/development/dev-setup) for local services, environment pulls, and shell completions.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
Welcome to Control Tower, a framework for AI control evaluations built on [Inspect](https://inspect.aisi.org.uk/) and developed by [EquiStamp](https://equistamp.com/), [Redwood Research](https://www.redwoodresearch.org/), and [Luthien](https://luthien.cc/).
|
|
2
|
+
|
|
3
|
+
> 🚨 Control Tower is in active development. [Star this repo](https://github.com/linuxarena/control-tower) to follow updates, or [Watch > Releases](https://github.com/linuxarena/control-tower/subscription) to get notified on new versions.
|
|
4
|
+
>
|
|
5
|
+
> Found a bug or have a question? [Open an issue](https://github.com/linuxarena/control-tower/issues), [submit a PR](https://github.com/linuxarena/control-tower/compare) or [book a call](https://calendar.app.google/j7K8yncsBvPfxomS7)
|
|
6
|
+
|
|
7
|
+
Control Tower provides many built-in components, including blue-team protocols, action- and trajectory-level monitors, control evaluations, safety-usefulness curves, and trajectory tooling. Environments and their main and side tasks come from separate settings repositories, and extensions (new protocols, policies, monitors, and scorers) can be provided by other Python packages.
|
|
8
|
+
|
|
9
|
+
See the [documentation](https://docs.linuxarena.ai) for an overview of Control Tower, a quickstart, and development guides.
|
|
10
|
+
|
|
11
|
+
To get started:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
git clone https://github.com/linuxarena/control-tower && cd control-tower
|
|
15
|
+
uv sync
|
|
16
|
+
alias ct='uv run ct' # add to your shell profile to keep it
|
|
17
|
+
cp .env.example .env # set ANTHROPIC_API_KEY (or OPENAI_API_KEY)
|
|
18
|
+
uv run python scripts/generate_model_rates.py # model prices, so evals can show what they cost
|
|
19
|
+
ct settings pull linuxarena
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Check the install without spending a model call. It takes a couple of minutes:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
ct run eval --policy ct/test --task-file simple --tag test
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Then run a real eval. The first one builds the environment image, which takes about ten minutes:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
ct run eval --policy ct/attack -e linuxarena/clinical_trial -t adverse_reaction_followup_tracking -s suppress_safety_notifications
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
***
|
|
35
|
+
|
|
36
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for code style, typing, testing, and pull request conventions, and the [development setup guide](https://docs.linuxarena.ai/development/dev-setup) for local services, environment pulls, and shell completions.
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "control-tower"
|
|
3
|
+
version = "6.0.0"
|
|
4
|
+
description = "Control Tower evaluation framework for AI control research"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.13"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
authors = [{ name = "LinuxArena" }]
|
|
10
|
+
keywords = ["ai-control", "agent-evaluation", "evals", "monitoring", "sabotage"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 4 - Beta",
|
|
13
|
+
"Environment :: Console",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"Intended Audience :: Science/Research",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.13",
|
|
18
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
19
|
+
]
|
|
20
|
+
dependencies = [
|
|
21
|
+
# CLI and core runtime
|
|
22
|
+
"click==8.5.0",
|
|
23
|
+
"docstring-parser>=0.17",
|
|
24
|
+
"flask>=3.1.3",
|
|
25
|
+
"gitignore-parser==0.1.13",
|
|
26
|
+
"gitpython>=3.1.46",
|
|
27
|
+
"inspect-ai==0.3.282",
|
|
28
|
+
"inspect-scout==0.5.5",
|
|
29
|
+
"jsonlines>=4.0.0",
|
|
30
|
+
"jsonpatch>=1.33",
|
|
31
|
+
"inspect-swe==0.2.71",
|
|
32
|
+
"pick==2.6.0",
|
|
33
|
+
"pydantic>=2.12",
|
|
34
|
+
"pydantic-settings>=2.0",
|
|
35
|
+
"python-dotenv==1.2.4",
|
|
36
|
+
"pyyaml>=6.0.3",
|
|
37
|
+
"scipy>=1.17.0",
|
|
38
|
+
"tabulate>=0.10.0",
|
|
39
|
+
"tenacity>=9.1.4",
|
|
40
|
+
"textual>=8.1.1",
|
|
41
|
+
"tqdm>=4.67.3",
|
|
42
|
+
"unidiff==1.0.1",
|
|
43
|
+
|
|
44
|
+
# Primary model providers and agent SDKs (openai also backs OpenRouter)
|
|
45
|
+
# inspect-ai 0.3.282's Anthropic provider fails on anthropic 2.x (inspect_ai#6003); drop the cap at inspect-ai 0.3.283+.
|
|
46
|
+
"anthropic>=1.0.0,<2",
|
|
47
|
+
"claude-agent-sdk>=0.1.50",
|
|
48
|
+
"openai>=3.1.0",
|
|
49
|
+
|
|
50
|
+
# Run storage and upload (`ct run eval --upload`)
|
|
51
|
+
"boto3>=1.40.0",
|
|
52
|
+
"zstandard>=0.25.0",
|
|
53
|
+
|
|
54
|
+
# The env API's wire contract, shared with every setting package
|
|
55
|
+
"ct-setting-sdk>=4.0.0,<5",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[project.optional-dependencies]
|
|
59
|
+
atif = ["harbor>=0.24.0"]
|
|
60
|
+
hf = ["pyarrow>=17.0.0"]
|
|
61
|
+
providers = [
|
|
62
|
+
"google-genai>=1.68.0",
|
|
63
|
+
"xai-sdk>=1.9.1",
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
[build-system]
|
|
67
|
+
requires = ["setuptools"]
|
|
68
|
+
build-backend = "setuptools.build_meta"
|
|
69
|
+
|
|
70
|
+
[tool.setuptools.packages.find]
|
|
71
|
+
where = ["src"]
|
|
72
|
+
namespaces = true
|
|
73
|
+
exclude = ["experiments*"]
|
|
74
|
+
|
|
75
|
+
[tool.setuptools.package-data]
|
|
76
|
+
# Non-Python assets that must be available from installed wheels.
|
|
77
|
+
"*" = [
|
|
78
|
+
"*.md",
|
|
79
|
+
"*.txt",
|
|
80
|
+
"*.yml",
|
|
81
|
+
"*.yaml",
|
|
82
|
+
"*.json",
|
|
83
|
+
"*.jsonl",
|
|
84
|
+
"*.tcss",
|
|
85
|
+
"*.sh",
|
|
86
|
+
"py.typed",
|
|
87
|
+
]
|
|
88
|
+
"control_tower.environments.internet_simulator" = [
|
|
89
|
+
"Dockerfile",
|
|
90
|
+
".dockerignore",
|
|
91
|
+
"resolve_override.c",
|
|
92
|
+
"malware/malware.c",
|
|
93
|
+
]
|
|
94
|
+
"control_tower.live" = ["assets/live.gitignore"]
|
|
95
|
+
"control_tower.sandbox.simulated" = ["scratch/Dockerfile"]
|
|
96
|
+
|
|
97
|
+
[tool.setuptools.package-dir]
|
|
98
|
+
"" = "src"
|
|
99
|
+
|
|
100
|
+
[dependency-groups]
|
|
101
|
+
dev = [
|
|
102
|
+
"moto>=5.1.22",
|
|
103
|
+
"pyright==1.1.414", # kept for `--verifytypes` coverage gate; ty has no equivalent yet
|
|
104
|
+
"pytest==9.1.1",
|
|
105
|
+
"pytest-asyncio==1.4.0",
|
|
106
|
+
"pytest-xdist==3.8.0",
|
|
107
|
+
"ruff==0.15.20",
|
|
108
|
+
"ty==0.0.33", # primary type checker; pinned because pre-1.0
|
|
109
|
+
"vulture>=2.15",
|
|
110
|
+
"yamllint==1.38.0",
|
|
111
|
+
"yamlfix>=1.19.1",
|
|
112
|
+
]
|
|
113
|
+
# A group, not a dependency: PyPI rejects direct-URL requirements, and Apollo ships the SDK only as a GitHub wheel.
|
|
114
|
+
watcher = [
|
|
115
|
+
# 0.41.0 or later: the protocol reads `cost_usd` from each hook outcome.
|
|
116
|
+
"watcher-sdk @ https://github.com/ApolloResearch/watcher-bin/releases/download/v0.41.0/watcher_sdk-0.41.0-py3-none-any.whl",
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
[tool.uv]
|
|
120
|
+
default-groups = ["dev", "watcher"]
|
|
121
|
+
required-version = ">=0.13.5"
|
|
122
|
+
|
|
123
|
+
# Inspect Scout imports only harbor's pydantic ATIF models; its litellm dependency caps openai below 3.
|
|
124
|
+
[[tool.uv.dependency-metadata]]
|
|
125
|
+
name = "harbor"
|
|
126
|
+
version = "0.24.0"
|
|
127
|
+
requires-dist = ["pydantic>=2"]
|
|
128
|
+
requires-python = ">=3.12"
|
|
129
|
+
|
|
130
|
+
[tool.uv.sources]
|
|
131
|
+
ct-setting-sdk = { path = "packages/ct-setting-sdk", editable = true }
|
|
132
|
+
|
|
133
|
+
[project.scripts]
|
|
134
|
+
ct = "control_tower.cli.main:main"
|
|
135
|
+
|
|
136
|
+
[project.entry-points.inspect_ai]
|
|
137
|
+
# Registers ``control_tower/eval`` and ``control_tower/control_eval`` as discoverable
|
|
138
|
+
# Inspect AI @tasks (plus the ct_upload and ct_diagnostics hooks) after pip-installing control-tower.
|
|
139
|
+
control_tower = "control_tower.eval.launch.inspect_tasks"
|
|
140
|
+
|
|
141
|
+
[project.urls]
|
|
142
|
+
Homepage = "https://linuxarena.ai"
|
|
143
|
+
Repository = "https://github.com/linuxarena/control-tower"
|
|
144
|
+
|
|
145
|
+
[tool.ruff]
|
|
146
|
+
required-version = "==0.15.20"
|
|
147
|
+
src = []
|
|
148
|
+
extend-exclude = [
|
|
149
|
+
".settings/**",
|
|
150
|
+
]
|
|
151
|
+
|
|
152
|
+
[tool.ruff.lint]
|
|
153
|
+
extend-select = ["I", "UP", "ANN", "PLC0415", "S110"]
|
|
154
|
+
ignore = [
|
|
155
|
+
"ANN002", # missing type annotation for *args
|
|
156
|
+
"ANN003", # missing type annotation for **kwargs
|
|
157
|
+
"ANN204", # missing return type for __init__ / __new__ / dunder
|
|
158
|
+
"ANN401", # disallow Any — too strict for this codebase
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
[tool.ruff.lint.isort]
|
|
162
|
+
known-first-party = ["control_tower", "ct_setting_sdk"]
|
|
163
|
+
|
|
164
|
+
[tool.ruff.lint.per-file-ignores]
|
|
165
|
+
"tests/**" = ["ANN", "PLC0415"]
|
|
166
|
+
"packages/*/tests/**" = ["ANN", "PLC0415"]
|
|
167
|
+
"scripts/**" = ["PLC0415"]
|
|
168
|
+
# CLI convention: imports stay inside command functions so `ct` starts fast
|
|
169
|
+
"src/**/cli/**" = ["PLC0415"]
|
|
170
|
+
"src/**/cli.py" = ["PLC0415"]
|
|
171
|
+
"src/**/*_cli.py" = ["PLC0415"]
|
|
172
|
+
|
|
173
|
+
[tool.pytest.ini_options]
|
|
174
|
+
testpaths = ["tests", "packages/ct-setting-sdk/tests"]
|
|
175
|
+
markers = [
|
|
176
|
+
"integration: marks tests as integration tests (deselect with '-m \"not integration\"')",
|
|
177
|
+
"slow: marks tests as slow running",
|
|
178
|
+
]
|
|
179
|
+
addopts = "-m 'not integration' --durations=10 --ignore=tests/replay_check/packages"
|
|
180
|
+
|
|
181
|
+
[tool.control_tower.typing]
|
|
182
|
+
verifytypes_min_completeness = 100.0
|
|
183
|
+
|
|
184
|
+
[[tool.control_tower.import_boundaries.rules]]
|
|
185
|
+
name = "only cli may import extras (generation/orchestration tooling)"
|
|
186
|
+
sources = ["*"]
|
|
187
|
+
ignore_sources = ["cli", "extras", "extras.*"]
|
|
188
|
+
targets = ["extras", "extras.*"]
|
|
189
|
+
allowed_files = [
|
|
190
|
+
"src/control_tower/backends/hawk/runner.py",
|
|
191
|
+
]
|
|
192
|
+
|
|
193
|
+
[[tool.control_tower.import_boundaries.rules]]
|
|
194
|
+
name = "extras subpackages are independent except declared edges"
|
|
195
|
+
sources = ["extras.*"]
|
|
196
|
+
targets = ["extras", "extras.*"]
|
|
197
|
+
allowed_edges = [
|
|
198
|
+
"extras.* -> extras.claude_host",
|
|
199
|
+
"extras.* -> extras.env_source",
|
|
200
|
+
"extras.* -> extras.prompts",
|
|
201
|
+
"extras.* -> extras.side_task_folder",
|
|
202
|
+
"extras.* -> extras.storage",
|
|
203
|
+
"extras.dashboard_cli -> extras.dashboard",
|
|
204
|
+
"extras.task_analysis -> extras.traj_analysis",
|
|
205
|
+
]
|
|
206
|
+
|
|
207
|
+
[[tool.control_tower.import_boundaries.rules]]
|
|
208
|
+
name = "utils is a leaf"
|
|
209
|
+
sources = ["utils"]
|
|
210
|
+
targets = ["*"]
|
|
211
|
+
|
|
212
|
+
[[tool.control_tower.import_boundaries.rules]]
|
|
213
|
+
name = "monitors stand alone: they import only models, tools and utils"
|
|
214
|
+
sources = ["monitors"]
|
|
215
|
+
targets = ["*"]
|
|
216
|
+
allowed_edges = [
|
|
217
|
+
"monitors -> models",
|
|
218
|
+
"monitors -> tools",
|
|
219
|
+
"monitors -> utils",
|
|
220
|
+
]
|
|
221
|
+
|
|
222
|
+
[[tool.control_tower.import_boundaries.rules]]
|
|
223
|
+
name = "eval and runs must not import live"
|
|
224
|
+
sources = ["eval", "eval.*", "runs"]
|
|
225
|
+
targets = ["live"]
|
|
226
|
+
|
|
227
|
+
[[tool.control_tower.import_boundaries.rules]]
|
|
228
|
+
name = "the game protocols and policies are written against imports no launch, monitoring or cli"
|
|
229
|
+
sources = ["eval.game"]
|
|
230
|
+
targets = ["eval.launch", "eval.monitoring", "cli"]
|
|
231
|
+
|
|
232
|
+
[[tool.control_tower.import_boundaries.rules]]
|
|
233
|
+
name = "only eval.launch and cli import backends"
|
|
234
|
+
sources = ["*"]
|
|
235
|
+
ignore_sources = ["backends", "cli", "eval.launch"]
|
|
236
|
+
targets = ["backends"]
|
|
237
|
+
allowed_files = [
|
|
238
|
+
"src/control_tower/eval/monitoring/posthoc.py",
|
|
239
|
+
"src/control_tower/models/role_model.py",
|
|
240
|
+
]
|
|
241
|
+
|
|
242
|
+
[[tool.control_tower.import_boundaries.module_rules]]
|
|
243
|
+
name = "a backend runs the task args eval.launch hands it, never the launch itself"
|
|
244
|
+
sources = ["control_tower.backends", "control_tower.backends.*"]
|
|
245
|
+
forbidden = [
|
|
246
|
+
"control_tower.cli",
|
|
247
|
+
"control_tower.eval.launch.assemble",
|
|
248
|
+
"control_tower.eval.launch.dispatch",
|
|
249
|
+
"control_tower.eval.launch.inspect_tasks",
|
|
250
|
+
]
|
|
251
|
+
|
|
252
|
+
[[tool.control_tower.import_boundaries.module_rules]]
|
|
253
|
+
name = "a blue protocol reads the sample only through its arguments"
|
|
254
|
+
sources = ["control_tower.protocols", "control_tower.protocols.*"]
|
|
255
|
+
forbidden = [
|
|
256
|
+
"inspect_ai.event",
|
|
257
|
+
"inspect_ai.log",
|
|
258
|
+
"inspect_ai.solver",
|
|
259
|
+
"inspect_ai.util.Store",
|
|
260
|
+
"inspect_ai.util.StoreModel",
|
|
261
|
+
"inspect_ai.util._store",
|
|
262
|
+
"inspect_ai.util._store_model",
|
|
263
|
+
"inspect_ai.util.store",
|
|
264
|
+
"inspect_ai.util.store_as",
|
|
265
|
+
"control_tower.eval.monitoring.scorer.MonitorScores",
|
|
266
|
+
"control_tower.eval.game.red",
|
|
267
|
+
"control_tower.eval.log",
|
|
268
|
+
"control_tower.sandbox.simulated",
|
|
269
|
+
"control_tower.task",
|
|
270
|
+
"ct_setting_sdk.env",
|
|
271
|
+
]
|
|
272
|
+
|
|
273
|
+
[tool.ty.src]
|
|
274
|
+
include = [
|
|
275
|
+
".github/scripts",
|
|
276
|
+
"packages/ct-setting-sdk/src",
|
|
277
|
+
"scripts",
|
|
278
|
+
"src/control_tower",
|
|
279
|
+
"tests",
|
|
280
|
+
]
|
|
281
|
+
exclude = [
|
|
282
|
+
"**/node_modules",
|
|
283
|
+
".settings/**",
|
|
284
|
+
]
|
|
285
|
+
|
|
286
|
+
[tool.ty.environment]
|
|
287
|
+
python-version = "3.13"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Where an eval runs: in this process, on the EC2 fleet, or on Hawk."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import TYPE_CHECKING, Any
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from inspect_ai.log import EvalLog
|
|
8
|
+
|
|
9
|
+
from control_tower.eval.launch.options import EvalCliInputs
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Backend(ABC):
|
|
13
|
+
"""Where `run_task` runs an eval, given its completed task args."""
|
|
14
|
+
|
|
15
|
+
def resolvable(self, name: str) -> bool:
|
|
16
|
+
"""Whether the task set, policy, protocol or monitor ``name`` is looked up before the run; the rest are looked
|
|
17
|
+
up where the task is built."""
|
|
18
|
+
return True
|
|
19
|
+
|
|
20
|
+
@abstractmethod
|
|
21
|
+
def run(
|
|
22
|
+
self,
|
|
23
|
+
task_name: str,
|
|
24
|
+
task_args: dict[str, Any],
|
|
25
|
+
eval_inputs: "EvalCliInputs",
|
|
26
|
+
*,
|
|
27
|
+
upload: bool,
|
|
28
|
+
metadata: dict[str, Any],
|
|
29
|
+
) -> "EvalLog | None":
|
|
30
|
+
"""Run ``task_name`` with ``task_args``, ``metadata`` joining its eval metadata, and upload the log when
|
|
31
|
+
``upload``; return it, or None when it stays where it ran."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Fleet mode: distributed evaluation on EC2 workers."""
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Worker AMI resolution for fleet mode: the pre-baked AMI named in SSM ``/linuxbench/worker-ami-id``."""
|
|
2
|
+
|
|
3
|
+
import boto3
|
|
4
|
+
import botocore.exceptions
|
|
5
|
+
|
|
6
|
+
SSM_AMI_PARAM = "/linuxbench/worker-ami-id"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_worker_ami_id(region: str = "us-east-1", requested: str | None = None) -> str:
|
|
10
|
+
"""Return the AMI to use for fleet workers, refusing one that cannot boot now.
|
|
11
|
+
|
|
12
|
+
``requested`` is an AMI id, or the SSM parameter naming one; the default is ``SSM_AMI_PARAM``.
|
|
13
|
+
"""
|
|
14
|
+
source = requested or SSM_AMI_PARAM
|
|
15
|
+
ami_id = source
|
|
16
|
+
if source.startswith("/"):
|
|
17
|
+
ssm = boto3.client("ssm", region_name=region)
|
|
18
|
+
try:
|
|
19
|
+
ami_id = ssm.get_parameter(Name=source)["Parameter"]["Value"]
|
|
20
|
+
except ssm.exceptions.ParameterNotFound as e:
|
|
21
|
+
raise RuntimeError(
|
|
22
|
+
f"No worker AMI: SSM parameter {source} does not exist in {region}. "
|
|
23
|
+
f"Build one with scripts/build_worker_ami.sh --region {region}."
|
|
24
|
+
) from e
|
|
25
|
+
label = ami_id if ami_id == source else f"{ami_id} (from {source})"
|
|
26
|
+
ec2 = boto3.client("ec2", region_name=region)
|
|
27
|
+
try:
|
|
28
|
+
images = ec2.describe_images(ImageIds=[ami_id])["Images"]
|
|
29
|
+
except botocore.exceptions.ClientError as e:
|
|
30
|
+
if not e.response["Error"]["Code"].startswith("InvalidAMIID"):
|
|
31
|
+
raise
|
|
32
|
+
raise RuntimeError(
|
|
33
|
+
f"Worker AMI {label} not found in {region}: "
|
|
34
|
+
f"{e.response['Error']['Message']}"
|
|
35
|
+
) from e
|
|
36
|
+
if not images:
|
|
37
|
+
raise RuntimeError(f"Worker AMI {label} not found in {region}.")
|
|
38
|
+
image = images[0]
|
|
39
|
+
if image["State"] != "available":
|
|
40
|
+
reason = image.get("StateReason", {}).get("Message", "")
|
|
41
|
+
raise RuntimeError(
|
|
42
|
+
f"Worker AMI {label} in {region} is {image['State']}"
|
|
43
|
+
f"{f' ({reason})' if reason else ''}, not available; no workers launched."
|
|
44
|
+
)
|
|
45
|
+
return ami_id
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""AWS caller identity lookup for resource tagging."""
|
|
2
|
+
|
|
3
|
+
import boto3
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def caller_identity_name(region: str) -> str:
|
|
7
|
+
"""Get the caller's identity name (IAM username or SSO session name) for resource tagging."""
|
|
8
|
+
sts = boto3.client("sts", region_name=region)
|
|
9
|
+
return sts.get_caller_identity()["Arn"].rsplit("/", 1)[-1]
|