{"repo": "breixopd/spectra", "files": {"config/tensorzero.toml": {"6fc2f2f855bef1bc563df7193e055fc31a47e963": {"t": 1785745349.4555917, "n": 4346, "h": "0c3c01cee99f0cbd", "c": "# =============================================================================\n# TensorZero Gateway Configuration for Spectra\n# =============================================================================\n#\n# All AI inference routes through TensorZero using the native DeepSeek provider.\n# Set DEEPSEEK_API_KEY in secrets/.env (Compose) or Swarm secret.\n#\n# Tiers (explicit V4 model IDs — the legacy `deepseek-chat`/`deepseek-reasoner`\n# aliases are deprecated by DeepSeek on 2026-07-24 and BOTH alias to v4-flash,\n# so `deepseek-reasoner` would NOT give you the Pro model):\n# fast — deepseek-v4-flash, thinking disabled (scope, tool select, parse, safety)\n# balanced — deepseek-v4-flash, thinking enabled (planning, steering, consensus, reporting)\n# capable — deepseek-v4-pro, thinking enabled (exploit crafting, PoC, post-exploitation)\n#\n# DEEPSEEK_API_KEY is required at gateway boot — the gateway validates provider\n# credentials on startup, so it must be set in .env / Swarm secret before launch.\n#\n\n[gateway]\nbind_address = \"0.0.0.0:3000\"\n\n# =============================================================================\n# Models — Three tiers (native DeepSeek)\n# =============================================================================\n\n[models.fast]\nrouting = [\"primary\"]\n\n[models.fast.providers.primary]\ntype = \"deepseek\"\nmodel_name = \"deepseek-v4-flash\"\napi_key_location = \"env::DEEPSEEK_API_KEY\"\nextra_body = [{ \"pointer\" = \"/thinking/type\", \"value\" = \"disabled\" }]\n\n[models.balanced]\nrouting = [\"primary\"]\n\n[models.balanced.providers.primary]\ntype = \"deepseek\"\nmodel_name = \"deepseek-v4-flash\"\napi_key_location = \"env::DEEPSEEK_API_KEY\"\nextra_body = [{ \"pointer\" = \"/thinking/type\", \"value\" = \"enabled\" }]\n\n[models.capable]\nrouting = [\"primary\"]\n\n[models.capable.providers.primary]\ntype = \"deepseek\"\nmodel_name = \"deepseek-v4-pro\"\napi_key_location = \"env::DEEPSEEK_API_KEY\"\n# DeepSeek thinking.type accepts only adaptive | enabled | disabled. \"enabled\" gives\n# Pro full chain-of-thought (the highest-reasoning tier).\nextra_body = [{ \"pointer\" = \"/thinking/type\", \"value\" = \"enabled\" }]\n\n# =============================================================================\n# Functions — Map Spectra tasks to model tiers\n# =============================================================================\n\n[functions.scope]\ntype = \"chat\"\n\n[functions.scope.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.tool_selection]\ntype = \"chat\"\n\n[functions.tool_selection.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.safety_check]\ntype = \"chat\"\n\n[functions.safety_check.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.parsing]\ntype = \"chat\"\n\n[functions.parsing.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.planning]\ntype = \"chat\"\n\n[functions.planning.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.steering]\ntype = \"chat\"\n\n[functions.steering.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.consensus]\ntype = \"chat\"\n\n[functions.consensus.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.vector_generation]\ntype = \"chat\"\n\n[functions.vector_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.reporting]\ntype = \"chat\"\n\n[functions.reporting.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.exploit_crafting]\ntype = \"chat\"\n\n[functions.exploit_crafting.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.poc_generation]\ntype = \"chat\"\n\n[functions.poc_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.post_exploitation]\ntype = \"chat\"\n\n[functions.post_exploitation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.default]\ntype = \"chat\"\n\n[functions.default.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# =============================================================================\n# Metrics\n# =============================================================================\n\n[metrics.task_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.exploit_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.response_quality]\ntype = \"float\"\nlevel = \"inference\"\noptimize = \"max\"\n"}, "6a77359f42835f6a9a40e08459a8539fb8340526": {"t": 1785750567.3562539, "n": 4346, "h": "0c3c01cee99f0cbd", "c": "# =============================================================================\n# TensorZero Gateway Configuration for Spectra\n# =============================================================================\n#\n# All AI inference routes through TensorZero using the native DeepSeek provider.\n# Set DEEPSEEK_API_KEY in secrets/.env (Compose) or Swarm secret.\n#\n# Tiers (explicit V4 model IDs — the legacy `deepseek-chat`/`deepseek-reasoner`\n# aliases are deprecated by DeepSeek on 2026-07-24 and BOTH alias to v4-flash,\n# so `deepseek-reasoner` would NOT give you the Pro model):\n# fast — deepseek-v4-flash, thinking disabled (scope, tool select, parse, safety)\n# balanced — deepseek-v4-flash, thinking enabled (planning, steering, consensus, reporting)\n# capable — deepseek-v4-pro, thinking enabled (exploit crafting, PoC, post-exploitation)\n#\n# DEEPSEEK_API_KEY is required at gateway boot — the gateway validates provider\n# credentials on startup, so it must be set in .env / Swarm secret before launch.\n#\n\n[gateway]\nbind_address = \"0.0.0.0:3000\"\n\n# =============================================================================\n# Models — Three tiers (native DeepSeek)\n# =============================================================================\n\n[models.fast]\nrouting = [\"primary\"]\n\n[models.fast.providers.primary]\ntype = \"deepseek\"\nmodel_name = \"deepseek-v4-flash\"\napi_key_location = \"env::DEEPSEEK_API_KEY\"\nextra_body = [{ \"pointer\" = \"/thinking/type\", \"value\" = \"disabled\" }]\n\n[models.balanced]\nrouting = [\"primary\"]\n\n[models.balanced.providers.primary]\ntype = \"deepseek\"\nmodel_name = \"deepseek-v4-flash\"\napi_key_location = \"env::DEEPSEEK_API_KEY\"\nextra_body = [{ \"pointer\" = \"/thinking/type\", \"value\" = \"enabled\" }]\n\n[models.capable]\nrouting = [\"primary\"]\n\n[models.capable.providers.primary]\ntype = \"deepseek\"\nmodel_name = \"deepseek-v4-pro\"\napi_key_location = \"env::DEEPSEEK_API_KEY\"\n# DeepSeek thinking.type accepts only adaptive | enabled | disabled. \"enabled\" gives\n# Pro full chain-of-thought (the highest-reasoning tier).\nextra_body = [{ \"pointer\" = \"/thinking/type\", \"value\" = \"enabled\" }]\n\n# =============================================================================\n# Functions — Map Spectra tasks to model tiers\n# =============================================================================\n\n[functions.scope]\ntype = \"chat\"\n\n[functions.scope.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.tool_selection]\ntype = \"chat\"\n\n[functions.tool_selection.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.safety_check]\ntype = \"chat\"\n\n[functions.safety_check.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.parsing]\ntype = \"chat\"\n\n[functions.parsing.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.planning]\ntype = \"chat\"\n\n[functions.planning.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.steering]\ntype = \"chat\"\n\n[functions.steering.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.consensus]\ntype = \"chat\"\n\n[functions.consensus.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.vector_generation]\ntype = \"chat\"\n\n[functions.vector_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.reporting]\ntype = \"chat\"\n\n[functions.reporting.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.exploit_crafting]\ntype = \"chat\"\n\n[functions.exploit_crafting.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.poc_generation]\ntype = \"chat\"\n\n[functions.poc_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.post_exploitation]\ntype = \"chat\"\n\n[functions.post_exploitation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.default]\ntype = \"chat\"\n\n[functions.default.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# =============================================================================\n# Metrics\n# =============================================================================\n\n[metrics.task_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.exploit_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.response_quality]\ntype = \"float\"\nlevel = \"inference\"\noptimize = \"max\"\n"}, "3e76256eae89ef8fc28bac937df3616b4de34df7": {"t": 1785750568.4154274, "n": 4062, "h": "7e52577b9418ed5e", "c": "# =============================================================================\n# TensorZero Gateway Configuration for Spectra\n# =============================================================================\n#\n# All AI inference routes through TensorZero using the native DeepSeek provider.\n# Set DEEPSEEK_API_KEY in secrets/.env (Compose) or Swarm secret.\n#\n# Tiers:\n# fast — deepseek-v4-flash (deepseek-chat), thinking disabled\n# balanced — deepseek-v4-flash (deepseek-chat), thinking enabled\n# capable — deepseek-v4-pro (deepseek-reasoner), thinking enabled\n#\n# DEEPSEEK_API_KEY is required at gateway boot — the gateway validates provider\n# credentials on startup, so it must be set in .env / Swarm secret before launch.\n#\n\n[gateway]\nbind_address = \"0.0.0.0:3000\"\n\n# =============================================================================\n# Models — Three tiers (native DeepSeek)\n# =============================================================================\n\n[models.fast]\nrouting = [\"primary\"]\n\n[models.fast.providers.primary]\ntype = \"deepseek\"\nmodel_name = \"deepseek-chat\"\napi_key_location = \"env::DEEPSEEK_API_KEY\"\nextra_body = [{ \"pointer\" = \"/thinking/type\", \"value\" = \"disabled\" }]\n\n[models.balanced]\nrouting = [\"primary\"]\n\n[models.balanced.providers.primary]\ntype = \"deepseek\"\nmodel_name = \"deepseek-chat\"\napi_key_location = \"env::DEEPSEEK_API_KEY\"\nextra_body = [{ \"pointer\" = \"/thinking/type\", \"value\" = \"enabled\" }]\n\n[models.capable]\nrouting = [\"primary\"]\n\n[models.capable.providers.primary]\ntype = \"deepseek\"\nmodel_name = \"deepseek-reasoner\"\napi_key_location = \"env::DEEPSEEK_API_KEY\"\n# DeepSeek thinking.type accepts only adaptive | enabled | disabled. \"enabled\" gives\n# the reasoner full chain-of-thought (the highest-reasoning tier).\nextra_body = [{ \"pointer\" = \"/thinking/type\", \"value\" = \"enabled\" }]\n\n# =============================================================================\n# Functions — Map Spectra tasks to model tiers\n# =============================================================================\n\n[functions.scope]\ntype = \"chat\"\n\n[functions.scope.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.tool_selection]\ntype = \"chat\"\n\n[functions.tool_selection.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.safety_check]\ntype = \"chat\"\n\n[functions.safety_check.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.parsing]\ntype = \"chat\"\n\n[functions.parsing.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.planning]\ntype = \"chat\"\n\n[functions.planning.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.steering]\ntype = \"chat\"\n\n[functions.steering.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.consensus]\ntype = \"chat\"\n\n[functions.consensus.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.vector_generation]\ntype = \"chat\"\n\n[functions.vector_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.reporting]\ntype = \"chat\"\n\n[functions.reporting.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.exploit_crafting]\ntype = \"chat\"\n\n[functions.exploit_crafting.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.poc_generation]\ntype = \"chat\"\n\n[functions.poc_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.post_exploitation]\ntype = \"chat\"\n\n[functions.post_exploitation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.default]\ntype = \"chat\"\n\n[functions.default.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# =============================================================================\n# Metrics\n# =============================================================================\n\n[metrics.task_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.exploit_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.response_quality]\ntype = \"float\"\nlevel = \"inference\"\noptimize = \"max\"\n"}, "e87d642f25dae89354bfb570ca788b39bb0cc139": {"t": 1785750569.7183251, "n": 4975, "h": "d4e3adc9b2162b2c", "c": "# =============================================================================\n# TensorZero Gateway Configuration for Spectra\n# =============================================================================\n#\n# All AI inference routes through TensorZero. Configure models, providers,\n# and API keys here. The Spectra app only needs the gateway URL.\n#\n# Default: OpenRouter free model router (no API cost).\n# Set OPENAI_API_KEY to your OpenRouter key.\n# Set OPENAI_BASE_URL to https://openrouter.ai/api/v1 (done in docker-compose).\n#\n# Fast tier: openrouter/free\n# Balanced tier: openrouter/free\n# Capable tier: openrouter/free\n#\n# Free OpenRouter endpoints are useful for development and smoke tests, but\n# providers may log prompts. Use paid/private routes for customer production data.\n#\n# To use paid models: change model_name values to e.g. \"openai/gpt-4.1\",\n# \"anthropic/claude-sonnet-4\", etc. Models are hot-swappable.\n#\n\n[gateway]\nbind_address = \"0.0.0.0:3000\"\n\n# =============================================================================\n# Models — Three tiers with automatic fallbacks\n# =============================================================================\n\n# Tier 1: Fast — cheap structured tasks (scope, parsing, tool selection)\n[models.fast]\nrouting = [\"primary\", \"fallback\"]\n\n[models.fast.providers.primary]\ntype = \"openai\"\nmodel_name = \"openrouter/free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.fast.providers.fallback]\ntype = \"openai\"\nmodel_name = \"openai/gpt-oss-120b:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# Tier 2: Balanced — reasoning tasks (planning, steering, reporting)\n[models.balanced]\nrouting = [\"primary\", \"fallback\"]\n\n[models.balanced.providers.primary]\ntype = \"openai\"\nmodel_name = \"openrouter/free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.balanced.providers.fallback]\ntype = \"openai\"\nmodel_name = \"openai/gpt-oss-120b:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# Tier 3: Capable — complex creative tasks (exploit crafting, PoC)\n[models.capable]\nrouting = [\"primary\", \"fallback\"]\n\n[models.capable.providers.primary]\ntype = \"openai\"\nmodel_name = \"openrouter/free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.capable.providers.fallback]\ntype = \"openai\"\nmodel_name = \"openai/gpt-oss-120b:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# =============================================================================\n# Functions — Map Spectra tasks to model tiers\n# =============================================================================\n\n# Tier 1: Simple, deterministic tasks\n[functions.scope]\ntype = \"chat\"\n\n[functions.scope.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.tool_selection]\ntype = \"chat\"\n\n[functions.tool_selection.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.safety_check]\ntype = \"chat\"\n\n[functions.safety_check.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.parsing]\ntype = \"chat\"\n\n[functions.parsing.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n# Tier 2: Moderate reasoning\n[functions.planning]\ntype = \"chat\"\n\n[functions.planning.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.steering]\ntype = \"chat\"\n\n[functions.steering.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.consensus]\ntype = \"chat\"\n\n[functions.consensus.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.vector_generation]\ntype = \"chat\"\n\n[functions.vector_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.reporting]\ntype = \"chat\"\n\n[functions.reporting.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# Tier 3: Complex creative tasks\n[functions.exploit_crafting]\ntype = \"chat\"\n\n[functions.exploit_crafting.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.poc_generation]\ntype = \"chat\"\n\n[functions.poc_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.post_exploitation]\ntype = \"chat\"\n\n[functions.post_exploitation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n# Default function for unclassified tasks\n[functions.default]\ntype = \"chat\"\n\n[functions.default.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# =============================================================================\n# Metrics — Feedback for continuous optimization\n# =============================================================================\n\n[metrics.task_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.exploit_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.response_quality]\ntype = \"float\"\nlevel = \"inference\"\noptimize = \"max\"\n"}, "cad6e37fb515177baf44b94e7b695de58f94bfbf": {"t": 1785750570.937335, "n": 5274, "h": "1addeebe51afcbe0", "c": "# =============================================================================\n# TensorZero Gateway Configuration for Spectra\n# =============================================================================\n#\n# All AI inference routes through TensorZero. Configure models, providers,\n# and API keys here. The Spectra app only needs the gateway URL.\n#\n# Default: OpenRouter free-tier models (no API cost).\n# Set OPENAI_API_KEY to your OpenRouter key.\n# Set OPENAI_BASE_URL to https://openrouter.ai/api/v1 (done in docker-compose).\n#\n# Fast tier: nvidia/nemotron-3-nano-30b-a3b:free (primary)\n# google/gemma-3-12b-it:free (fallback)\n# Balanced tier: nvidia/nemotron-3-super-120b-a12b:free (primary)\n# z-ai/glm-4.5-air:free (fallback)\n# Capable tier: minimax/minimax-m2.5:free (primary)\n# google/gemma-4-31b-it:free (fallback)\n#\n# Free OpenRouter endpoints are useful for development and smoke tests, but\n# providers may log prompts. Use paid/private routes for customer production data.\n#\n# To use paid models: change model_name values to e.g. \"openai/gpt-4.1\",\n# \"anthropic/claude-sonnet-4\", etc. Models are hot-swappable.\n#\n\n[gateway]\nbind_address = \"0.0.0.0:3000\"\n\n# =============================================================================\n# Models — Three tiers with automatic fallbacks\n# =============================================================================\n\n# Tier 1: Fast — cheap structured tasks (scope, parsing, tool selection)\n[models.fast]\nrouting = [\"primary\", \"fallback\"]\n\n[models.fast.providers.primary]\ntype = \"openai\"\nmodel_name = \"nvidia/nemotron-3-nano-30b-a3b:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.fast.providers.fallback]\ntype = \"openai\"\nmodel_name = \"google/gemma-3-12b-it:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# Tier 2: Balanced — reasoning tasks (planning, steering, reporting)\n[models.balanced]\nrouting = [\"primary\", \"fallback\"]\n\n[models.balanced.providers.primary]\ntype = \"openai\"\nmodel_name = \"nvidia/nemotron-3-super-120b-a12b:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.balanced.providers.fallback]\ntype = \"openai\"\nmodel_name = \"z-ai/glm-4.5-air:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# Tier 3: Capable — complex creative tasks (exploit crafting, PoC)\n[models.capable]\nrouting = [\"primary\", \"fallback\"]\n\n[models.capable.providers.primary]\ntype = \"openai\"\nmodel_name = \"minimax/minimax-m2.5:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.capable.providers.fallback]\ntype = \"openai\"\nmodel_name = \"google/gemma-4-31b-it:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# =============================================================================\n# Functions — Map Spectra tasks to model tiers\n# =============================================================================\n\n# Tier 1: Simple, deterministic tasks\n[functions.scope]\ntype = \"chat\"\n\n[functions.scope.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.tool_selection]\ntype = \"chat\"\n\n[functions.tool_selection.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.safety_check]\ntype = \"chat\"\n\n[functions.safety_check.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.parsing]\ntype = \"chat\"\n\n[functions.parsing.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n# Tier 2: Moderate reasoning\n[functions.planning]\ntype = \"chat\"\n\n[functions.planning.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.steering]\ntype = \"chat\"\n\n[functions.steering.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.consensus]\ntype = \"chat\"\n\n[functions.consensus.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.vector_generation]\ntype = \"chat\"\n\n[functions.vector_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.reporting]\ntype = \"chat\"\n\n[functions.reporting.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# Tier 3: Complex creative tasks\n[functions.exploit_crafting]\ntype = \"chat\"\n\n[functions.exploit_crafting.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.poc_generation]\ntype = \"chat\"\n\n[functions.poc_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.post_exploitation]\ntype = \"chat\"\n\n[functions.post_exploitation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n# Default function for unclassified tasks\n[functions.default]\ntype = \"chat\"\n\n[functions.default.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# =============================================================================\n# Metrics — Feedback for continuous optimization\n# =============================================================================\n\n[metrics.task_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.exploit_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.response_quality]\ntype = \"float\"\nlevel = \"inference\"\noptimize = \"max\"\n"}, "2f9c0e2a8f0904375b6a45e3240bed13acefc532": {"t": 1785750572.1223853, "n": 5232, "h": "2035225d7e5daf0e", "c": "# =============================================================================\n# TensorZero Gateway Configuration for Spectra\n# =============================================================================\n#\n# All AI inference routes through TensorZero. Configure models, providers,\n# and API keys here. The Spectra app only needs the gateway URL.\n#\n# Default: OpenRouter free-tier models (no API cost).\n# Set OPENAI_API_KEY to your OpenRouter key.\n# Set OPENAI_BASE_URL to https://openrouter.ai/api/v1 (done in docker-compose).\n#\n# Fast tier: inclusionai/ling-2.6-flash:free (primary)\n# inclusionai/ling-2.6-1t:free (fallback)\n# Balanced tier: inclusionai/ling-2.6-1t:free (primary)\n# google/gemma-4-31b-it:free (fallback)\n# Capable tier: google/gemma-4-31b-it:free (primary)\n# inclusionai/ling-2.6-1t:free (fallback)\n#\n# Gemma 4 chosen for self-hosting/fine-tuning path — can be replaced with\n# a custom fine-tuned variant when training pipeline is ready\n#\n# To use paid models: change model_name values to e.g. \"openai/gpt-4.1\",\n# \"anthropic/claude-sonnet-4\", etc. Models are hot-swappable.\n#\n\n[gateway]\nbind_address = \"0.0.0.0:3000\"\n\n# =============================================================================\n# Models — Three tiers with automatic fallbacks\n# =============================================================================\n\n# Tier 1: Fast — cheap structured tasks (scope, parsing, tool selection)\n[models.fast]\nrouting = [\"primary\", \"fallback\"]\n\n[models.fast.providers.primary]\ntype = \"openai\"\nmodel_name = \"inclusionai/ling-2.6-flash:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.fast.providers.fallback]\ntype = \"openai\"\nmodel_name = \"inclusionai/ling-2.6-1t:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# Tier 2: Balanced — reasoning tasks (planning, steering, reporting)\n[models.balanced]\nrouting = [\"primary\", \"fallback\"]\n\n[models.balanced.providers.primary]\ntype = \"openai\"\nmodel_name = \"inclusionai/ling-2.6-1t:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.balanced.providers.fallback]\ntype = \"openai\"\nmodel_name = \"google/gemma-4-31b-it:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# Tier 3: Capable — complex creative tasks (exploit crafting, PoC)\n[models.capable]\nrouting = [\"primary\", \"fallback\"]\n\n[models.capable.providers.primary]\ntype = \"openai\"\nmodel_name = \"google/gemma-4-31b-it:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.capable.providers.fallback]\ntype = \"openai\"\nmodel_name = \"inclusionai/ling-2.6-1t:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# =============================================================================\n# Functions — Map Spectra tasks to model tiers\n# =============================================================================\n\n# Tier 1: Simple, deterministic tasks\n[functions.scope]\ntype = \"chat\"\n\n[functions.scope.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.tool_selection]\ntype = \"chat\"\n\n[functions.tool_selection.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.safety_check]\ntype = \"chat\"\n\n[functions.safety_check.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.parsing]\ntype = \"chat\"\n\n[functions.parsing.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n# Tier 2: Moderate reasoning\n[functions.planning]\ntype = \"chat\"\n\n[functions.planning.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.steering]\ntype = \"chat\"\n\n[functions.steering.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.consensus]\ntype = \"chat\"\n\n[functions.consensus.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.vector_generation]\ntype = \"chat\"\n\n[functions.vector_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.reporting]\ntype = \"chat\"\n\n[functions.reporting.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# Tier 3: Complex creative tasks\n[functions.exploit_crafting]\ntype = \"chat\"\n\n[functions.exploit_crafting.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.poc_generation]\ntype = \"chat\"\n\n[functions.poc_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.post_exploitation]\ntype = \"chat\"\n\n[functions.post_exploitation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n# Default function for unclassified tasks\n[functions.default]\ntype = \"chat\"\n\n[functions.default.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# =============================================================================\n# Metrics — Feedback for continuous optimization\n# =============================================================================\n\n[metrics.task_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.exploit_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.response_quality]\ntype = \"float\"\nlevel = \"inference\"\noptimize = \"max\"\n"}, "211acb2b0aa851fb52539c0360df2342177ac3c5": {"t": 1785750573.4419415, "n": 5326, "h": "93403b19430a199d", "c": "# =============================================================================\n# TensorZero Gateway Configuration for Spectra\n# =============================================================================\n#\n# All AI inference routes through TensorZero. Configure models, providers,\n# and API keys here. The Spectra app only needs the gateway URL.\n#\n# Default: OpenRouter free-tier models (no API cost).\n# Set OPENAI_API_KEY to your OpenRouter key.\n# Set OPENAI_BASE_URL to https://openrouter.ai/api/v1 (done in docker-compose).\n#\n# Fast tier: google/gemma-3-4b-it:free (primary)\n# cognitivecomputations/dolphin-mistral-24b-venice-edition:free (fallback)\n# Balanced tier: qwen/qwen3-coder:free (primary)\n# google/gemma-3-4b-it:free (fallback)\n# Capable tier: qwen/qwen3-coder:free (primary)\n# cognitivecomputations/dolphin-mistral-24b-venice-edition:free (fallback)\n#\n# Gemma 4 chosen for self-hosting/fine-tuning path — can be replaced with\n# a custom fine-tuned variant when training pipeline is ready\n#\n# To use paid models: change model_name values to e.g. \"openai/gpt-4.1\",\n# \"anthropic/claude-sonnet-4\", etc. Models are hot-swappable.\n#\n\n[gateway]\nbind_address = \"0.0.0.0:3000\"\n\n# =============================================================================\n# Models — Three tiers with automatic fallbacks\n# =============================================================================\n\n# Tier 1: Fast — cheap structured tasks (scope, parsing, tool selection)\n[models.fast]\nrouting = [\"primary\", \"fallback\"]\n\n[models.fast.providers.primary]\ntype = \"openai\"\nmodel_name = \"google/gemma-3-4b-it:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.fast.providers.fallback]\ntype = \"openai\"\nmodel_name = \"cognitivecomputations/dolphin-mistral-24b-venice-edition:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# Tier 2: Balanced — reasoning tasks (planning, steering, reporting)\n[models.balanced]\nrouting = [\"primary\", \"fallback\"]\n\n[models.balanced.providers.primary]\ntype = \"openai\"\nmodel_name = \"qwen/qwen3-coder:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.balanced.providers.fallback]\ntype = \"openai\"\nmodel_name = \"google/gemma-3-4b-it:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# Tier 3: Capable — complex creative tasks (exploit crafting, PoC)\n[models.capable]\nrouting = [\"primary\", \"fallback\"]\n\n[models.capable.providers.primary]\ntype = \"openai\"\nmodel_name = \"qwen/qwen3-coder:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.capable.providers.fallback]\ntype = \"openai\"\nmodel_name = \"cognitivecomputations/dolphin-mistral-24b-venice-edition:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# =============================================================================\n# Functions — Map Spectra tasks to model tiers\n# =============================================================================\n\n# Tier 1: Simple, deterministic tasks\n[functions.scope]\ntype = \"chat\"\n\n[functions.scope.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.tool_selection]\ntype = \"chat\"\n\n[functions.tool_selection.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.safety_check]\ntype = \"chat\"\n\n[functions.safety_check.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.parsing]\ntype = \"chat\"\n\n[functions.parsing.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n# Tier 2: Moderate reasoning\n[functions.planning]\ntype = \"chat\"\n\n[functions.planning.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.steering]\ntype = \"chat\"\n\n[functions.steering.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.consensus]\ntype = \"chat\"\n\n[functions.consensus.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.vector_generation]\ntype = \"chat\"\n\n[functions.vector_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.reporting]\ntype = \"chat\"\n\n[functions.reporting.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# Tier 3: Complex creative tasks\n[functions.exploit_crafting]\ntype = \"chat\"\n\n[functions.exploit_crafting.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.poc_generation]\ntype = \"chat\"\n\n[functions.poc_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.post_exploitation]\ntype = \"chat\"\n\n[functions.post_exploitation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n# Default function for unclassified tasks\n[functions.default]\ntype = \"chat\"\n\n[functions.default.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# =============================================================================\n# Metrics — Feedback for continuous optimization\n# =============================================================================\n\n[metrics.task_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.exploit_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.response_quality]\ntype = \"float\"\nlevel = \"inference\"\noptimize = \"max\"\n"}, "d6d4f113702639c141188556d7021a7034341ca7": {"t": 1785750574.5185091, "n": 5220, "h": "04d655862e28f785", "c": "# =============================================================================\n# TensorZero Gateway Configuration for Spectra\n# =============================================================================\n#\n# All AI inference routes through TensorZero. Configure models, providers,\n# and API keys here. The Spectra app only needs the gateway URL.\n#\n# Default: OpenRouter free-tier models (no API cost).\n# Set OPENAI_API_KEY to your OpenRouter key.\n# Set OPENAI_BASE_URL to https://openrouter.ai/api/v1 (done in docker-compose).\n#\n# Fast tier: qwen/qwen3-30b-a3b:free (primary)\n# google/gemma-3-27b-it:free (fallback)\n# Balanced tier: qwen/qwen3.6-plus:free (primary)\n# google/gemma-4-27b-it:free (fallback)\n# Capable tier: google/gemma-4-27b-it:free (primary)\n# nvidia/nemotron-3-super-120b-a12b:free (fallback)\n#\n# Gemma 4 chosen for self-hosting/fine-tuning path — can be replaced with\n# a custom fine-tuned variant when training pipeline is ready\n#\n# To use paid models: change model_name values to e.g. \"openai/gpt-4.1\",\n# \"anthropic/claude-sonnet-4\", etc. Models are hot-swappable.\n#\n\n[gateway]\nbind_address = \"0.0.0.0:3000\"\n\n# =============================================================================\n# Models — Three tiers with automatic fallbacks\n# =============================================================================\n\n# Tier 1: Fast — cheap structured tasks (scope, parsing, tool selection)\n[models.fast]\nrouting = [\"primary\", \"fallback\"]\n\n[models.fast.providers.primary]\ntype = \"openai\"\nmodel_name = \"qwen/qwen3-30b-a3b:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.fast.providers.fallback]\ntype = \"openai\"\nmodel_name = \"google/gemma-3-27b-it:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# Tier 2: Balanced — reasoning tasks (planning, steering, reporting)\n[models.balanced]\nrouting = [\"primary\", \"fallback\"]\n\n[models.balanced.providers.primary]\ntype = \"openai\"\nmodel_name = \"qwen/qwen3.6-plus:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.balanced.providers.fallback]\ntype = \"openai\"\nmodel_name = \"google/gemma-4-27b-it:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# Tier 3: Capable — complex creative tasks (exploit crafting, PoC)\n[models.capable]\nrouting = [\"primary\", \"fallback\"]\n\n[models.capable.providers.primary]\ntype = \"openai\"\nmodel_name = \"google/gemma-4-27b-it:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.capable.providers.fallback]\ntype = \"openai\"\nmodel_name = \"nvidia/nemotron-3-super-120b-a12b:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# =============================================================================\n# Functions — Map Spectra tasks to model tiers\n# =============================================================================\n\n# Tier 1: Simple, deterministic tasks\n[functions.scope]\ntype = \"chat\"\n\n[functions.scope.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.tool_selection]\ntype = \"chat\"\n\n[functions.tool_selection.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.safety_check]\ntype = \"chat\"\n\n[functions.safety_check.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.parsing]\ntype = \"chat\"\n\n[functions.parsing.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n# Tier 2: Moderate reasoning\n[functions.planning]\ntype = \"chat\"\n\n[functions.planning.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.steering]\ntype = \"chat\"\n\n[functions.steering.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.consensus]\ntype = \"chat\"\n\n[functions.consensus.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.vector_generation]\ntype = \"chat\"\n\n[functions.vector_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.reporting]\ntype = \"chat\"\n\n[functions.reporting.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# Tier 3: Complex creative tasks\n[functions.exploit_crafting]\ntype = \"chat\"\n\n[functions.exploit_crafting.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.poc_generation]\ntype = \"chat\"\n\n[functions.poc_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.post_exploitation]\ntype = \"chat\"\n\n[functions.post_exploitation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n# Default function for unclassified tasks\n[functions.default]\ntype = \"chat\"\n\n[functions.default.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# =============================================================================\n# Metrics — Feedback for continuous optimization\n# =============================================================================\n\n[metrics.task_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.exploit_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.response_quality]\ntype = \"float\"\nlevel = \"inference\"\noptimize = \"max\"\n"}, "9ea69fac32d758d4cc0cee728ecd1cd1b8f7cccc": {"t": 1785750575.7817576, "n": 5096, "h": "4bb1ee45ee7b9696", "c": "# =============================================================================\n# TensorZero Gateway Configuration for Spectra\n# =============================================================================\n#\n# All AI inference routes through TensorZero. Configure models, providers,\n# and API keys here. The Spectra app only needs the gateway URL.\n#\n# Default: OpenRouter free-tier models (no API cost).\n# Set OPENAI_API_KEY to your OpenRouter key.\n# Set OPENAI_BASE_URL to https://openrouter.ai/api/v1 (done in docker-compose).\n#\n# Fast tier: qwen/qwen3-30b-a3b:free (primary)\n# google/gemma-3-27b-it:free (fallback)\n# Balanced tier: qwen/qwen3.6-plus:free (primary)\n# nvidia/nemotron-3-super-120b-a12b:free (fallback)\n# Capable tier: nvidia/nemotron-3-super-120b-a12b:free (primary)\n# qwen/qwen3-coder:free (fallback)\n#\n# To use paid models: change model_name values to e.g. \"openai/gpt-4.1\",\n# \"anthropic/claude-sonnet-4\", etc. Models are hot-swappable.\n#\n\n[gateway]\nbind_address = \"0.0.0.0:3000\"\n\n# =============================================================================\n# Models — Three tiers with automatic fallbacks\n# =============================================================================\n\n# Tier 1: Fast — cheap structured tasks (scope, parsing, tool selection)\n[models.fast]\nrouting = [\"primary\", \"fallback\"]\n\n[models.fast.providers.primary]\ntype = \"openai\"\nmodel_name = \"qwen/qwen3-30b-a3b:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.fast.providers.fallback]\ntype = \"openai\"\nmodel_name = \"google/gemma-3-27b-it:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# Tier 2: Balanced — reasoning tasks (planning, steering, reporting)\n[models.balanced]\nrouting = [\"primary\", \"fallback\"]\n\n[models.balanced.providers.primary]\ntype = \"openai\"\nmodel_name = \"qwen/qwen3.6-plus:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.balanced.providers.fallback]\ntype = \"openai\"\nmodel_name = \"nvidia/nemotron-3-super-120b-a12b:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# Tier 3: Capable — complex creative tasks (exploit crafting, PoC)\n[models.capable]\nrouting = [\"primary\", \"fallback\"]\n\n[models.capable.providers.primary]\ntype = \"openai\"\nmodel_name = \"nvidia/nemotron-3-super-120b-a12b:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.capable.providers.fallback]\ntype = \"openai\"\nmodel_name = \"qwen/qwen3-coder:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# =============================================================================\n# Functions — Map Spectra tasks to model tiers\n# =============================================================================\n\n# Tier 1: Simple, deterministic tasks\n[functions.scope]\ntype = \"chat\"\n\n[functions.scope.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.tool_selection]\ntype = \"chat\"\n\n[functions.tool_selection.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.safety_check]\ntype = \"chat\"\n\n[functions.safety_check.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.parsing]\ntype = \"chat\"\n\n[functions.parsing.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n# Tier 2: Moderate reasoning\n[functions.planning]\ntype = \"chat\"\n\n[functions.planning.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.steering]\ntype = \"chat\"\n\n[functions.steering.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.consensus]\ntype = \"chat\"\n\n[functions.consensus.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.vector_generation]\ntype = \"chat\"\n\n[functions.vector_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.reporting]\ntype = \"chat\"\n\n[functions.reporting.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# Tier 3: Complex creative tasks\n[functions.exploit_crafting]\ntype = \"chat\"\n\n[functions.exploit_crafting.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.poc_generation]\ntype = \"chat\"\n\n[functions.poc_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.post_exploitation]\ntype = \"chat\"\n\n[functions.post_exploitation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n# Default function for unclassified tasks\n[functions.default]\ntype = \"chat\"\n\n[functions.default.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# =============================================================================\n# Metrics — Feedback for continuous optimization\n# =============================================================================\n\n[metrics.task_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.exploit_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.response_quality]\ntype = \"float\"\nlevel = \"inference\"\noptimize = \"max\"\n"}, "622fd3a54b1ff3c19eba25ecaa0d28a0f7896384": {"t": 1785750577.0021045, "n": 5126, "h": "4b7e57658dea8028", "c": "# =============================================================================\n# TensorZero Gateway Configuration for Spectra\n# =============================================================================\n#\n# All AI inference routes through TensorZero. Configure models, providers,\n# and API keys here. The Spectra app only needs the gateway URL.\n#\n# Default: OpenRouter free-tier models (no API cost).\n# Set OPENAI_API_KEY to your OpenRouter key.\n# Set OPENAI_BASE_URL to https://openrouter.ai/api/v1 (done in docker-compose).\n#\n# Fast tier: meta-llama/llama-3.3-70b-instruct:free (primary)\n# google/gemma-3-27b-it:free (fallback)\n# Balanced tier: qwen/qwen3.6-plus:free (primary)\n# nvidia/nemotron-3-super-120b-a12b:free (fallback)\n# Capable tier: nvidia/nemotron-3-super-120b-a12b:free (primary)\n# qwen/qwen3-coder:free (fallback)\n#\n# To use paid models: change model_name values to e.g. \"openai/gpt-4.1\",\n# \"anthropic/claude-sonnet-4\", etc. Models are hot-swappable.\n#\n\n[gateway]\nbind_address = \"0.0.0.0:3000\"\n\n# =============================================================================\n# Models — Three tiers with automatic fallbacks\n# =============================================================================\n\n# Tier 1: Fast — cheap structured tasks (scope, parsing, tool selection)\n[models.fast]\nrouting = [\"primary\", \"fallback\"]\n\n[models.fast.providers.primary]\ntype = \"openai\"\nmodel_name = \"meta-llama/llama-3.3-70b-instruct:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.fast.providers.fallback]\ntype = \"openai\"\nmodel_name = \"google/gemma-3-27b-it:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# Tier 2: Balanced — reasoning tasks (planning, steering, reporting)\n[models.balanced]\nrouting = [\"primary\", \"fallback\"]\n\n[models.balanced.providers.primary]\ntype = \"openai\"\nmodel_name = \"qwen/qwen3.6-plus:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.balanced.providers.fallback]\ntype = \"openai\"\nmodel_name = \"nvidia/nemotron-3-super-120b-a12b:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# Tier 3: Capable — complex creative tasks (exploit crafting, PoC)\n[models.capable]\nrouting = [\"primary\", \"fallback\"]\n\n[models.capable.providers.primary]\ntype = \"openai\"\nmodel_name = \"nvidia/nemotron-3-super-120b-a12b:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.capable.providers.fallback]\ntype = \"openai\"\nmodel_name = \"qwen/qwen3-coder:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# =============================================================================\n# Functions — Map Spectra tasks to model tiers\n# =============================================================================\n\n# Tier 1: Simple, deterministic tasks\n[functions.scope]\ntype = \"chat\"\n\n[functions.scope.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.tool_selection]\ntype = \"chat\"\n\n[functions.tool_selection.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.safety_check]\ntype = \"chat\"\n\n[functions.safety_check.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.parsing]\ntype = \"chat\"\n\n[functions.parsing.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n# Tier 2: Moderate reasoning\n[functions.planning]\ntype = \"chat\"\n\n[functions.planning.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.steering]\ntype = \"chat\"\n\n[functions.steering.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.consensus]\ntype = \"chat\"\n\n[functions.consensus.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.vector_generation]\ntype = \"chat\"\n\n[functions.vector_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.reporting]\ntype = \"chat\"\n\n[functions.reporting.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# Tier 3: Complex creative tasks\n[functions.exploit_crafting]\ntype = \"chat\"\n\n[functions.exploit_crafting.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.poc_generation]\ntype = \"chat\"\n\n[functions.poc_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.post_exploitation]\ntype = \"chat\"\n\n[functions.post_exploitation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n# Default function for unclassified tasks\n[functions.default]\ntype = \"chat\"\n\n[functions.default.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# =============================================================================\n# Metrics — Feedback for continuous optimization\n# =============================================================================\n\n[metrics.task_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.exploit_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.response_quality]\ntype = \"float\"\nlevel = \"inference\"\noptimize = \"max\"\n"}, "48288df32336ce37db38d4f7558d57c4b21d0bb0": {"t": 1785750578.1922762, "n": 5134, "h": "1021284a07d949f7", "c": "# =============================================================================\n# TensorZero Gateway Configuration for Spectra\n# =============================================================================\n#\n# All AI inference routes through TensorZero. Configure models, providers,\n# and API keys here. The Spectra app only needs the gateway URL.\n#\n# Default: OpenRouter free-tier models (no API cost).\n# Set OPENAI_API_KEY to your OpenRouter key.\n# Set OPENAI_BASE_URL to https://openrouter.ai/api/v1 (done in docker-compose).\n#\n# Fast tier: meta-llama/llama-3.3-70b-instruct:free (primary)\n# meta-llama/llama-3.2-3b-instruct:free (fallback)\n# Balanced tier: qwen/qwen3.6-plus:free (primary)\n# nousresearch/hermes-3-llama-3.1-405b:free (fallback)\n# Capable tier: openai/gpt-oss-120b:free (primary)\n# minimax/minimax-m2.5:free (fallback)\n#\n# To use paid models: change model_name values to e.g. \"openai/gpt-4.1\",\n# \"anthropic/claude-sonnet-4\", etc. Models are hot-swappable.\n#\n\n[gateway]\nbind_address = \"0.0.0.0:3000\"\n\n# =============================================================================\n# Models — Three tiers with automatic fallbacks\n# =============================================================================\n\n# Tier 1: Fast — cheap structured tasks (scope, parsing, tool selection)\n[models.fast]\nrouting = [\"primary\", \"fallback\"]\n\n[models.fast.providers.primary]\ntype = \"openai\"\nmodel_name = \"meta-llama/llama-3.3-70b-instruct:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.fast.providers.fallback]\ntype = \"openai\"\nmodel_name = \"meta-llama/llama-3.2-3b-instruct:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# Tier 2: Balanced — reasoning tasks (planning, steering, reporting)\n[models.balanced]\nrouting = [\"primary\", \"fallback\"]\n\n[models.balanced.providers.primary]\ntype = \"openai\"\nmodel_name = \"qwen/qwen3.6-plus:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.balanced.providers.fallback]\ntype = \"openai\"\nmodel_name = \"nousresearch/hermes-3-llama-3.1-405b:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# Tier 3: Capable — complex creative tasks (exploit crafting, PoC)\n[models.capable]\nrouting = [\"primary\", \"fallback\"]\n\n[models.capable.providers.primary]\ntype = \"openai\"\nmodel_name = \"openai/gpt-oss-120b:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n[models.capable.providers.fallback]\ntype = \"openai\"\nmodel_name = \"minimax/minimax-m2.5:free\"\napi_base = \"https://openrouter.ai/api/v1\"\napi_key_location = \"env::OPENAI_API_KEY\"\n\n# =============================================================================\n# Functions — Map Spectra tasks to model tiers\n# =============================================================================\n\n# Tier 1: Simple, deterministic tasks\n[functions.scope]\ntype = \"chat\"\n\n[functions.scope.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.tool_selection]\ntype = \"chat\"\n\n[functions.tool_selection.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.safety_check]\ntype = \"chat\"\n\n[functions.safety_check.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.parsing]\ntype = \"chat\"\n\n[functions.parsing.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n# Tier 2: Moderate reasoning\n[functions.planning]\ntype = \"chat\"\n\n[functions.planning.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.steering]\ntype = \"chat\"\n\n[functions.steering.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.consensus]\ntype = \"chat\"\n\n[functions.consensus.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.vector_generation]\ntype = \"chat\"\n\n[functions.vector_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.reporting]\ntype = \"chat\"\n\n[functions.reporting.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# Tier 3: Complex creative tasks\n[functions.exploit_crafting]\ntype = \"chat\"\n\n[functions.exploit_crafting.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.poc_generation]\ntype = \"chat\"\n\n[functions.poc_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.post_exploitation]\ntype = \"chat\"\n\n[functions.post_exploitation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n# Default function for unclassified tasks\n[functions.default]\ntype = \"chat\"\n\n[functions.default.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# =============================================================================\n# Metrics — Feedback for continuous optimization\n# =============================================================================\n\n[metrics.task_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.exploit_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.response_quality]\ntype = \"float\"\nlevel = \"inference\"\noptimize = \"max\"\n"}, "b97bd90d5ac19576638a15668055719e8af79965": {"t": 1785750579.249728, "n": 4676, "h": "7bab0c61f99b1f9f", "c": "# =============================================================================\n# TensorZero Gateway Configuration for Spectra\n# =============================================================================\n#\n# All AI inference routes through TensorZero. Configure models, providers,\n# and API keys here. The Spectra app only needs the gateway URL.\n#\n# Default: OpenRouter free-tier models (no API cost).\n# Set OPENAI_API_KEY to your OpenRouter key.\n# Set OPENAI_BASE_URL to https://openrouter.ai/api/v1 (done in docker-compose).\n#\n# Fast tier: nvidia/nemotron-3-nano-30b-a3b:free (194 tok/s, 256K ctx)\n# google/gemma-3-12b-it:free (fallback, 32K ctx)\n# Balanced tier: nvidia/nemotron-3-super-120b-a12b:free (120B MoE, 262K ctx)\n# z-ai/glm-4.5-air:free (fallback, 131K ctx)\n# Capable tier: minimax/minimax-m2.5:free (SWE-Bench 80.2%, 197K ctx)\n# stepfun/step-3.5-flash:free (fallback, 256K ctx)\n#\n# To use paid models: change model_name values to e.g. \"openai/gpt-4.1\",\n# \"anthropic/claude-sonnet-4\", etc. Models are hot-swappable.\n#\n\n[gateway]\nbind_address = \"0.0.0.0:3000\"\n\n# =============================================================================\n# Models — Three tiers with automatic fallbacks\n# =============================================================================\n\n# Tier 1: Fast — cheap structured tasks (scope, parsing, tool selection)\n[models.fast]\nrouting = [\"primary\", \"fallback\"]\n\n[models.fast.providers.primary]\ntype = \"openai\"\nmodel_name = \"nvidia/nemotron-3-nano-30b-a3b:free\"\n\n[models.fast.providers.fallback]\ntype = \"openai\"\nmodel_name = \"google/gemma-3-12b-it:free\"\n\n# Tier 2: Balanced — reasoning tasks (planning, steering, reporting)\n[models.balanced]\nrouting = [\"primary\", \"fallback\"]\n\n[models.balanced.providers.primary]\ntype = \"openai\"\nmodel_name = \"nvidia/nemotron-3-super-120b-a12b:free\"\n\n[models.balanced.providers.fallback]\ntype = \"openai\"\nmodel_name = \"z-ai/glm-4.5-air:free\"\n\n# Tier 3: Capable — complex creative tasks (exploit crafting, PoC)\n[models.capable]\nrouting = [\"primary\", \"fallback\"]\n\n[models.capable.providers.primary]\ntype = \"openai\"\nmodel_name = \"minimax/minimax-m2.5:free\"\n\n[models.capable.providers.fallback]\ntype = \"openai\"\nmodel_name = \"stepfun/step-3.5-flash:free\"\n\n# =============================================================================\n# Functions — Map Spectra tasks to model tiers\n# =============================================================================\n\n# Tier 1: Simple, deterministic tasks\n[functions.scope]\ntype = \"chat\"\n\n[functions.scope.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.tool_selection]\ntype = \"chat\"\n\n[functions.tool_selection.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.safety_check]\ntype = \"chat\"\n\n[functions.safety_check.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.parsing]\ntype = \"chat\"\n\n[functions.parsing.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n# Tier 2: Moderate reasoning\n[functions.planning]\ntype = \"chat\"\n\n[functions.planning.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.steering]\ntype = \"chat\"\n\n[functions.steering.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.consensus]\ntype = \"chat\"\n\n[functions.consensus.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.vector_generation]\ntype = \"chat\"\n\n[functions.vector_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.reporting]\ntype = \"chat\"\n\n[functions.reporting.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# Tier 3: Complex creative tasks\n[functions.exploit_crafting]\ntype = \"chat\"\n\n[functions.exploit_crafting.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.poc_generation]\ntype = \"chat\"\n\n[functions.poc_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.post_exploitation]\ntype = \"chat\"\n\n[functions.post_exploitation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n# Default function for unclassified tasks\n[functions.default]\ntype = \"chat\"\n\n[functions.default.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# =============================================================================\n# Metrics — Feedback for continuous optimization\n# =============================================================================\n\n[metrics.task_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.exploit_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.response_quality]\ntype = \"float\"\nlevel = \"inference\"\noptimize = \"max\"\n"}, "003fe9799b98bb8f7257c23bff5e5c411e94896d": {"t": 1785750580.3138843, "n": 4289, "h": "719118194985a837", "c": "# =============================================================================\n# TensorZero Gateway Configuration for Spectra\n# =============================================================================\n#\n# All AI inference routes through TensorZero. Configure models, providers,\n# and API keys here. The Spectra app only needs the gateway URL.\n#\n# Default: OpenRouter free-tier models (no API cost).\n# Set OPENAI_API_KEY to your OpenRouter key.\n# Set OPENAI_BASE_URL to https://openrouter.ai/api/v1 (done in docker-compose).\n#\n# To use paid models: change model_name values to e.g. \"openai/gpt-4.1\",\n# \"anthropic/claude-sonnet-4\", etc. Models are hot-swappable.\n#\n\n[gateway]\nbind_address = \"0.0.0.0:3000\"\n\n# =============================================================================\n# Models — Three tiers with automatic fallbacks\n# =============================================================================\n\n# Tier 1: Fast — cheap structured tasks (scope, parsing, tool selection)\n[models.fast]\nrouting = [\"primary\", \"fallback\"]\n\n[models.fast.providers.primary]\ntype = \"openai\"\nmodel_name = \"stepfun/step-2-16k:free\"\n\n[models.fast.providers.fallback]\ntype = \"openai\"\nmodel_name = \"google/gemma-3-4b-it:free\"\n\n# Tier 2: Balanced — reasoning tasks (planning, steering, reporting)\n[models.balanced]\nrouting = [\"primary\", \"fallback\"]\n\n[models.balanced.providers.primary]\ntype = \"openai\"\nmodel_name = \"nvidia/llama-3.3-nemotron-super-49b-v1:free\"\n\n[models.balanced.providers.fallback]\ntype = \"openai\"\nmodel_name = \"deepseek/deepseek-r1-0528:free\"\n\n# Tier 3: Capable — complex creative tasks (exploit crafting, PoC)\n[models.capable]\nrouting = [\"primary\", \"fallback\"]\n\n[models.capable.providers.primary]\ntype = \"openai\"\nmodel_name = \"nvidia/llama-3.1-nemotron-ultra-253b-v1:free\"\n\n[models.capable.providers.fallback]\ntype = \"openai\"\nmodel_name = \"deepseek/deepseek-r1-0528:free\"\n\n# =============================================================================\n# Functions — Map Spectra tasks to model tiers\n# =============================================================================\n\n# Tier 1: Simple, deterministic tasks\n[functions.scope]\ntype = \"chat\"\n\n[functions.scope.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.tool_selection]\ntype = \"chat\"\n\n[functions.tool_selection.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.safety_check]\ntype = \"chat\"\n\n[functions.safety_check.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n[functions.parsing]\ntype = \"chat\"\n\n[functions.parsing.variants.default]\ntype = \"chat_completion\"\nmodel = \"fast\"\n\n# Tier 2: Moderate reasoning\n[functions.planning]\ntype = \"chat\"\n\n[functions.planning.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.steering]\ntype = \"chat\"\n\n[functions.steering.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.consensus]\ntype = \"chat\"\n\n[functions.consensus.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.vector_generation]\ntype = \"chat\"\n\n[functions.vector_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n[functions.reporting]\ntype = \"chat\"\n\n[functions.reporting.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# Tier 3: Complex creative tasks\n[functions.exploit_crafting]\ntype = \"chat\"\n\n[functions.exploit_crafting.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.poc_generation]\ntype = \"chat\"\n\n[functions.poc_generation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n[functions.post_exploitation]\ntype = \"chat\"\n\n[functions.post_exploitation.variants.default]\ntype = \"chat_completion\"\nmodel = \"capable\"\n\n# Default function for unclassified tasks\n[functions.default]\ntype = \"chat\"\n\n[functions.default.variants.default]\ntype = \"chat_completion\"\nmodel = \"balanced\"\n\n# =============================================================================\n# Metrics — Feedback for continuous optimization\n# =============================================================================\n\n[metrics.task_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.exploit_success]\ntype = \"boolean\"\nlevel = \"inference\"\noptimize = \"max\"\n\n[metrics.response_quality]\ntype = \"float\"\nlevel = \"inference\"\noptimize = \"max\"\n"}}, ".github/workflows/ci.yml": {"6fc2f2f855bef1bc563df7193e055fc31a47e963": {"t": 1785747032.8824086, "n": 19839, "h": "93722b2917639e7d", "c": "name: CI\n\non:\n push:\n branches: [main, dev]\n pull_request:\n # Feature work lands in dev first; promotion from dev to main uses the\n # exact same required checks.\n branches: [main, dev]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n # TensorZero validates provider credentials at boot even for tests that do\n # not invoke an LLM. This inert value is never used for inference and keeps\n # CI health checks deterministic without storing customer credentials.\n DEEPSEEK_API_KEY: spectra-ci-test-key\n\npermissions:\n contents: read\n\nconcurrency:\n group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n # Keep the protected release branch's evidence intact while superseding stale\n # pull-request and development-branch runs.\n cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n timeout-minutes: 45\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Build Docker test runner\n run: docker build -f deploy/docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff format\n run: docker run --rm spectra-test-ci python -m ruff format --check tests/ services/ packages/ scripts/ db/\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check tests/ services/ packages/ scripts/ db/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci pyright\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/ services/ -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n timeout-minutes: 75\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../../.env.test\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f deploy/docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f deploy/docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Prepare unit database\n run: |\n docker compose -f deploy/docker/compose.yaml --profile test run --rm unit-test-runner \\\n \"alembic upgrade head\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f deploy/docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --timeout=120 --override-ini=addopts= --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov=spectra_ai_core --cov=spectra_billing --cov=spectra_common --cov=spectra_auth --cov=spectra_contracts --cov=spectra_domain --cov=spectra_infra --cov=spectra_mission --cov=spectra_observability --cov=spectra_persistence --cov=spectra_scaling --cov=spectra_storage_policy --cov=spectra_system --cov=spectra_tools --cov=spectra_tools_core --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=65\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f deploy/docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n timeout-minutes: 75\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../../.env.test\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start integration infrastructure\n run: |\n ENV_FILE=../../.env.test docker compose -f deploy/docker/compose.yaml --profile app --profile test up -d --wait \\\n db redis garage tensorzero metasploitable dvwa\n GARAGE_CONTAINER=\"$(docker compose -f deploy/docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash deploy/docker/garage-init.sh\n - name: Build and start integration services\n run: |\n ENV_FILE=../../.env.test docker compose -f deploy/docker/compose.yaml --profile app --profile test up -d --build --wait \\\n app ai-svc scheduler worker tools caddy\n - name: Run integration tests in Docker\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile test run --rm --no-deps test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n - name: Collect integration logs on failure\n if: failure()\n run: |\n mkdir -p integration-logs\n docker compose -f deploy/docker/compose.yaml --profile app --profile test logs --no-color > integration-logs/compose.log 2>&1 || true\n - name: Upload integration logs\n if: failure()\n uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0\n with:\n name: integration-test-logs\n path: integration-logs/\n if-no-files-found: warn\n retention-days: 14\n - name: Tear down integration stack\n if: always()\n run: docker compose -f deploy/docker/compose.yaml --profile app --profile test down --volumes --remove-orphans\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n timeout-minutes: 120\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.0.0\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../../.env.example docker compose --env-file .env.example -f deploy/docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f deploy/docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Verify first-party worker tool entry points\n run: docker run --rm --entrypoint sh spectra-worker:ci -c 'imds-fetcher --version && graphql-fuzzer --version'\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n timeout-minutes: 20\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - uses: astral-sh/setup-uv@94527f2e458b27549849d47d273a16bec83a01e9 # v7.0.0\n with:\n python-version: \"3.11\"\n # Audit the locked resolution (all transitive pins) instead of a manifest.\n - run: uv export --frozen --all-packages --no-emit-workspace --format requirements.txt -o /tmp/uv-lock-export.txt > /dev/null\n - run: uvx pip-audit --cache-dir /tmp/pip-audit-cache --progress-spinner off --strict --require-hashes -r /tmp/uv-lock-export.txt\n\n workflow-security:\n name: Workflow & Secret Security\n runs-on: ubuntu-latest\n timeout-minutes: 20\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n fetch-depth: 0\n persist-credentials: false\n - name: Detect exposed credentials\n uses: gitleaks/gitleaks-action@e0c47f4f8be36e29cdc102c57e68cb5cbf0e8d1e # v3.0.0\n env:\n GITHUB_TOKEN: ${{ github.token }}\n - uses: astral-sh/setup-uv@94527f2e458b27549849d47d273a16bec83a01e9 # v7.0.0\n with:\n python-version: \"3.11\"\n - name: Audit GitHub Actions workflow security\n run: uvx --from zizmor==1.28.0 zizmor .github/workflows\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n timeout-minutes: 120\n needs: [test, integration-test]\n # Run the full live smoke for pull requests and the protected release\n # branch. Feature branch pushes are covered by their pull request, avoiding\n # a second expensive stack boot for the same commit.\n if: >-\n github.event_name == 'pull_request' ||\n (github.event_name == 'push' && github.ref == 'refs/heads/main')\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../../.env.test\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f deploy/docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash deploy/docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n expected_services=(\n db redis garage registry clickhouse tensorzero\n app app-replica ai-svc scheduler tools worker caddy\n )\n compose=(docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test)\n for i in $(seq 1 90); do\n missing=()\n pending=()\n unhealthy=()\n for service in \"${expected_services[@]}\"; do\n container_id=$(\"${compose[@]}\" ps -q \"$service\" 2>/dev/null || true)\n if [ -z \"$container_id\" ]; then\n missing+=(\"$service\")\n continue\n fi\n running=$(docker inspect --format '{{.State.Running}}' \"$container_id\" 2>/dev/null || echo false)\n if [ \"$running\" != true ]; then\n missing+=(\"$service\")\n continue\n fi\n health=$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' \"$container_id\" 2>/dev/null || echo unknown)\n case \"$health\" in\n unhealthy) unhealthy+=(\"$service\") ;;\n starting|unknown) pending+=(\"$service\") ;;\n esac\n done\n if [ \"${#unhealthy[@]}\" -gt 0 ]; then\n echo \"Unhealthy expected services: ${unhealthy[*]}\"\n \"${compose[@]}\" ps\n exit 1\n fi\n if [ \"${#missing[@]}\" -eq 0 ] && [ \"${#pending[@]}\" -eq 0 ]; then\n echo \"All expected services are running and healthy (or have no healthcheck).\"\n \"${compose[@]}\" ps\n break\n fi\n echo \"Waiting... ($i/90) missing=${missing[*]:-none} pending=${pending[*]:-none}\"\n sleep 5\n done\n if [ \"${#missing[@]}\" -ne 0 ] || [ \"${#pending[@]}\" -ne 0 ]; then\n echo \"Timed out waiting for expected services to start\" >&2\n \"${compose[@]}\" ps >&2 || true\n docker ps -a --filter \"label=spectra.managed=true\" --format \"{{.Names}}\\t{{.Status}}\" >&2 || true\n exit 1\n fi\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run vulnerable-target live scan\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm --no-deps \\\n -e VULN_WEB_HOST=spectra-vuln-web \\\n -e VULN_SSH_HOST=spectra-vuln-ssh \\\n -e VULN_NETWORK_HOST=spectra-vuln-network \\\n test-runner \\\n \"python -m pytest tests/integration/test_live_scan.py -v -m live --timeout=120 --tb=short --override-ini=addopts= -p no:cov\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "14dad104fb3a2ab710b53fcc602ed46eb1bb09b9": {"t": 1785750568.5759523, "n": 19062, "h": "5454fb2c00d3e5e2", "c": "name: CI\n\non:\n push:\n branches: [main, dev]\n pull_request:\n # Feature work lands in dev first; promotion from dev to main uses the\n # exact same required checks.\n branches: [main, dev]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\nconcurrency:\n group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n # Keep the protected release branch's evidence intact while superseding stale\n # pull-request and development-branch runs.\n cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n timeout-minutes: 45\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Build Docker test runner\n run: docker build -f deploy/docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff format\n run: docker run --rm spectra-test-ci python -m ruff format --check tests/ services/ packages/ scripts/ db/\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check tests/ services/ packages/ scripts/ db/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci pyright\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/ services/ -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n timeout-minutes: 75\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../../.env.test\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f deploy/docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f deploy/docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Prepare unit database\n run: |\n docker compose -f deploy/docker/compose.yaml --profile test run --rm unit-test-runner \\\n \"alembic upgrade head\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f deploy/docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --timeout=120 --override-ini=addopts= --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov=spectra_ai_core --cov=spectra_billing --cov=spectra_common --cov=spectra_auth --cov=spectra_contracts --cov=spectra_domain --cov=spectra_infra --cov=spectra_mission --cov=spectra_observability --cov=spectra_persistence --cov=spectra_scaling --cov=spectra_storage_policy --cov=spectra_system --cov=spectra_tools --cov=spectra_tools_core --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=65\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f deploy/docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n timeout-minutes: 75\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../../.env.test\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start integration infrastructure\n run: |\n ENV_FILE=../../.env.test docker compose -f deploy/docker/compose.yaml --profile app --profile test up -d --wait \\\n db redis garage tensorzero metasploitable dvwa\n GARAGE_CONTAINER=\"$(docker compose -f deploy/docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash deploy/docker/garage-init.sh\n - name: Build and start integration services\n run: |\n ENV_FILE=../../.env.test docker compose -f deploy/docker/compose.yaml --profile app --profile test up -d --build --wait \\\n app ai-svc worker tools caddy\n - name: Run integration tests in Docker\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile test run --rm --no-deps test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n - name: Collect integration logs on failure\n if: failure()\n run: |\n mkdir -p integration-logs\n docker compose -f deploy/docker/compose.yaml --profile app --profile test logs --no-color > integration-logs/compose.log 2>&1 || true\n - name: Upload integration logs\n if: failure()\n uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0\n with:\n name: integration-test-logs\n path: integration-logs/\n if-no-files-found: warn\n retention-days: 14\n - name: Tear down integration stack\n if: always()\n run: docker compose -f deploy/docker/compose.yaml --profile app --profile test down --volumes --remove-orphans\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n timeout-minutes: 120\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.0.0\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../../.env.example docker compose --env-file .env.example -f deploy/docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f deploy/docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Verify first-party worker tool entry points\n run: docker run --rm --entrypoint sh spectra-worker:ci -c 'imds-fetcher --version && graphql-fuzzer --version'\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n timeout-minutes: 20\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - uses: astral-sh/setup-uv@94527f2e458b27549849d47d273a16bec83a01e9 # v7.0.0\n with:\n python-version: \"3.11\"\n # Audit the locked resolution (all transitive pins) instead of a manifest.\n - run: uv export --frozen --all-packages --no-emit-workspace --format requirements.txt -o /tmp/uv-lock-export.txt > /dev/null\n - run: uvx pip-audit --cache-dir /tmp/pip-audit-cache --progress-spinner off --strict --require-hashes -r /tmp/uv-lock-export.txt\n\n workflow-security:\n name: Workflow & Secret Security\n runs-on: ubuntu-latest\n timeout-minutes: 20\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n fetch-depth: 0\n persist-credentials: false\n - name: Detect exposed credentials\n uses: gitleaks/gitleaks-action@e0c47f4f8be36e29cdc102c57e68cb5cbf0e8d1e # v3.0.0\n env:\n GITHUB_TOKEN: ${{ github.token }}\n - uses: astral-sh/setup-uv@94527f2e458b27549849d47d273a16bec83a01e9 # v7.0.0\n with:\n python-version: \"3.11\"\n - name: Audit GitHub Actions workflow security\n run: uvx --from zizmor==1.27.0 zizmor .github/workflows\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n timeout-minutes: 120\n needs: [test, integration-test]\n # Run the full live smoke for pull requests and the protected release\n # branch. Feature branch pushes are covered by their pull request, avoiding\n # a second expensive stack boot for the same commit.\n if: >-\n github.event_name == 'pull_request' ||\n (github.event_name == 'push' && github.ref == 'refs/heads/main')\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../../.env.test\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f deploy/docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash deploy/docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n expected_services=(\n db redis garage registry clickhouse tensorzero\n app app-replica ai-svc scheduler tools worker caddy\n )\n compose=(docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test)\n for i in $(seq 1 90); do\n missing=()\n pending=()\n unhealthy=()\n for service in \"${expected_services[@]}\"; do\n container_id=$(\"${compose[@]}\" ps -q \"$service\" 2>/dev/null || true)\n if [ -z \"$container_id\" ]; then\n missing+=(\"$service\")\n continue\n fi\n running=$(docker inspect --format '{{.State.Running}}' \"$container_id\" 2>/dev/null || echo false)\n if [ \"$running\" != true ]; then\n missing+=(\"$service\")\n continue\n fi\n health=$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' \"$container_id\" 2>/dev/null || echo unknown)\n case \"$health\" in\n unhealthy) unhealthy+=(\"$service\") ;;\n starting|unknown) pending+=(\"$service\") ;;\n esac\n done\n if [ \"${#unhealthy[@]}\" -gt 0 ]; then\n echo \"Unhealthy expected services: ${unhealthy[*]}\"\n \"${compose[@]}\" ps\n exit 1\n fi\n if [ \"${#missing[@]}\" -eq 0 ] && [ \"${#pending[@]}\" -eq 0 ]; then\n echo \"All expected services are running and healthy (or have no healthcheck).\"\n \"${compose[@]}\" ps\n break\n fi\n echo \"Waiting... ($i/90) missing=${missing[*]:-none} pending=${pending[*]:-none}\"\n sleep 5\n done\n if [ \"${#missing[@]}\" -ne 0 ] || [ \"${#pending[@]}\" -ne 0 ]; then\n echo \"Timed out waiting for expected services to start\" >&2\n \"${compose[@]}\" ps >&2 || true\n docker ps -a --filter \"label=spectra.managed=true\" --format \"{{.Names}}\\t{{.Status}}\" >&2 || true\n exit 1\n fi\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "fd5b86c6774686e34f73f58b6bbcfd9797f07558": {"t": 1785750569.7044191, "n": 17204, "h": "afbaa6142c0d6fe0", "c": "name: CI\n\non:\n push:\n branches: [main, dev]\n pull_request:\n # Feature work lands in dev first; promotion from dev to main uses the\n # exact same required checks.\n branches: [main, dev]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\nconcurrency:\n group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n # Keep the protected release branch's evidence intact while superseding stale\n # pull-request and development-branch runs.\n cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n timeout-minutes: 45\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Build Docker test runner\n run: docker build -f deploy/docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff format\n run: docker run --rm spectra-test-ci python -m ruff format --check tests/ services/ packages/ scripts/ db/\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check tests/ services/ packages/ scripts/ db/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci pyright\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/ services/ -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n timeout-minutes: 75\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../../.env.test\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f deploy/docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f deploy/docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Prepare unit database\n run: |\n docker compose -f deploy/docker/compose.yaml --profile test run --rm unit-test-runner \\\n \"alembic upgrade head\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f deploy/docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov=spectra_ai_core --cov=spectra_billing --cov=spectra_common --cov=spectra_mission --cov=spectra_persistence --cov=spectra_scaling --cov=spectra_storage_policy --cov=spectra_tools_core --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=67\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f deploy/docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n timeout-minutes: 75\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../../.env.test\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start integration infrastructure\n run: |\n ENV_FILE=../../.env.test docker compose -f deploy/docker/compose.yaml --profile app --profile test up -d --wait \\\n db redis garage tensorzero metasploitable dvwa\n GARAGE_CONTAINER=\"$(docker compose -f deploy/docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash deploy/docker/garage-init.sh\n - name: Build and start integration services\n run: |\n ENV_FILE=../../.env.test docker compose -f deploy/docker/compose.yaml --profile app --profile test up -d --build --wait \\\n app ai-svc worker tools caddy\n - name: Run integration tests in Docker\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile test run --rm --no-deps test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n - name: Tear down integration stack\n if: always()\n run: docker compose -f deploy/docker/compose.yaml --profile app --profile test down --volumes --remove-orphans\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n timeout-minutes: 120\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.0.0\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../../.env.example docker compose --env-file .env.example -f deploy/docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f deploy/docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Verify first-party worker tool entry points\n run: docker run --rm --entrypoint sh spectra-worker:ci -c 'imds-fetcher --version && graphql-fuzzer --version'\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n timeout-minutes: 20\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - uses: astral-sh/setup-uv@94527f2e458b27549849d47d273a16bec83a01e9 # v7.0.0\n with:\n python-version: \"3.11\"\n # Audit the locked resolution (all transitive pins) instead of a manifest.\n - run: uv export --frozen --all-packages --no-emit-workspace --format requirements.txt -o /tmp/uv-lock-export.txt > /dev/null\n - run: uvx pip-audit --cache-dir /tmp/pip-audit-cache --progress-spinner off --strict --require-hashes -r /tmp/uv-lock-export.txt\n\n workflow-security:\n name: Workflow & Secret Security\n runs-on: ubuntu-latest\n timeout-minutes: 20\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n fetch-depth: 0\n persist-credentials: false\n - name: Detect exposed credentials\n uses: gitleaks/gitleaks-action@e0c47f4f8be36e29cdc102c57e68cb5cbf0e8d1e # v3.0.0\n env:\n GITHUB_TOKEN: ${{ github.token }}\n - uses: astral-sh/setup-uv@94527f2e458b27549849d47d273a16bec83a01e9 # v7.0.0\n with:\n python-version: \"3.11\"\n - name: Audit GitHub Actions workflow security\n run: uvx --from zizmor==1.27.0 zizmor .github/workflows\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n timeout-minutes: 120\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../../.env.test\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f deploy/docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash deploy/docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n if [ \"${all_running:-0}\" -lt 10 ]; then\n echo \"Timed out waiting for all managed services to start\" >&2\n docker ps -a --filter \"label=spectra.managed=true\" --format \"{{.Names}}\\t{{.Status}}\" >&2 || true\n exit 1\n fi\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "b72772af5b56b0e5542eae5dbdc18201ff7e947b": {"t": 1785750570.8641083, "n": 17204, "h": "3a236efb4b6ee79f", "c": "name: CI\n\non:\n push:\n branches: [main, dev]\n pull_request:\n # Feature work lands in dev first; promotion from dev to main uses the\n # exact same required checks.\n branches: [main, dev]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\nconcurrency:\n group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n # Keep the protected release branch's evidence intact while superseding stale\n # pull-request and development-branch runs.\n cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n timeout-minutes: 45\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Build Docker test runner\n run: docker build -f deploy/docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff format\n run: docker run --rm spectra-test-ci python -m ruff format --check tests/ services/ packages/ scripts/ db/\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check tests/ services/ packages/ scripts/ db/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci pyright\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/ services/ -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n timeout-minutes: 75\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../../.env.test\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f deploy/docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f deploy/docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Prepare unit database\n run: |\n docker compose -f deploy/docker/compose.yaml --profile test run --rm unit-test-runner \\\n \"alembic upgrade head\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f deploy/docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov=spectra_ai_core --cov=spectra_billing --cov=spectra_common --cov=spectra_mission --cov=spectra_persistence --cov=spectra_scaling --cov=spectra_storage_policy --cov=spectra_tools_core --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=67\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f deploy/docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n timeout-minutes: 75\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../../.env.test\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start integration infrastructure\n run: |\n ENV_FILE=../../.env.test docker compose -f deploy/docker/compose.yaml --profile app --profile test up -d --wait \\\n db redis garage tensorzero metasploitable dvwa\n GARAGE_CONTAINER=\"$(docker compose -f deploy/docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash deploy/docker/garage-init.sh\n - name: Build and start integration services\n run: |\n ENV_FILE=../../.env.test docker compose -f deploy/docker/compose.yaml --profile app --profile test up -d --build --wait \\\n app ai-svc worker tools caddy\n - name: Run integration tests in Docker\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile test run --rm --no-deps test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n - name: Tear down integration stack\n if: always()\n run: docker compose -f deploy/docker/compose.yaml --profile app --profile test down --volumes --remove-orphans\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n timeout-minutes: 120\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.0.0\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../../.env.example docker compose --env-file .env.example -f deploy/docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f deploy/docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Verify first-party worker tool entry points\n run: docker run --rm --entrypoint sh spectra-worker:ci -c 'imds-fetcher --version && graphql-fuzzer --version'\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n timeout-minutes: 20\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - uses: astral-sh/setup-uv@94527f2e458b27549849d47d273a16bec83a01e9 # v7.0.0\n with:\n python-version: \"3.11\"\n # Audit the locked resolution (all transitive pins) instead of a manifest.\n - run: uv export --frozen --all-packages --no-emit-workspace --format requirements.txt -o /tmp/uv-lock-export.txt > /dev/null\n - run: uvx pip-audit --cache-dir /tmp/pip-audit-cache --progress-spinner off --strict --require-hashes -r /tmp/uv-lock-export.txt\n\n workflow-security:\n name: Workflow & Secret Security\n runs-on: ubuntu-latest\n timeout-minutes: 20\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n fetch-depth: 0\n persist-credentials: false\n - name: Detect exposed credentials\n uses: gitleaks/gitleaks-action@dcedce43c6f43de0b836d1fe38946645c9c638dc # v2.3.9\n env:\n GITHUB_TOKEN: ${{ github.token }}\n - uses: astral-sh/setup-uv@94527f2e458b27549849d47d273a16bec83a01e9 # v7.0.0\n with:\n python-version: \"3.11\"\n - name: Audit GitHub Actions workflow security\n run: uvx --from zizmor==1.27.0 zizmor .github/workflows\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n timeout-minutes: 120\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../../.env.test\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f deploy/docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash deploy/docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n if [ \"${all_running:-0}\" -lt 10 ]; then\n echo \"Timed out waiting for all managed services to start\" >&2\n docker ps -a --filter \"label=spectra.managed=true\" --format \"{{.Names}}\\t{{.Status}}\" >&2 || true\n exit 1\n fi\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "eea468b08571e02b4ca032dadb21ba325c91e9dc": {"t": 1785750571.9953504, "n": 16988, "h": "ce2350cc011118dc", "c": "name: CI\n\non:\n push:\n branches: [main, dev]\n pull_request:\n # Feature work lands in dev first; promotion from dev to main uses the\n # exact same required checks.\n branches: [main, dev]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\nconcurrency:\n group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n # Keep the protected release branch's evidence intact while superseding stale\n # pull-request and development-branch runs.\n cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n timeout-minutes: 45\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Build Docker test runner\n run: docker build -f deploy/docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff format\n run: docker run --rm spectra-test-ci python -m ruff format --check tests/ services/ packages/ scripts/ db/\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check tests/ services/ packages/ scripts/ db/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci pyright\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/ services/ -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n timeout-minutes: 75\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f deploy/docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f deploy/docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f deploy/docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov=spectra_ai_core --cov=spectra_billing --cov=spectra_common --cov=spectra_mission --cov=spectra_persistence --cov=spectra_scaling --cov=spectra_storage_policy --cov=spectra_tools_core --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=67\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f deploy/docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n timeout-minutes: 75\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../../.env.test\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start integration infrastructure\n run: |\n ENV_FILE=../../.env.test docker compose -f deploy/docker/compose.yaml --profile app --profile test up -d --wait \\\n db redis garage tensorzero metasploitable dvwa\n GARAGE_CONTAINER=\"$(docker compose -f deploy/docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash deploy/docker/garage-init.sh\n - name: Build and start integration services\n run: |\n ENV_FILE=../../.env.test docker compose -f deploy/docker/compose.yaml --profile app --profile test up -d --build --wait \\\n app ai-svc worker tools caddy\n - name: Run integration tests in Docker\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile test run --rm --no-deps test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n - name: Tear down integration stack\n if: always()\n run: docker compose -f deploy/docker/compose.yaml --profile app --profile test down --volumes --remove-orphans\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n timeout-minutes: 120\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.0.0\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../../.env.example docker compose --env-file .env.example -f deploy/docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f deploy/docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.0.0\n with:\n context: .\n file: deploy/docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Verify first-party worker tool entry points\n run: docker run --rm --entrypoint sh spectra-worker:ci -c 'imds-fetcher --version && graphql-fuzzer --version'\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n timeout-minutes: 20\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - uses: astral-sh/setup-uv@94527f2e458b27549849d47d273a16bec83a01e9 # v7.0.0\n with:\n python-version: \"3.11\"\n # Audit the locked resolution (all transitive pins) instead of a manifest.\n - run: uv export --frozen --all-packages --no-emit-workspace --format requirements.txt -o /tmp/uv-lock-export.txt > /dev/null\n - run: uvx pip-audit --cache-dir /tmp/pip-audit-cache --progress-spinner off --strict --require-hashes -r /tmp/uv-lock-export.txt\n\n workflow-security:\n name: Workflow & Secret Security\n runs-on: ubuntu-latest\n timeout-minutes: 20\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n fetch-depth: 0\n persist-credentials: false\n - name: Detect exposed credentials\n uses: gitleaks/gitleaks-action@dcedce43c6f43de0b836d1fe38946645c9c638dc # v2.3.9\n env:\n GITHUB_TOKEN: ${{ github.token }}\n - uses: astral-sh/setup-uv@94527f2e458b27549849d47d273a16bec83a01e9 # v7.0.0\n with:\n python-version: \"3.11\"\n - name: Audit GitHub Actions workflow security\n run: uvx --from zizmor==1.27.0 zizmor .github/workflows\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n timeout-minutes: 120\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../../.env.test\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.0\n with:\n persist-credentials: false\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f deploy/docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash deploy/docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n if [ \"${all_running:-0}\" -lt 10 ]; then\n echo \"Timed out waiting for all managed services to start\" >&2\n docker ps -a --filter \"label=spectra.managed=true\" --format \"{{.Names}}\\t{{.Status}}\" >&2 || true\n exit 1\n fi\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "b8fe0067b6b173168d53581ed312e92589ef18a5": {"t": 1785750573.54129, "n": 13933, "h": "11711ba57138a7f3", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - name: Build Docker test runner\n run: docker build -f deploy/docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check tests/ services/ packages/ scripts/ db/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/ services/ -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f deploy/docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f deploy/docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f deploy/docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov=spectra_ai_core --cov=spectra_billing --cov=spectra_common --cov=spectra_mission --cov=spectra_persistence --cov=spectra_scaling --cov=spectra_storage_policy --cov=spectra_tools_core --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f deploy/docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v7\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../../.env.test\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f deploy/docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../../.env.test docker compose -f deploy/docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f deploy/docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash deploy/docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: docker/setup-buildx-action@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../../.env.example docker compose --env-file .env.example -f deploy/docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f deploy/docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: deploy/docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: deploy/docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: deploy/docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: deploy/docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: deploy/docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: astral-sh/setup-uv@v7\n with:\n python-version: \"3.11\"\n # Audit the locked resolution (all transitive pins) instead of a manifest.\n # Ignore known disputed advisories with no applicable fix.\n - run: uv export --frozen --all-packages --no-emit-workspace --no-hashes --format requirements.txt -o /tmp/uv-lock-export.txt\n - run: uvx pip-audit --no-deps -r /tmp/uv-lock-export.txt --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../../.env.test\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f deploy/docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash deploy/docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v7\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n\n"}, "eba78bdb9fec6653595031f1d638f4f0696253ab": {"t": 1785750574.8273473, "n": 15897, "h": "bdf0b50ac90b693c", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - name: Build Docker test runner\n run: docker build -f deploy/deploy/docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check packages/platform/src/spectra_platform tests/ services/ packages/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/platform/src/spectra_platform -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f deploy/docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f deploy/docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f deploy/docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_platform --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f deploy/docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v7\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../../.env.test\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f deploy/docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../../.env.test docker compose -f deploy/docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f deploy/docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash deploy/docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: docker/setup-buildx-action@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../../.env.example docker compose --env-file .env.example -f deploy/docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f deploy/docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: deploy/deploy/docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: deploy/deploy/docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: deploy/deploy/docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: deploy/deploy/docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: deploy/deploy/docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n - name: Verify packages/platform/src/spectra_platform/_meta/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('packages/platform/src/spectra_platform/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../../.env.test\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f deploy/docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash deploy/docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v7\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f deploy/docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n\n # ── Package Build Verification ─────────────────────────────────\n # GitHub Packages does not expose a PyPI-compatible registry. CI verifies\n # wheel/sdist builds and uploads them as run artifacts; release assets are\n # attached by .github/workflows/release.yml.\n build-packages:\n name: Build package artifacts\n runs-on: ubuntu-latest\n if: github.event_name == 'push' && github.ref == 'refs/heads/main'\n needs: [static-analysis, test]\n permissions:\n contents: read\n steps:\n - uses: actions/checkout@v6\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n - name: Install uv\n run: pip install uv\n - name: Build packages\n run: |\n uv build packages/common\n uv build packages/domain\n uv build packages/platform\n uv build packages/tools-core\n uv build packages/storage-policy\n mkdir -p package-artifacts\n cp packages/common/dist/* package-artifacts/\n cp packages/domain/dist/* package-artifacts/\n cp packages/platform/dist/* package-artifacts/\n cp packages/tools-core/dist/* package-artifacts/\n cp packages/storage-policy/dist/* package-artifacts/\n - name: Upload package artifacts\n uses: actions/upload-artifact@v7\n with:\n name: python-packages\n path: package-artifacts/*\n if-no-files-found: error\n retention-days: 14\n"}, "0295ab2cb65c0215d867bfc6fa5f87af29d33274": {"t": 1785750575.9468226, "n": 15675, "h": "398180502f021941", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check packages/platform/src/spectra_platform tests/ services/ packages/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/platform/src/spectra_platform -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_platform --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v7\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: docker/setup-buildx-action@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n - name: Verify packages/platform/src/spectra_platform/_meta/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('packages/platform/src/spectra_platform/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v7\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n\n # ── Package Build Verification ─────────────────────────────────\n # GitHub Packages does not expose a PyPI-compatible registry. CI verifies\n # wheel/sdist builds and uploads them as run artifacts; release assets are\n # attached by .github/workflows/release.yml.\n build-packages:\n name: Build package artifacts\n runs-on: ubuntu-latest\n if: github.event_name == 'push' && github.ref == 'refs/heads/main'\n needs: [static-analysis, test]\n permissions:\n contents: read\n steps:\n - uses: actions/checkout@v6\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n - name: Install uv\n run: pip install uv\n - name: Build packages\n run: |\n uv build packages/common\n uv build packages/domain\n uv build packages/platform\n uv build packages/tools-core\n uv build packages/storage-policy\n mkdir -p package-artifacts\n cp packages/common/dist/* package-artifacts/\n cp packages/domain/dist/* package-artifacts/\n cp packages/platform/dist/* package-artifacts/\n cp packages/tools-core/dist/* package-artifacts/\n cp packages/storage-policy/dist/* package-artifacts/\n - name: Upload package artifacts\n uses: actions/upload-artifact@v7\n with:\n name: python-packages\n path: package-artifacts/*\n if-no-files-found: error\n retention-days: 14\n"}, "d2701f607a03f0eebdb6ba2909357f32238fd717": {"t": 1785750577.179178, "n": 15519, "h": "81678aa311eabed2", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check packages/platform/src/spectra_platform tests/ services/ packages/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/platform/src/spectra_platform -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_platform --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v7\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: docker/setup-buildx-action@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n - name: Verify packages/platform/src/spectra_platform/_meta/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('packages/platform/src/spectra_platform/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v7\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n\n # ── Package Publishing ──────────────────────────────────────────\n # Builds and publishes Python packages to GitHub Packages registry.\n # Only runs on push to main (not PRs) to avoid publishing from feature branches.\n publish-packages:\n name: Publish packages\n runs-on: ubuntu-latest\n if: github.event_name == 'push' && github.ref == 'refs/heads/main'\n needs: [static-analysis, test]\n permissions:\n contents: read\n packages: write\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: '3.11'\n - name: Install uv\n run: pip install uv\n - name: Build packages\n run: |\n uv build packages/common\n uv build packages/domain\n uv build packages/platform\n uv build packages/tools-core\n uv build packages/storage-policy\n - name: Publish to GitHub Packages\n run: |\n uv publish --publish-url https://pypi.org/legacy/ \\\n --username __token__ \\\n --password \"${{ secrets.GITHUB_TOKEN }}\" \\\n packages/common/dist/*.whl \\\n packages/domain/dist/*.whl \\\n packages/platform/dist/*.whl \\\n packages/tools-core/dist/*.whl \\\n packages/storage-policy/dist/*.whl\n"}, "c1e9be3d573177b5d98ae74fa3b652e2735ab2b4": {"t": 1785750578.4613886, "n": 15519, "h": "9cb9656875399e3b", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check packages/platform/src/spectra_platform tests/ services/ packages/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/platform/src/spectra_platform -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_platform --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v7\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: docker/setup-buildx-action@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n - name: Verify packages/platform/src/spectra_platform/_meta/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('packages/platform/src/spectra_platform/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v7\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n\n # ── Package Publishing ──────────────────────────────────────────\n # Builds and publishes Python packages to GitHub Packages registry.\n # Only runs on push to main (not PRs) to avoid publishing from feature branches.\n publish-packages:\n name: Publish packages\n runs-on: ubuntu-latest\n if: github.event_name == 'push' && github.ref == 'refs/heads/main'\n needs: [static-analysis, test]\n permissions:\n contents: read\n packages: write\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: '3.11'\n - name: Install uv\n run: pip install uv\n - name: Build packages\n run: |\n uv build packages/common\n uv build packages/domain\n uv build packages/platform\n uv build packages/tools-core\n uv build packages/storage-policy\n - name: Publish to GitHub Packages\n run: |\n uv publish --publish-url https://pypi.org/legacy/ \\\n --username __token__ \\\n --password \"${{ secrets.GITHUB_TOKEN }}\" \\\n packages/common/dist/*.whl \\\n packages/domain/dist/*.whl \\\n packages/platform/dist/*.whl \\\n packages/tools-core/dist/*.whl \\\n packages/storage-policy/dist/*.whl\n"}, "f456b6aed6eb925d2fb1e88c5a36e08976e06e91": {"t": 1785750581.7409604, "n": 15519, "h": "10b68c7707d37014", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check packages/platform/src/spectra_platform tests/ services/ packages/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/platform/src/spectra_platform -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_platform --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v7\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: docker/setup-buildx-action@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n - name: Verify packages/platform/src/spectra_platform/_meta/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('packages/platform/src/spectra_platform/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v7\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n\n # ── Package Publishing ──────────────────────────────────────────\n # Builds and publishes Python packages to GitHub Packages registry.\n # Only runs on push to main (not PRs) to avoid publishing from feature branches.\n publish-packages:\n name: Publish packages\n runs-on: ubuntu-latest\n if: github.event_name == 'push' && github.ref == 'refs/heads/main'\n needs: [static-analysis, test]\n permissions:\n contents: read\n packages: write\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: '3.11'\n - name: Install uv\n run: pip install uv\n - name: Build packages\n run: |\n uv build packages/common\n uv build packages/domain\n uv build packages/platform\n uv build packages/tools-core\n uv build packages/storage-policy\n - name: Publish to GitHub Packages\n run: |\n uv publish --publish-url https://pypi.org/legacy/ \\\n --username __token__ \\\n --password \"${{ secrets.GITHUB_TOKEN }}\" \\\n packages/common/dist/*.whl \\\n packages/domain/dist/*.whl \\\n packages/platform/dist/*.whl \\\n packages/tools-core/dist/*.whl \\\n packages/storage-policy/dist/*.whl\n"}, "c8bbdba7046188bfc372d3d6d77fea131204cf4c": {"t": 1785750582.8716772, "n": 15519, "h": "b963ec4773ae3034", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check packages/platform/src/spectra_platform tests/ services/ packages/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/platform/src/spectra_platform -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_platform --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v7\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: docker/setup-buildx-action@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n - name: Verify packages/platform/src/spectra_platform/_meta/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('packages/platform/src/spectra_platform/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v7\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n\n # ── Package Publishing ──────────────────────────────────────────\n # Builds and publishes Python packages to GitHub Packages registry.\n # Only runs on push to main (not PRs) to avoid publishing from feature branches.\n publish-packages:\n name: Publish packages\n runs-on: ubuntu-latest\n if: github.event_name == 'push' && github.ref == 'refs/heads/main'\n needs: [static-analysis, test]\n permissions:\n contents: read\n packages: write\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: '3.11'\n - name: Install uv\n run: pip install uv\n - name: Build packages\n run: |\n uv build packages/common\n uv build packages/domain\n uv build packages/platform\n uv build packages/tools-core\n uv build packages/storage-policy\n - name: Publish to GitHub Packages\n run: |\n uv publish --publish-url https://pypi.org/legacy/ \\\n --username __token__ \\\n --password \"${{ secrets.GITHUB_TOKEN }}\" \\\n packages/common/dist/*.whl \\\n packages/domain/dist/*.whl \\\n packages/platform/dist/*.whl \\\n packages/tools-core/dist/*.whl \\\n packages/storage-policy/dist/*.whl\n"}, "6b127a5914912cd182bb122cc85ff06954738a83": {"t": 1785750583.995226, "n": 14215, "h": "bab3eef4c0a4176a", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check packages/platform/src/spectra_platform tests/ services/ packages/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/platform/src/spectra_platform -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_platform --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v7\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: docker/setup-buildx-action@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v7\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n - name: Verify packages/platform/src/spectra_platform/_meta/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('packages/platform/src/spectra_platform/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v7\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "ae1488707410686d783ebfd6fae6524a444150b8": {"t": 1785750585.1134496, "n": 14215, "h": "d6f631dab6491d23", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check packages/platform/src/spectra_platform tests/ services/ packages/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/platform/src/spectra_platform -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_platform --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v7\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: docker/setup-buildx-action@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n - name: Verify packages/platform/src/spectra_platform/_meta/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('packages/platform/src/spectra_platform/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v7\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "a0280301e3eea6dbde7acd02b889a72d4942644f": {"t": 1785750586.236676, "n": 14215, "h": "faf560ac2637e27d", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check packages/platform/src/spectra_platform tests/ services/ packages/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/platform/src/spectra_platform -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_platform --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v7\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: docker/setup-buildx-action@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v6\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n - name: Verify packages/platform/src/spectra_platform/_meta/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('packages/platform/src/spectra_platform/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v6\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v7\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "71015afabb12262cfa639b3d1323b672a059f5b6": {"t": 1785750587.3778985, "n": 14215, "h": "79c49c23b191b496", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check packages/platform/src/spectra_platform tests/ services/ packages/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/platform/src/spectra_platform -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_platform --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v7\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: docker/setup-buildx-action@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n - name: Verify packages/platform/src/spectra_platform/_meta/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('packages/platform/src/spectra_platform/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v7\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "9bcf33e5283f7846c54f3e453f605ac4a97ce464": {"t": 1785750588.6671965, "n": 14215, "h": "2c0ed0f4e22ee5ef", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check packages/platform/src/spectra_platform tests/ services/ packages/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/platform/src/spectra_platform -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_platform --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v4\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: docker/setup-buildx-action@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v6\n with:\n python-version: \"3.11\"\n - name: Verify packages/platform/src/spectra_platform/_meta/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('packages/platform/src/spectra_platform/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v4\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "468e911f6acefcd5c3e678f69f29853648161032": {"t": 1785750592.6012807, "n": 14215, "h": "fcb41e64f5efc675", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check packages/platform/src/spectra_platform tests/ services/ packages/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/platform/src/spectra_platform -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_platform --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v4\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: docker/setup-buildx-action@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n - name: Verify packages/platform/src/spectra_platform/_meta/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('packages/platform/src/spectra_platform/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v4\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "385b392edd6516910d4e51d06f0b9d26d1ed3fc3": {"t": 1785750594.72557, "n": 15519, "h": "a46e01d5a44f1c5e", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check packages/platform/src/spectra_platform tests/ services/ packages/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/platform/src/spectra_platform -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_platform --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v4\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: docker/setup-buildx-action@v3\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n - name: Verify packages/platform/src/spectra_platform/_meta/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('packages/platform/src/spectra_platform/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v4\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n\n # ── Package Publishing ──────────────────────────────────────────\n # Builds and publishes Python packages to GitHub Packages registry.\n # Only runs on push to main (not PRs) to avoid publishing from feature branches.\n publish-packages:\n name: Publish packages\n runs-on: ubuntu-latest\n if: github.event_name == 'push' && github.ref == 'refs/heads/main'\n needs: [static-analysis, test]\n permissions:\n contents: read\n packages: write\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: '3.11'\n - name: Install uv\n run: pip install uv\n - name: Build packages\n run: |\n uv build packages/common\n uv build packages/domain\n uv build packages/platform\n uv build packages/tools-core\n uv build packages/storage-policy\n - name: Publish to GitHub Packages\n run: |\n uv publish --publish-url https://pypi.org/legacy/ \\\n --username __token__ \\\n --password \"${{ secrets.GITHUB_TOKEN }}\" \\\n packages/common/dist/*.whl \\\n packages/domain/dist/*.whl \\\n packages/platform/dist/*.whl \\\n packages/tools-core/dist/*.whl \\\n packages/storage-policy/dist/*.whl\n"}, "082c03edfa154878fba257764583e61876fdbb8c": {"t": 1785750595.8366134, "n": 14215, "h": "4908d05950d95bb4", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check packages/platform/src/spectra_platform tests/ services/ packages/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/platform/src/spectra_platform -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_platform --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v4\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: docker/setup-buildx-action@v3\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n cache-from: type=gha\n cache-to: type=gha,mode=max\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n - name: Verify packages/platform/src/spectra_platform/_meta/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('packages/platform/src/spectra_platform/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v4\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "8bfafe54ef57ad5520ea566e3ff2363b22cb3136": {"t": 1785750596.960416, "n": 14176, "h": "7d4a3f216dc0fad8", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check packages/platform/src/spectra_platform tests/ services/ packages/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/platform/src/spectra_platform -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_platform --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v4\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: docker/setup-buildx-action@v3\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: sudo rm -rf /opt/hostedtoolcache || true; df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n - name: Verify packages/platform/src/spectra_platform/_meta/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('packages/platform/src/spectra_platform/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n # Performance runs first: it calls ensure_admin_setup() so a fresh postgres volume has an\n # admin user before e2e tests authenticate (see tests/platform_harness.py defaults).\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120 --override-ini=addopts=\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v4\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "43e3b1c3c7482c66dd17807f20cae17978058d03": {"t": 1785750599.043008, "n": 13917, "h": "e0ae3be9ce8ba62e", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check packages/platform/src/spectra_platform tests/ services/ packages/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r packages/platform/src/spectra_platform -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_platform --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v4\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: docker/setup-buildx-action@v3\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: sudo rm -rf /opt/hostedtoolcache || true; df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n - name: Verify packages/platform/src/spectra_platform/_meta/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('packages/platform/src/spectra_platform/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120\"\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v4\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "2b21a4f60044439fd82ef1acde53021198afe254": {"t": 1785750600.15642, "n": 13831, "h": "43e1f64c6ad8c00d", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check spectra_platform/ tests/ services/ packages/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r spectra_platform/ -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=spectra_platform --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v4\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: docker/setup-buildx-action@v3\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: sudo rm -rf /opt/hostedtoolcache || true; df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n - name: Verify spectra_platform/_meta/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('spectra_platform/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120\"\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v4\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "19704fdb0dc85ac87b6d654691a63c3eeee8799f": {"t": 1785750601.4245417, "n": 13766, "h": "b6c4a7f481133d58", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n # One image build (Dockerfile.test): Ruff, import boundaries, Pyright, Bandit — avoids\n # duplicating the same docker build across separate jobs on fresh runners.\n static-analysis:\n name: Static analysis\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Ruff\n run: docker run --rm spectra-test-ci python -m ruff check app/ tests/ services/ packages/\n - name: Import boundaries\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n - name: Pyright\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright >/dev/null && pyright\"\n - name: Bandit\n run: docker run --rm spectra-test-ci bandit -r app/ -c pyproject.toml --severity-level high --confidence-level high\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=app --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v4\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: docker/setup-buildx-action@v3\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: sudo rm -rf /opt/hostedtoolcache || true; df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n - name: Verify app/_meta/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('app/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120\"\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v4\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "000a1b192bf9c6cea818d665036171cc353c876f": {"t": 1785750602.5745044, "n": 14310, "h": "f3f623a6bbb9c4ff", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n lint:\n name: Lint\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Run lint in Docker\n run: docker run --rm spectra-test-ci python -m ruff check app/ tests/ services/ packages/\n - name: Check import boundaries in Docker\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n\n type-check:\n name: Type Check\n runs-on: ubuntu-latest\n needs: lint\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Run pyright in Docker\n run: docker run --rm spectra-test-ci sh -c \"pip install --no-cache-dir pyright && pyright\"\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=app --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov=spectra_scheduler --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v4\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n security:\n name: Security Scan\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Run Bandit in Docker\n run: docker run --rm spectra-test-ci bandit -r app/ -c pyproject.toml --severity-level high --confidence-level high\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: docker/setup-buildx-action@v3\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: sudo rm -rf /opt/hostedtoolcache || true; df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build Docker test runner image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.test\n push: false\n load: false\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n - name: Verify app/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('app/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n continue-on-error: false\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120\"\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v4\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "ab52caba0a595cad321b2e50d54d46e473c44853": {"t": 1785750603.7085989, "n": 14345, "h": "ddb29cc04d648922", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n lint:\n name: Lint\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Run lint in Docker\n run: docker run --rm spectra-test-ci python -m ruff check app/ tests/ services/ packages/\n - name: Check import boundaries in Docker\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n\n type-check:\n name: Type Check\n runs-on: ubuntu-latest\n needs: lint\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n cache: pip\n - run: pip install pyright\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n - run: pyright\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=app --cov=spectra_api --cov=spectra_worker --cov=spectra_ai --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v4\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n security:\n name: Security Scan\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Run Bandit in Docker\n run: docker run --rm spectra-test-ci bandit -r app/ -c pyproject.toml --severity-level high --confidence-level high\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: docker/setup-buildx-action@v3\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: sudo rm -rf /opt/hostedtoolcache || true; df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build Docker test runner image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.test\n push: false\n load: false\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n - name: Verify app/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('app/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n continue-on-error: false\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120\"\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v4\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "90195b1b4489010f4ad69c54eb5e6e7b7239e4ef": {"t": 1785750604.850011, "n": 14308, "h": "f2d99d02ca5335f1", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n lint:\n name: Lint\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Run lint in Docker\n run: docker run --rm spectra-test-ci python -m ruff check app/ tests/\n - name: Check import boundaries in Docker\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n\n type-check:\n name: Type Check\n runs-on: ubuntu-latest\n needs: lint\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n cache: pip\n - run: pip install pyright\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n - run: pyright\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=app --cov=spectra_api --cov=spectra_worker --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v4\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n security:\n name: Security Scan\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Run Bandit in Docker\n run: docker run --rm spectra-test-ci bandit -r app/ -c pyproject.toml --severity-level high --confidence-level high\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: docker/setup-buildx-action@v3\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: sudo rm -rf /opt/hostedtoolcache || true; df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build Docker test runner image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.test\n push: false\n load: false\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n - name: Verify app/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('app/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n continue-on-error: false\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120\"\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v4\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "47bf3dac8ef894a11439d9630d50ae043fdcc6c5": {"t": 1785750606.072024, "n": 14290, "h": "d1295506a621641a", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n lint:\n name: Lint\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Run lint in Docker\n run: docker run --rm spectra-test-ci python -m ruff check app/ tests/\n - name: Check import boundaries in Docker\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n\n type-check:\n name: Type Check\n runs-on: ubuntu-latest\n needs: lint\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n cache: pip\n - run: pip install pyright\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n - run: pyright\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=app --cov=spectra_worker --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v4\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n security:\n name: Security Scan\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Run Bandit in Docker\n run: docker run --rm spectra-test-ci bandit -r app/ -c pyproject.toml --severity-level high --confidence-level high\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: docker/setup-buildx-action@v3\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image builds\n run: sudo rm -rf /opt/hostedtoolcache || true; df -h\n - name: Build Caddy image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build API image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build AI image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build scheduler image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build worker image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; docker builder prune -af || true; docker system prune -f || true; df -h\n - name: Build Docker test runner image\n uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.test\n push: false\n load: false\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n - name: Verify app/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('app/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n continue-on-error: false\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120\"\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v4\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "d21683a6754c42841051655532580598ab04f91d": {"t": 1785750607.219007, "n": 14049, "h": "d39d3a56353653ae", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n lint:\n name: Lint\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Run lint in Docker\n run: docker run --rm spectra-test-ci python -m ruff check app/ tests/\n - name: Check import boundaries in Docker\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n\n type-check:\n name: Type Check\n runs-on: ubuntu-latest\n needs: lint\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n cache: pip\n - run: pip install pyright\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n - run: pyright\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=app --cov=spectra_worker --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v4\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n security:\n name: Security Scan\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Run Bandit in Docker\n run: docker run --rm spectra-test-ci bandit -r app/ -c pyproject.toml --severity-level high --confidence-level high\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: docker/setup-buildx-action@v3\n - uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n - uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n - uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n - uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n - uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n - uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.test\n push: false\n load: false\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Free hosted runner tool cache before image scans\n run: sudo rm -rf /opt/hostedtoolcache || true; df -h\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after Caddy scan\n run: docker rmi spectra-caddy:ci || true; docker builder prune -af || true; docker system prune -f || true\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; docker builder prune -af || true; docker system prune -f || true\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; docker builder prune -af || true; docker system prune -f || true\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; docker builder prune -af || true; docker system prune -f || true\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n - name: Verify app/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('app/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n continue-on-error: false\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120\"\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v4\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}, "8fbf5df19fafae33d493414302bd451dc14f7e3a": {"t": 1785750608.3276339, "n": 13761, "h": "55e79391ee0de135", "c": "name: CI\n\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main]\n\nenv:\n FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: \"true\"\n\npermissions:\n contents: read\n\njobs:\n lint:\n name: Lint\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Run lint in Docker\n run: docker run --rm spectra-test-ci python -m ruff check app/ tests/\n - name: Check import boundaries in Docker\n run: docker run --rm spectra-test-ci python scripts/check_import_boundaries.py\n\n type-check:\n name: Type Check\n runs-on: ubuntu-latest\n needs: lint\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n cache: pip\n - run: pip install pyright\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n - run: pyright\n\n test:\n name: Unit Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker unit runner\n run: docker compose -f docker/compose.yaml --profile test build unit-test-runner\n - name: Validate TensorZero config\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm --no-deps unit-test-runner \"python -c \\\"import tomllib; tomllib.load(open('config/tensorzero.toml', 'rb')); print('tensorzero.toml: valid')\\\"\"\n - name: Run unit tests with coverage in Docker\n run: |\n set +e\n docker compose -f docker/compose.yaml --profile test run --name spectra-unit-coverage unit-test-runner \\\n \"python -m pytest tests/unit/ -q --override-ini=addopts= --cov=app --cov=spectra_worker --cov-report=term-missing --cov-report=xml:/tmp/coverage.xml --cov-fail-under=70\"\n status=$?\n docker cp spectra-unit-coverage:/tmp/coverage.xml coverage.xml 2>/dev/null || true\n docker rm -f spectra-unit-coverage >/dev/null 2>&1 || true\n exit \"$status\"\n - name: Run settings tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile test run --rm settings-test-runner\n - name: Coverage summary\n if: always()\n run: |\n if [ -f coverage.xml ]; then\n echo '## Coverage Report' >> \"$GITHUB_STEP_SUMMARY\"\n python3 << 'PYEOF' >> \"$GITHUB_STEP_SUMMARY\"\n import xml.etree.ElementTree as ET\n tree = ET.parse('coverage.xml')\n root = tree.getroot()\n rate = float(root.attrib.get('line-rate', 0)) * 100\n print(f'| Metric | Value |')\n print(f'|--------|-------|')\n print(f'| Line coverage | {rate:.1f}% |')\n PYEOF\n fi\n - name: Upload coverage artifact\n if: always()\n uses: actions/upload-artifact@v4\n with:\n name: coverage-report\n path: coverage.xml\n retention-days: 30\n - name: Remove copied coverage artifact\n if: always()\n run: rm -f coverage.xml\n\n integration-test:\n name: Integration Tests\n runs-on: ubuntu-latest\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Build Docker integration runner\n run: docker compose -f docker/compose.yaml --profile app --profile test build test-runner\n - name: Bootstrap Garage for integration tests\n run: |\n ENV_FILE=../.env.test docker compose -f docker/compose.yaml --profile app --profile test up -d garage\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Run integration tests in Docker\n run: |\n docker compose -f docker/compose.yaml --profile app --profile test run --rm test-runner \\\n \"python -m pytest tests/integration/ -v --tb=short --timeout=120 --override-ini=addopts= -k 'not live and not e2e'\"\n\n security:\n name: Security Scan\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - name: Build Docker test runner\n run: docker build -f docker/Dockerfile.test -t spectra-test-ci .\n - name: Run Bandit in Docker\n run: docker run --rm spectra-test-ci bandit -r app/ -c pyproject.toml --severity-level high --confidence-level high\n\n docker-build:\n name: Docker Build Verification\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: docker/setup-buildx-action@v3\n - uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.caddy\n push: false\n load: true\n tags: spectra-caddy:ci\n - uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.api\n push: false\n load: true\n tags: spectra-api:ci\n - uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.ai\n push: false\n load: true\n tags: spectra-ai:ci\n - uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.scheduler\n push: false\n load: true\n tags: spectra-scheduler:ci\n - uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.worker\n push: false\n load: true\n tags: spectra-worker:ci\n - uses: docker/build-push-action@v6\n with:\n context: .\n file: docker/Dockerfile.test\n push: false\n load: false\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Validate Compose config\n run: ENV_FILE=../.env.example docker compose --env-file .env.example -f docker/compose.yaml --profile app --profile test --profile targets config --quiet\n - name: Validate Swarm compose\n run: docker compose --env-file .env.example -f docker/docker-compose.swarm.yml config --quiet\n - name: Scan API image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-api:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after API scan\n run: docker rmi spectra-api:ci || true; docker builder prune -af || true; docker system prune -f || true\n - name: Scan AI image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-ai:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after AI scan\n run: docker rmi spectra-ai:ci || true; docker builder prune -af || true; docker system prune -f || true\n - name: Scan scheduler image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-scheduler:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after scheduler scan\n run: docker rmi spectra-scheduler:ci || true; docker builder prune -af || true; docker system prune -f || true\n - name: Scan worker image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-worker:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n - name: Free Docker cache after worker scan\n run: docker rmi spectra-worker:ci || true; docker builder prune -af || true; docker system prune -f || true\n - name: Scan Caddy image for critical CVEs\n uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1\n with:\n image-ref: spectra-caddy:ci\n severity: CRITICAL\n ignore-unfixed: true\n exit-code: \"1\"\n\n deps:\n name: Dependency Audit\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n cache: pip\n - run: python -m pip install --upgrade pip\n - run: pip install pip-audit\n - run: sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config python3-dev\n - run: pip install -r requirements/app.txt\n # pip-audit: hard gate for project dependencies; ignore known disputed advisories\n # and the runner's transient pip advisory when no fixed pip release is available.\n - run: pip-audit --fix --dry-run -l --ignore-vuln PYSEC-2024-65 --ignore-vuln PYSEC-2024-66 --ignore-vuln CVE-2026-3219\n\n version-check:\n name: Version file check\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-python@v5\n with:\n python-version: \"3.11\"\n - name: Verify app/version.py exists and has __version__\n run: |\n python3 -c \"exec(open('app/_meta/version.py').read()); print('Version:', __version__)\"\n\n compose-smoke:\n name: Compose Smoke Tests\n runs-on: ubuntu-latest\n needs: [test, integration-test]\n if: github.event_name == 'push'\n continue-on-error: false\n env:\n ENCRYPTION_KEY: test-encryption-key\n ENV_FILE: ../.env.test\n steps:\n - uses: actions/checkout@v4\n - name: Ensure .env.test for Docker Compose\n run: test -f .env.test || cp .env.test.example .env.test\n - name: Start test stack\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test up -d --build\n - name: Bootstrap Garage buckets\n run: |\n GARAGE_CONTAINER=\"$(docker compose -f docker/compose.yaml ps -q garage)\" \\\n GARAGE_ACCESS_KEY=\"${GARAGE_ACCESS_KEY:-GK0123456789abcdef01234567}\" \\\n GARAGE_SECRET_KEY=\"${GARAGE_SECRET_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}\" \\\n GARAGE_PRINT_CREDENTIALS=0 \\\n bash docker/garage-init.sh\n - name: Wait for services to be healthy\n run: |\n echo \"Waiting for services to become healthy...\"\n for i in $(seq 1 90); do\n containers=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\t{{.Status}}\")\n if [ -z \"$containers\" ]; then\n echo \"No managed containers found yet...\"\n sleep 5\n continue\n fi\n explicitly_unhealthy=$(docker ps --filter \"label=spectra.managed=true\" --filter \"health=unhealthy\" --format \"{{.Names}}\" || true)\n if [ -n \"$explicitly_unhealthy\" ]; then\n echo \"Unhealthy containers found:\"\n echo \"$explicitly_unhealthy\"\n exit 1\n fi\n all_running=$(docker ps --filter \"label=spectra.managed=true\" --format \"{{.Names}}\" | wc -l)\n if [ \"$all_running\" -ge 10 ]; then\n echo \"All $all_running managed containers are running.\"\n echo \"$containers\"\n break\n fi\n echo \"Waiting... ($i/90) - $all_running containers running\"\n sleep 5\n done\n - name: Run e2e API live tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/e2e/test_api_live.py -v --tb=short --timeout=120\"\n - name: Run health endpoint integration test\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e APP_BASE_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/integration/test_api_health_live.py -v --tb=short --timeout=120\"\n - name: Run performance smoke tests\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test run --rm \\\n -e LOAD_TEST_APP_URL=http://app:5000 \\\n test-runner \\\n \"python -m pytest tests/performance/test_api_latency.py -v --tb=short --timeout=120\"\n - name: Collect logs on failure\n if: failure()\n run: |\n mkdir -p compose-logs\n for container in $(docker ps -aq --filter \"label=spectra.managed=true\"); do\n name=$(docker inspect --format '{{.Name}}' \"$container\" | sed 's/^\\///')\n docker logs \"$container\" > \"compose-logs/${name}.log\" 2>&1 || true\n done\n - name: Upload container logs as artifacts on failure\n if: failure()\n uses: actions/upload-artifact@v4\n with:\n name: compose-smoke-logs\n path: compose-logs/\n - name: Stop test stack\n if: always()\n run: |\n docker compose -f docker/compose.yaml --profile app --profile targets --profile test down -v --remove-orphans\n"}}}}