Coverage for gco_mcp / feature_flags.py: 100.00%
21 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-09-14 22:07 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-09-14 22:07 +0000
1"""Feature-flag evaluation for the GCO MCP server.
3Convention: a flag is enabled if and only if (a) the umbrella flag
4GCO_ENABLE_ALL_TOOLS is set to "true", OR (b) the case-insensitive,
5whitespace-stripped value of os.environ.get(<flag>, "") equals the
6literal "true". Anything else (unset, empty, "false", "0", "yes", "1",
7"True\n" without strip, ...) is disabled.
9The umbrella flag is mutually inclusive — setting GCO_ENABLE_ALL_TOOLS=true
10overrides per-flag values, even per-flag values explicitly set to "false".
11"""
13import os
15# Known flag constants. Tool modules import these by name.
16FLAG_ALL_TOOLS = "GCO_ENABLE_ALL_TOOLS"
17FLAG_CAPACITY_PURCHASE = "GCO_ENABLE_CAPACITY_PURCHASE"
18FLAG_MODEL_UPLOAD = "GCO_ENABLE_MODEL_UPLOAD"
19FLAG_IMAGE_PUBLISH = "GCO_ENABLE_IMAGE_PUBLISH"
20FLAG_INFRASTRUCTURE_DEPLOY = "GCO_ENABLE_INFRASTRUCTURE_DEPLOY"
21FLAG_INFRASTRUCTURE_DESTROY = "GCO_ENABLE_INFRASTRUCTURE_DESTROY"
22FLAG_DESTRUCTIVE_OPERATIONS = "GCO_ENABLE_DESTRUCTIVE_OPERATIONS"
23FLAG_MISSION = "GCO_ENABLE_MISSION"
24# Read-only-but-sensitive metric readers: local-filesystem reads and per-call
25# LLM scoring are default-off for security / cost reasons even though they
26# never mutate AWS state. They are full members of the registry like any
27# other per-tool flag.
28FLAG_LOCAL_METRICS = "GCO_ENABLE_LOCAL_METRICS"
29# Reads from or writes to the MCP host and can upload data to S3.
30FLAG_LOCAL_STORAGE_SYNC = "GCO_ENABLE_LOCAL_STORAGE_SYNC"
31FLAG_SEMANTIC_PROGRESS = "GCO_ENABLE_SEMANTIC_PROGRESS"
32# Writes to the deployment configuration (cdk.json) on the MCP host —
33# validated, atomic, and audited via the managed-config engine, but still a
34# local-file mutation an agent could chain into a deploy, so default-off.
35FLAG_CONFIG_MANAGEMENT = "GCO_ENABLE_CONFIG_MANAGEMENT"
36# Swarm supervision: one orchestrator Mission session spawning and driving
37# concurrent child Mission sessions. Default-off because it multiplies the
38# blast radius of whatever tool flags are already enabled (N children acting
39# concurrently) and because loop-spawning-loops deserves an explicit opt-in.
40FLAG_SWARM = "GCO_ENABLE_SWARM"
42# Per-tool flags. The umbrella is intentionally not in this tuple — callers
43# iterating ALL_FLAGS for "what gates this tool?" lookups should not see
44# the umbrella, only the per-tool flags.
45ALL_FLAGS = (
46 FLAG_CAPACITY_PURCHASE,
47 FLAG_MODEL_UPLOAD,
48 FLAG_IMAGE_PUBLISH,
49 FLAG_INFRASTRUCTURE_DEPLOY,
50 FLAG_INFRASTRUCTURE_DESTROY,
51 FLAG_DESTRUCTIVE_OPERATIONS,
52 FLAG_MISSION,
53 FLAG_LOCAL_METRICS,
54 FLAG_LOCAL_STORAGE_SYNC,
55 FLAG_SEMANTIC_PROGRESS,
56 FLAG_CONFIG_MANAGEMENT,
57 FLAG_SWARM,
58)
61def _raw(flag_name: str) -> bool:
62 """Return True iff the env var equals literal "true" (case-insensitive, stripped)."""
63 return os.environ.get(flag_name, "").strip().lower() == "true"
66def is_enabled(flag_name: str) -> bool:
67 """Return True iff the umbrella flag is set OR the named flag is set."""
68 return _raw(FLAG_ALL_TOOLS) or _raw(flag_name)
71def all_tools_enabled() -> bool:
72 """Return True iff GCO_ENABLE_ALL_TOOLS is set. Used by emit_startup_log."""
73 return _raw(FLAG_ALL_TOOLS)