package config_test import ( "fmt" "os" "path/filepath" "strings" "testing" "iop/packages/go/config" ) // validWorkspaceYAML is a baseline valid workspace catalog YAML used by // multiple sub-tests. It uses a single node with one workspace defining read // and list operations with bounded limits and a safe environment allowlist. const validWorkspaceYAML = ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" nodes: - id: "node-ws-01" alias: "mac-node" token: "token-ws-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-project-root" platform: "darwin" root: "/Users/operator/projects/iop-workspace" operations: - "read" - "list" max_read_bytes: 1048576 max_output_bytes: 4194304 environment_allowlist: - "IOP_ENV" ` // validWorkspaceWithCommandsYAML is a valid workspace catalog with command // operations and command templates. const validWorkspaceWithCommandsYAML = ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" nodes: - id: "node-ws-cmd" alias: "mac-node-cmd" token: "token-ws-cmd" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-cmd-workspace" platform: "darwin" root: "/Users/operator/projects/cmd-workspace" operations: - "read" - "list" - "write" - "delete" - "command" commands: - id: "list-files" executable: "/usr/bin/find" args: - "/Users/operator/projects/cmd-workspace" - "-name" - "*.go" - id: "read-file" executable: "/usr/bin/cat" args: [] max_read_bytes: 2097152 max_write_bytes: 1048576 max_output_bytes: 8388608 max_command_timeout_ms: 30000 environment_allowlist: - "PATH" - "HOME" ` // TestLoadEdgeWorkspaceCatalog verifies that valid workspace catalogs decode, // normalize, and survive LoadEdge alongside ordinary node definitions. func TestLoadEdgeWorkspaceCatalog(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") t.Run("single workspace with read/list operations loads", func(t *testing.T) { if err := os.WriteFile(f, []byte(validWorkspaceYAML), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.Nodes) != 1 { t.Fatalf("expected 1 node, got %d", len(cfg.Nodes)) } node := cfg.Nodes[0] if len(node.Workspaces) != 1 { t.Fatalf("expected 1 workspace, got %d", len(node.Workspaces)) } ws := node.Workspaces[0] if ws.Ref != "ws-project-root" { t.Errorf("ref = %q, want ws-project-root", ws.Ref) } if ws.Platform != "darwin" { t.Errorf("platform = %q, want darwin", ws.Platform) } if ws.Root != "/Users/operator/projects/iop-workspace" { t.Errorf("root = %q, want /Users/operator/projects/iop-workspace", ws.Root) } if len(ws.Operations) != 2 { t.Fatalf("expected 2 operations, got %d", len(ws.Operations)) } if ws.Operations[0] != config.WorkspaceOpRead { t.Errorf("operations[0] = %q, want read", ws.Operations[0]) } if ws.Operations[1] != config.WorkspaceOpList { t.Errorf("operations[1] = %q, want list", ws.Operations[1]) } if ws.MaxReadBytes != 1048576 { t.Errorf("max_read_bytes = %d, want 1048576", ws.MaxReadBytes) } if ws.MaxOutputBytes != 4194304 { t.Errorf("max_output_bytes = %d, want 4194304", ws.MaxOutputBytes) } if len(ws.EnvironmentAllowlist) != 1 || ws.EnvironmentAllowlist[0] != "IOP_ENV" { t.Errorf("environment_allowlist = %v, want [IOP_ENV]", ws.EnvironmentAllowlist) } }) t.Run("linux workspace loads", func(t *testing.T) { yaml := strings.ReplaceAll(validWorkspaceYAML, `platform: "darwin"`, `platform: "linux"`) yaml = strings.ReplaceAll(yaml, `/Users/operator/projects/iop-workspace`, `/home/operator/projects/iop-workspace`) if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("LoadEdge: %v", err) } workspace := cfg.Nodes[0].Workspaces[0] if workspace.Platform != config.WorkspacePlatformLinux { t.Fatalf("platform = %q, want %q", workspace.Platform, config.WorkspacePlatformLinux) } }) t.Run("workspace with command operations and templates loads", func(t *testing.T) { if err := os.WriteFile(f, []byte(validWorkspaceWithCommandsYAML), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } node := cfg.Nodes[0] ws := node.Workspaces[0] if ws.Ref != "ws-cmd-workspace" { t.Errorf("ref = %q, want ws-cmd-workspace", ws.Ref) } if len(ws.Operations) != 5 { t.Fatalf("expected 5 operations, got %d", len(ws.Operations)) } if len(ws.Commands) != 2 { t.Fatalf("expected 2 commands, got %d", len(ws.Commands)) } if ws.Commands[0].ID != "list-files" { t.Errorf("commands[0].id = %q, want list-files", ws.Commands[0].ID) } if ws.Commands[0].Executable != "/usr/bin/find" { t.Errorf("commands[0].executable = %q, want /usr/bin/find", ws.Commands[0].Executable) } if ws.Commands[1].ID != "read-file" { t.Errorf("commands[1].id = %q, want read-file", ws.Commands[1].ID) } if ws.MaxCommandTimeoutMS != 30000 { t.Errorf("max_command_timeout_ms = %d, want 30000", ws.MaxCommandTimeoutMS) } }) t.Run("empty workspaces is backward-compatible", func(t *testing.T) { yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" nodes: - id: "node-no-ws" alias: "no-workspace-node" token: "token-no-ws" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.Nodes[0].Workspaces) != 0 { t.Errorf("expected 0 workspaces, got %d", len(cfg.Nodes[0].Workspaces)) } }) t.Run("workspace ref is trimmed", func(t *testing.T) { yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" nodes: - id: "node-ws-trim" alias: "trim-node" token: "token-trim" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: " ws-trimmed " platform: "darwin" root: "/Users/operator/projects/trimmed" operations: - "read" max_read_bytes: 1024 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if cfg.Nodes[0].Workspaces[0].Ref != "ws-trimmed" { t.Errorf("ref = %q, want ws-trimmed (trimmed)", cfg.Nodes[0].Workspaces[0].Ref) } }) t.Run("workspace coexists with execution_presets", func(t *testing.T) { yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" - id: "model-plan" providers: prov-a: "model-plan" - id: "model-work" providers: prov-a: "model-work" - id: "model-review" providers: prov-a: "model-review" execution_presets: - id: "preset-fixed-light" selector: model: "model-plan" options: reasoning_effort: "high" allowed_modes: - "light" routes: light: stages: - role: "plan" model: "model-plan" options: reasoning_effort: "high" - role: "work" model: "model-work" - role: "review" model: "model-review" options: reasoning_effort: "high" single_request: workspace_ref: "ws-single-request-ref" limits: wall_clock_ms: 1800000 timeout_ms: 600000 max_tool_iterations: 64 max_output_bytes: 16777216 stages: plan: model: "model-plan" options: reasoning_effort: "high" work: model: "model-work" review: model: "model-review" options: reasoning_effort: "high" nodes: - id: "node-ws-and-preset" alias: "full-node" token: "token-full" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a", "model-plan", "model-work", "model-review"] capacity: 2 workspaces: - ref: "ws-operator-root" platform: "darwin" root: "/Users/operator/projects/iop" operations: - "read" - "list" max_read_bytes: 1048576 max_output_bytes: 4194304 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.Nodes) != 1 { t.Fatalf("expected 1 node, got %d", len(cfg.Nodes)) } if len(cfg.Nodes[0].Workspaces) != 1 { t.Fatalf("expected 1 workspace, got %d", len(cfg.Nodes[0].Workspaces)) } if len(cfg.ExecutionPresets) != 1 { t.Fatalf("expected 1 preset, got %d", len(cfg.ExecutionPresets)) } }) } // TestLoadEdgeWorkspaceCatalogRejectsInvalid verifies that invalid workspace // catalogs fail closed with descriptive errors covering all validation // dimensions: ref, platform, root, operations, commands, environment, and // numeric limits. func TestLoadEdgeWorkspaceCatalogRejectsInvalid(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") baseNode := ` models: - id: "model-a" providers: prov-a: "model-a" nodes:` t.Run("empty ref rejected", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-empty-ref" alias: "empty-ref-node" token: "token-empty-ref" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: " " platform: "darwin" root: "/Users/operator/projects/test" operations: - "read" max_read_bytes: 1024 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for empty ref") } if !strings.Contains(err.Error(), "ref must not be empty") { t.Fatalf("expected ref error, got %v", err) } }) t.Run("duplicate ref within node rejected", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-dup-ref" alias: "dup-ref-node" token: "token-dup-ref" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-dup" platform: "darwin" root: "/Users/operator/projects/test1" operations: - "read" max_read_bytes: 1024 - ref: "ws-dup" platform: "darwin" root: "/Users/operator/projects/test2" operations: - "list" max_read_bytes: 2048 max_output_bytes: 2048 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for duplicate ref within node") } if !strings.Contains(err.Error(), "duplicate ref") { t.Fatalf("expected duplicate ref error, got %v", err) } }) t.Run("duplicate ref across nodes rejected", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-dup-a" alias: "dup-a-node" token: "token-dup-a" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-global-dup" platform: "darwin" root: "/Users/operator/projects/test-a" operations: - "read" max_read_bytes: 1024 - id: "node-ws-dup-b" alias: "dup-b-node" token: "token-dup-b" providers: - id: "prov-b" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-global-dup" platform: "darwin" root: "/Users/operator/projects/test-b" operations: - "list" max_read_bytes: 2048 max_output_bytes: 2048 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for duplicate ref across nodes") } if !strings.Contains(err.Error(), "duplicate workspace ref") { t.Fatalf("expected cross-node duplicate error, got %v", err) } }) for _, platform := range []string{"windows", "plan9"} { t.Run("unsupported platform "+platform+" rejected", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-bad-platform" alias: "bad-platform-node" token: "token-bad-platform" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-unsupported" platform: "` + platform + `" root: "/home/operator/projects/test" operations: - "read" max_read_bytes: 1024 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatalf("expected error for unsupported platform %q", platform) } if !strings.Contains(err.Error(), "unsupported workspace platform") { t.Fatalf("expected unsupported platform error, got %v", err) } }) } t.Run("relative root path rejected", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-rel-root" alias: "rel-root-node" token: "token-rel-root" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-rel-root" platform: "darwin" root: "relative/path" operations: - "read" max_read_bytes: 1024 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for relative root") } if !strings.Contains(err.Error(), "absolute path") { t.Fatalf("expected absolute path error, got %v", err) } }) t.Run("root \"/\" rejected", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-root-slash" alias: "root-slash-node" token: "token-root-slash" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-root-slash" platform: "darwin" root: "/" operations: - "read" max_read_bytes: 1024 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for root = /") } if !strings.Contains(err.Error(), `must not be "/"`) { t.Fatalf("expected root / error, got %v", err) } }) t.Run("unclean root path rejected", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-unclean" alias: "unclean-node" token: "token-unclean" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-unclean" platform: "darwin" root: "/Users/operator/projects/../projects/test" operations: - "read" max_read_bytes: 1024 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for unclean root") } if !strings.Contains(err.Error(), "must be clean") { t.Fatalf("expected clean path error, got %v", err) } }) t.Run("empty operations rejected", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-empty-ops" alias: "empty-ops-node" token: "token-empty-ops" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-empty-ops" platform: "darwin" root: "/Users/operator/projects/test" operations: [] max_read_bytes: 1024 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for empty operations") } if !strings.Contains(err.Error(), "operations must not be empty") { t.Fatalf("expected empty operations error, got %v", err) } }) t.Run("unknown operation rejected", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-bad-op" alias: "bad-op-node" token: "token-bad-op" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-bad-op" platform: "darwin" root: "/Users/operator/projects/test" operations: - "read" - "execute" max_read_bytes: 1024 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for unknown operation") } if !strings.Contains(err.Error(), "unknown operation") { t.Fatalf("expected unknown operation error, got %v", err) } }) t.Run("duplicate operation rejected", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-dup-op" alias: "dup-op-node" token: "token-dup-op" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-dup-op" platform: "darwin" root: "/Users/operator/projects/test" operations: - "read" - "read" max_read_bytes: 1024 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for duplicate operation") } if !strings.Contains(err.Error(), "duplicate operation") { t.Fatalf("expected duplicate operation error, got %v", err) } }) t.Run("commands present without command operation rejected", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-cmd-without-op" alias: "cmd-without-op-node" token: "token-cmd-without-op" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-cmd-without-op" platform: "darwin" root: "/Users/operator/projects/test" operations: - "read" - "list" commands: - id: "list-files" executable: "/usr/bin/find" args: [] max_read_bytes: 1024 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for commands without command operation") } if !strings.Contains(err.Error(), "commands must be empty") { t.Fatalf("expected commands must be empty error, got %v", err) } }) t.Run("command operation without commands rejected", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-cmd-op-no-cmds" alias: "cmd-op-no-cmds-node" token: "token-cmd-op-no-cmds" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-cmd-op-no-cmds" platform: "darwin" root: "/Users/operator/projects/test" operations: - "read" - "command" max_read_bytes: 1024 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for command operation without commands") } if !strings.Contains(err.Error(), "commands must not be empty") { t.Fatalf("expected commands must not be empty error, got %v", err) } }) t.Run("duplicate command id rejected", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-dup-cmd" alias: "dup-cmd-node" token: "token-dup-cmd" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-dup-cmd" platform: "darwin" root: "/Users/operator/projects/test" operations: - "read" - "command" commands: - id: "list-files" executable: "/usr/bin/find" args: [] - id: "list-files" executable: "/usr/bin/ls" args: [] max_read_bytes: 1024 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for duplicate command id") } if !strings.Contains(err.Error(), "duplicate command id") { t.Fatalf("expected duplicate command id error, got %v", err) } }) t.Run("non-absolute command executable rejected", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-rel-exe" alias: "rel-exe-node" token: "token-rel-exe" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-rel-exe" platform: "darwin" root: "/Users/operator/projects/test" operations: - "read" - "command" commands: - id: "list-files" executable: "relative/path/to/cmd" args: [] max_read_bytes: 1024 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for relative command executable") } if !strings.Contains(err.Error(), "absolute path") { t.Fatalf("expected absolute path error for executable, got %v", err) } }) t.Run("invalid environment variable name rejected", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-bad-env" alias: "bad-env-node" token: "token-bad-env" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-bad-env" platform: "darwin" root: "/Users/operator/projects/test" operations: - "read" max_read_bytes: 1024 environment_allowlist: - "1INVALID" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for invalid env name") } if !strings.Contains(err.Error(), "portable environment variable name") { t.Fatalf("expected portable env name error, got %v", err) } }) t.Run("duplicate environment variable name rejected", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-dup-env" alias: "dup-env-node" token: "token-dup-env" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-dup-env" platform: "darwin" root: "/Users/operator/projects/test" operations: - "read" max_read_bytes: 1024 environment_allowlist: - "PATH" - "PATH" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for duplicate env name") } if !strings.Contains(err.Error(), "duplicate name") { t.Fatalf("expected duplicate name error, got %v", err) } }) t.Run("max_read_bytes over 1GiB rejected", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-over-read" alias: "over-read-node" token: "token-over-read" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-over-read" platform: "darwin" root: "/Users/operator/projects/test" operations: - "read" max_read_bytes: 1073741825 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for over-limit max_read_bytes") } if !strings.Contains(err.Error(), "max_read_bytes must be between") { t.Fatalf("expected max_read_bytes range error, got %v", err) } }) t.Run("max_command_timeout_ms over 1 hour rejected", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-over-timeout" alias: "over-timeout-node" token: "token-over-timeout" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-over-timeout" platform: "darwin" root: "/Users/operator/projects/test" operations: - "read" - "command" commands: - id: "list-files" executable: "/usr/bin/find" args: [] max_command_timeout_ms: 3600001 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for over-limit timeout") } if !strings.Contains(err.Error(), "max_command_timeout_ms must be between") { t.Fatalf("expected timeout range error, got %v", err) } }) for _, tc := range []struct { name string operations string commands string limits string want string }{ { name: "read without max_read_bytes rejected", operations: " - \"read\"\n", want: "max_read_bytes must be positive", }, { name: "list without max_output_bytes rejected", operations: " - \"list\"\n", want: "max_output_bytes must be positive", }, { name: "write without max_write_bytes rejected", operations: " - \"write\"\n", want: "max_write_bytes must be positive", }, { name: "command without max_output_bytes rejected", operations: " - \"command\"\n", commands: " commands:\n - id: \"list-files\"\n executable: \"/usr/bin/find\"\n args: []\n", limits: " max_command_timeout_ms: 1000\n", want: "max_output_bytes must be positive", }, { name: "command without max_command_timeout_ms rejected", operations: " - \"command\"\n", commands: " commands:\n - id: \"list-files\"\n executable: \"/usr/bin/find\"\n args: []\n", limits: " max_output_bytes: 1024\n", want: "max_command_timeout_ms must be positive", }, { name: "negative max_read_bytes rejected", operations: " - \"read\"\n", limits: " max_read_bytes: -1\n", want: "max_read_bytes must be between", }, { name: "negative max_write_bytes rejected", operations: " - \"write\"\n", limits: " max_write_bytes: -1\n", want: "max_write_bytes must be between", }, { name: "negative max_output_bytes rejected", operations: " - \"list\"\n", limits: " max_output_bytes: -1\n", want: "max_output_bytes must be between", }, { name: "negative max_command_timeout_ms rejected", operations: " - \"command\"\n", commands: " commands:\n - id: \"list-files\"\n executable: \"/usr/bin/find\"\n args: []\n", limits: " max_output_bytes: 1024\n max_command_timeout_ms: -1\n", want: "max_command_timeout_ms must be between", }, } { t.Run(tc.name, func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-effective-bound" alias: "effective-bound-node" token: "token-effective-bound" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-effective-bound" platform: "darwin" root: "/Users/operator/projects/test" operations: ` + tc.operations + tc.commands + tc.limits if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected effective bound validation error") } if !strings.Contains(err.Error(), tc.want) { t.Fatalf("expected error containing %q, got %v", tc.want, err) } }) } t.Run("boundary limit values load", func(t *testing.T) { yaml := baseNode + ` - id: "node-ws-boundary" alias: "boundary-node" token: "token-boundary" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-boundary" platform: "darwin" root: "/Users/operator/projects/test" operations: - "read" - "write" - "delete" - "command" commands: - id: "cmd-boundary" executable: "/usr/bin/cat" args: [] max_read_bytes: 1 max_write_bytes: 1073741824 max_output_bytes: 1 max_command_timeout_ms: 1 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } ws := cfg.Nodes[0].Workspaces[0] if ws.MaxReadBytes != 1 { t.Errorf("max_read_bytes = %d, want 1", ws.MaxReadBytes) } if ws.MaxWriteBytes != 1073741824 { t.Errorf("max_write_bytes = %d, want 1073741824", ws.MaxWriteBytes) } if ws.MaxOutputBytes != 1 { t.Errorf("max_output_bytes = %d, want 1", ws.MaxOutputBytes) } if ws.MaxCommandTimeoutMS != 1 { t.Errorf("max_command_timeout_ms = %d, want 1", ws.MaxCommandTimeoutMS) } }) t.Run("boundary limit values at max load", func(t *testing.T) { yaml := fmt.Sprintf(baseNode+` - id: "node-ws-boundary-max" alias: "boundary-max-node" token: "token-boundary-max" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 workspaces: - ref: "ws-boundary-max" platform: "darwin" root: "/Users/operator/projects/test" operations: - "read" - "write" - "delete" - "command" commands: - id: "cmd-boundary-max" executable: "/usr/bin/cat" args: [] max_read_bytes: %d max_write_bytes: %d max_output_bytes: %d max_command_timeout_ms: 3600000 `, 1073741824, 1073741824, 1073741824) if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } ws := cfg.Nodes[0].Workspaces[0] if ws.MaxReadBytes != 1073741824 { t.Errorf("max_read_bytes = %d, want 1073741824", ws.MaxReadBytes) } if ws.MaxWriteBytes != 1073741824 { t.Errorf("max_write_bytes = %d, want 1073741824", ws.MaxWriteBytes) } if ws.MaxOutputBytes != 1073741824 { t.Errorf("max_output_bytes = %d, want 1073741824", ws.MaxOutputBytes) } if ws.MaxCommandTimeoutMS != 3600000 { t.Errorf("max_command_timeout_ms = %d, want 3600000", ws.MaxCommandTimeoutMS) } }) }