Files
Agent-System/internal/config/compose_flag_declaration_test.go
T
weichenandCursor 8b84ee4ecf chore(config): declare WORKFLOW_SCOPE_MODE with a strict default
The flag reaches all three compose app services and the sysadmin catalog, and unknown values stay on the existing hard block.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 09:26:03 +00:00

121 lines
4.2 KiB
Go

package config_test
import (
"os"
"path/filepath"
"regexp"
"strings"
"testing"
)
var composeFilesForFlagCheck = []string{
"docker-compose.dev.yml",
"docker-compose.test.yml",
"docker-compose.main.yml",
}
func readComposeFile(t *testing.T, name string) string {
t.Helper()
root := composeRepoRoot(t)
raw, err := os.ReadFile(filepath.Join(root, name))
if err != nil {
t.Fatalf("%s: %v", name, err)
}
return string(raw)
}
// serviceBlockText extracts one top-level compose service block's raw YAML text.
func serviceBlockText(t *testing.T, composeYAML, serviceName string) string {
t.Helper()
marker := "\n " + serviceName + ":\n"
idx := strings.Index(composeYAML, marker)
if idx < 0 {
t.Fatalf("service %q not found", serviceName)
}
rest := composeYAML[idx+1:]
next := regexp.MustCompile(`(?m)^ [a-zA-Z0-9_-]+:\s*$`)
locs := next.FindAllStringIndex(rest, -1)
if len(locs) >= 2 {
return rest[:locs[1][0]]
}
return rest
}
// E-3: MULTI_INTENT_PLAN_TIER and U9-U12 must be declared (legacy/false) in all
// three environments' app service so operator-set env vars actually reach the
// container. Values must never change from legacy/false in this test.
func TestComposeAppDeclaresMultiIntentPlanTierAndExpansionFlags(t *testing.T) {
wantKeys := []string{
"MULTI_INTENT_U9_SEGMENT:",
"MULTI_INTENT_U10_MUTATE:",
"MULTI_INTENT_U11_DOCGOV:",
"MULTI_INTENT_U12_RUN_CONTROL:",
}
for _, name := range composeFilesForFlagCheck {
block := serviceBlockText(t, readComposeFile(t, name), "app")
if !strings.Contains(block, "MULTI_INTENT_PLAN_TIER: ${MULTI_INTENT_PLAN_TIER:-legacy}") {
t.Errorf("%s: app service must declare MULTI_INTENT_PLAN_TIER with legacy default", name)
}
for _, key := range wantKeys {
if !strings.Contains(block, key) {
t.Errorf("%s: app service missing %s declaration", name, key)
}
}
}
}
// A-4: SEMANTIC_SUMMARY_SHADOW / PI_CHANGE_REPORT_NARRATIVE must be declared in
// all three environments (test/main were missing before Wave 2).
func TestComposeAppDeclaresSemanticSummaryAndNarrativeShadowFlags(t *testing.T) {
for _, name := range composeFilesForFlagCheck {
block := serviceBlockText(t, readComposeFile(t, name), "app")
for _, key := range []string{"SEMANTIC_SUMMARY_SHADOW:", "PI_CHANGE_REPORT_NARRATIVE:"} {
if !strings.Contains(block, key) {
t.Errorf("%s: app service missing %s declaration", name, key)
}
}
}
}
func TestComposeAppDeclaresWorkflowScopeMode(t *testing.T) {
for _, name := range composeFilesForFlagCheck {
block := serviceBlockText(t, readComposeFile(t, name), "app")
if !strings.Contains(block, "WORKFLOW_SCOPE_MODE: ${WORKFLOW_SCOPE_MODE:-strict}") {
t.Errorf("%s: app service must declare WORKFLOW_SCOPE_MODE with strict default", name)
}
}
}
// E-6: main must explicitly disable demo-user seeding at the compose layer
// (defense in depth; internal/auth/bootstrap.go already gates on cfg.Env=="main").
func TestComposeMainSeedDemoUsersExplicitFalse(t *testing.T) {
block := serviceBlockText(t, readComposeFile(t, "docker-compose.main.yml"), "app")
if !strings.Contains(block, `SEED_DEMO_USERS: "false"`) {
t.Fatalf("docker-compose.main.yml: app service must declare SEED_DEMO_USERS: \"false\"")
}
}
// E-4: CURSOR_RUNNER_URL has zero Go readers repo-wide; neither it nor the
// cursor-agent placeholder service should exist in any environment.
func TestComposeNoDeadCursorRunnerConfig(t *testing.T) {
for _, name := range composeFilesForFlagCheck {
text := readComposeFile(t, name)
if strings.Contains(text, "CURSOR_RUNNER_URL") {
t.Errorf("%s: dead CURSOR_RUNNER_URL must stay removed (E-4)", name)
}
if strings.Contains(text, "\n cursor-agent:\n") {
t.Errorf("%s: dead cursor-agent placeholder service must stay removed (E-4)", name)
}
}
}
// X-1: SEMANTIC_FALLBACK_ENABLED has zero Go readers repo-wide and no design
// doc describing intended semantics; Wave 5 decision = delete, not re-declare.
func TestComposeNoDeadSemanticFallbackConfig(t *testing.T) {
for _, name := range composeFilesForFlagCheck {
if strings.Contains(readComposeFile(t, name), "SEMANTIC_FALLBACK_ENABLED") {
t.Errorf("%s: dead SEMANTIC_FALLBACK_ENABLED must stay removed (Wave5 X-1)", name)
}
}
}