package openai import ( "encoding/json" "os" "os/exec" "path/filepath" "reflect" "strings" "testing" "iop/packages/go/config" ) func TestWorkspaceToolBindingContract(t *testing.T) { structured := workspaceAlternative("structured", "write_file", false, true) command := workspaceAlternative("command", "run_workspace", true, false) openAITools := []any{openAIChatTool("write_file", structuredSchema()), unrelatedTool()} anthropicTools := []any{anthropicWorkspaceTool("write_file", structuredSchema()), unrelatedTool()} t.Run("normalizes actual OpenAI and Anthropic definitions", func(t *testing.T) { openAIBinding, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{structured}, openAITools) if err != nil { t.Fatalf("compile OpenAI tool: %v", err) } anthropicBinding, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{structured}, anthropicTools) if err != nil { t.Fatalf("compile Anthropic tool: %v", err) } if openAIBinding.alternativeName != "structured" || anthropicBinding.alternativeName != "structured" { t.Fatalf("unexpected selected alternatives: %q, %q", openAIBinding.alternativeName, anthropicBinding.alternativeName) } if openAIBinding.fingerprint != anthropicBinding.fingerprint { t.Fatalf("normalized endpoint shapes must fingerprint identically: %s != %s", openAIBinding.fingerprint, anthropicBinding.fingerprint) } }) t.Run("normalizes native decoded Anthropic tool", func(t *testing.T) { rawSchema, err := json.Marshal(structuredSchema()) if err != nil { t.Fatalf("marshal native schema: %v", err) } nativeBinding, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{structured}, []anthropicTool{ anthropicTool{Name: "write_file", Description: "workspace tool", InputSchema: rawSchema}, }) if err != nil { t.Fatalf("compile native Anthropic tool: %v", err) } openAIBinding := mustBinding(t, structured, []any{openAIChatTool("write_file", structuredSchema())}) if nativeBinding.fingerprint != openAIBinding.fingerprint { t.Fatalf("native Anthropic fingerprint = %s, want %s", nativeBinding.fingerprint, openAIBinding.fingerprint) } }) t.Run("rejects unsupported command placeholders and missing write content", func(t *testing.T) { for name, argv := range map[string][]any{ "missing content": {"write", "{path}"}, "duplicate content": {"write", "{path}", "{content}", "{content}"}, "embedded placeholder": {"write", "--path={path}", "{content}"}, "unknown placeholder": {"write", "{path}", "{unsupported}", "{content}"}, "missing path placeholder": {"write", "{content}"}, } { t.Run(name, func(t *testing.T) { invalid := workspaceAlternative("invalid-command", "run_workspace", true, true) invalid.Operations["write"] = config.ExecutionWorkspaceOperation{ ToolName: "run_workspace", SchemaMatcher: map[string]any{"type": "object"}, ArgumentMap: map[string]any{"path": "path", "content": "content", "command": "command", "argv": argv}, ResultMatcher: successMatcher(), CreatesParents: true, } if _, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{invalid}, []any{openAIChatTool("run_workspace", commandSchema())}); err == nil { t.Fatal("invalid command template unexpectedly compiled") } }) } }) t.Run("uses configured order and rejects name heuristics", func(t *testing.T) { fallback, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{command, structured}, openAITools) if err != nil { t.Fatalf("compile fallback: %v", err) } if fallback.alternativeName != "structured" { t.Fatalf("expected configured second alternative, got %q", fallback.alternativeName) } if _, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{structured}, []any{unrelatedTool()}); err == nil { t.Fatal("unrelated get_weather tool must not bind by lexical role inference") } }) t.Run("rejects missing tools, schema mismatch, and incomplete parent contract", func(t *testing.T) { missing := workspaceAlternative("missing", "absent_tool", true, true) if _, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{missing}, openAITools); err == nil { t.Fatal("missing configured tool unexpectedly bound") } mismatched := workspaceAlternative("mismatched", "write_file", true, true) mismatched.Operations["write"] = config.ExecutionWorkspaceOperation{ ToolName: "write_file", SchemaMatcher: map[string]any{"type": "object", "properties": map[string]any{"bytes": map[string]any{"type": "number"}}}, ArgumentMap: map[string]any{"path": "path", "content": "content"}, ResultMatcher: successMatcher(), CreatesParents: true, } if _, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{mismatched}, openAITools); err == nil { t.Fatal("schema-mismatched configured tool unexpectedly bound") } noPrepare := workspaceAlternative("no-prepare", "write_file", false, false) delete(noPrepare.Operations, "prepare") if _, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{noPrepare}, openAITools); err == nil { t.Fatal("write without parent capability or prepare unexpectedly bound") } }) t.Run("copies full contract into a stable fingerprint", func(t *testing.T) { binding, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{structured}, openAITools) if err != nil { t.Fatalf("compile binding: %v", err) } before := binding.fingerprint structured.Operations["write"] = config.ExecutionWorkspaceOperation{ToolName: "changed"} if binding.fingerprint != before || binding.operation(opKindWrite).toolName != "write_file" { t.Fatal("binding retained mutable config state") } openAITools[0].(map[string]any)["function"].(map[string]any)["parameters"].(map[string]any)["properties"].(map[string]any)["path"] = map[string]any{"type": "number"} if binding.operation(opKindWrite).normalizedSchema.properties["path"].(map[string]any)["type"] != "string" { t.Fatal("binding retained mutable request tool schema") } withDifferentReceipt := workspaceAlternative("structured", "write_file", false, true) withDifferentReceipt.Operations["write"] = config.ExecutionWorkspaceOperation{ ToolName: "write_file", SchemaMatcher: map[string]any{"type": "object"}, ArgumentMap: map[string]any{"path": "path", "content": "content"}, ResultMatcher: map[string]any{"status": "success", "result": map[string]any{"saved": true}}, CreatesParents: true, } changed, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{withDifferentReceipt}, openAITools) if err != nil { t.Fatalf("compile changed receipt binding: %v", err) } if before == changed.fingerprint { t.Fatal("fingerprint omitted configured result contract") } }) } func TestWorkspaceContainmentGuard(t *testing.T) { writeCall := func(path string) normalizedToolCall { return normalizedToolCall{ID: "guard-call", Name: "write_file", Arguments: map[string]any{"path": path, "content": "x"}} } t.Run("parent-capable write admits fresh nested parents", func(t *testing.T) { binding := mustBinding(t, workspaceAlternative("parents", "write_file", false, true), []any{openAIChatTool("write_file", structuredSchema())}) payload, err := encodeWorkspaceCall(binding, opKindWrite, writeCall(".iop/job/request-1/plan.md")) if err != nil { t.Fatalf("encode workspace call: %v", err) } if err := evaluateContainmentGuard(t.TempDir(), payload.containmentGuard); err != nil { t.Fatalf("parent-capable guard rejected a fresh nested path: %v", err) } }) t.Run("write without parent capability requires immediate parent", func(t *testing.T) { binding := mustBinding(t, workspaceAlternative("prepare-required", "write_file", false, false), []any{openAIChatTool("write_file", structuredSchema())}) payload, err := encodeWorkspaceCall(binding, opKindWrite, writeCall(".iop/job/request-2/plan.md")) if err != nil { t.Fatalf("encode workspace call: %v", err) } if err := evaluateContainmentGuard(t.TempDir(), payload.containmentGuard); err == nil { t.Fatal("non-parent-capable guard accepted a missing immediate parent") } }) t.Run("root workspace admits existing relative target", func(t *testing.T) { binding := mustBinding(t, workspaceAlternative("parents", "write_file", false, true), []any{openAIChatTool("write_file", structuredSchema())}) payload, err := encodeWorkspaceCall(binding, opKindWrite, writeCall("tmp")) if err != nil { t.Fatalf("encode workspace call: %v", err) } if err := evaluateContainmentGuard("/", payload.containmentGuard); err != nil { t.Fatalf("root workspace guard rejected existing relative target: %v", err) } }) t.Run("root workspace admits non-parent-capable target with existing immediate parent", func(t *testing.T) { binding := mustBinding(t, workspaceAlternative("prepare-required", "write_file", false, false), []any{openAIChatTool("write_file", structuredSchema())}) payload, err := encodeWorkspaceCall(binding, opKindWrite, writeCall("tmp/iop_root_test_file.txt")) if err != nil { t.Fatalf("encode workspace call: %v", err) } if err := evaluateContainmentGuard("/", payload.containmentGuard); err != nil { t.Fatalf("root workspace guard rejected non-parent-capable target with existing parent: %v", err) } }) for name, setup := range map[string]func(t *testing.T, root, outside string){ "final symlink": func(t *testing.T, root, outside string) { t.Helper() if err := os.MkdirAll(filepath.Join(root, ".iop", "job", "request-3"), 0o755); err != nil { t.Fatalf("create workspace path: %v", err) } if err := os.WriteFile(filepath.Join(outside, "target.md"), []byte("outside"), 0o600); err != nil { t.Fatalf("create outside target: %v", err) } if err := os.Symlink(filepath.Join(outside, "target.md"), filepath.Join(root, ".iop", "job", "request-3", "plan.md")); err != nil { t.Fatalf("create final symlink: %v", err) } }, "ancestor symlink": func(t *testing.T, root, outside string) { t.Helper() if err := os.Symlink(outside, filepath.Join(root, ".iop")); err != nil { t.Fatalf("create ancestor symlink: %v", err) } }, } { t.Run(name+" escapes workspace", func(t *testing.T) { root := t.TempDir() outside := t.TempDir() setup(t, root, outside) binding := mustBinding(t, workspaceAlternative("parents", "write_file", false, true), []any{openAIChatTool("write_file", structuredSchema())}) payload, err := encodeWorkspaceCall(binding, opKindWrite, writeCall(".iop/job/request-3/plan.md")) if err != nil { t.Fatalf("encode workspace call: %v", err) } if err := evaluateContainmentGuard(root, payload.containmentGuard); err == nil { t.Fatal("symlink escape was accepted") } }) } } // evaluateContainmentGuard executes only the generated guard against a // temporary workspace fixture. It never invokes a caller workspace command. func evaluateContainmentGuard(root, guard string) error { cmd := exec.Command("sh", "-c", guard) cmd.Env = append(os.Environ(), "IOP_WORKSPACE_CWD="+root) return cmd.Run() } func TestWorkspaceCommandEncodingAndGuards(t *testing.T) { structured := workspaceAlternative("structured", "write_file", false, true) command := workspaceAlternative("command", "run_workspace", true, false) t.Run("structured payload preserves typed values and identities", func(t *testing.T) { binding := mustBinding(t, structured, []any{openAIChatTool("write_file", structuredSchema())}) content := map[string]any{"lines": []any{"first", 2, true}, "nested": map[string]any{"raw": "' $HOME"}} payload, err := encodeWorkspaceCall(binding, opKindWrite, normalizedToolCall{ ID: "public-1", ProviderCallID: "provider-1", Name: "write_file", Arguments: map[string]any{"path": ".iop/job/r1/plan.md", "content": content, "ignored": "must not pass"}, }) if err != nil { t.Fatalf("encode structured call: %v", err) } if payload.publicCallID != "public-1" || payload.providerCallID != "provider-1" { t.Fatalf("call identities lost: %#v", payload) } if !reflect.DeepEqual(payload.structuredArgs["content"], content) { t.Fatalf("structured content changed: %#v", payload.structuredArgs["content"]) } if _, present := payload.structuredArgs["ignored"]; present { t.Fatal("unmapped structured argument escaped the configured contract") } }) t.Run("command mapping has fixed positions and shell-safe output", func(t *testing.T) { binding := mustBinding(t, command, []any{openAIChatTool("run_workspace", commandSchema())}) call := normalizedToolCall{ID: "public-2", Name: "run_workspace", Arguments: map[string]any{"path": ".iop/job/r2/review.md", "content": "hello 'world'"}} first, err := encodeWorkspaceCall(binding, opKindWrite, call) if err != nil { t.Fatalf("encode command call: %v", err) } second, err := encodeWorkspaceCall(binding, opKindWrite, call) if err != nil || first.commandString != second.commandString { t.Fatalf("command encoding is not deterministic: %q / %q (%v)", first.commandString, second.commandString, err) } wantArgv := []string{"write", ".iop/job/r2/review.md", "hello 'world'"} if !reflect.DeepEqual(first.commandArgv, wantArgv) { t.Fatalf("command argv = %#v, want %#v", first.commandArgv, wantArgv) } if !strings.Contains(first.commandString, "'\\''") { t.Fatalf("command does not safely quote apostrophe: %q", first.commandString) } }) t.Run("no-escape guard is concrete and unsafe paths fail before caller execution", func(t *testing.T) { binding := mustBinding(t, structured, []any{openAIChatTool("write_file", structuredSchema())}) for _, path := range []string{"../escape", "/etc/passwd", ".iop/job/r3/../../escape", "bad;rm"} { if _, err := encodeWorkspaceCall(binding, opKindWrite, normalizedToolCall{ID: "public-3", Name: "write_file", Arguments: map[string]any{"path": path, "content": "x"}}); err == nil { t.Fatalf("unsafe path %q was accepted", path) } } payload, err := encodeWorkspaceCall(binding, opKindWrite, normalizedToolCall{ID: "public-4", Name: "write_file", Arguments: map[string]any{"path": ".iop/job/r4/plan.md", "content": "x"}}) if err != nil { t.Fatalf("encode safe path: %v", err) } for _, required := range []string{"IOP_WS_ROOT=", "IOP_WORKSPACE_CWD", "realpath -e", "IOP_WS_CANDIDATE=", "path escapes workspace root"} { if !strings.Contains(payload.containmentGuard, required) { t.Fatalf("guard missing %q: %s", required, payload.containmentGuard) } } if !strings.Contains(payload.containmentGuard, `IOP_WS_CANDIDATE="$IOP_WS_ROOT/.iop/job/r4/plan.md"`) { t.Fatalf("guard does not retain exact candidate path: %s", payload.containmentGuard) } }) } func TestWorkspaceBindingReceipts(t *testing.T) { binding := mustBinding(t, workspaceAlternative("structured", "write_file", false, true), []any{openAIChatTool("write_file", structuredSchema())}) payload, err := encodeWorkspaceCall(binding, opKindWrite, normalizedToolCall{ ID: "public-receipt", ProviderCallID: "provider-receipt", Name: "write_file", Arguments: map[string]any{"path": ".iop/job/r5/plan.md", "content": "plan"}, }) if err != nil { t.Fatalf("encode payload: %v", err) } t.Run("configured exact receipt accepts either issued identity", func(t *testing.T) { for _, id := range []string{"public-receipt", "provider-receipt"} { receipt := matchResultReceipt(binding, payload, workspaceResult{callID: id, status: "success", body: []byte(`{"written":true}`)}) if !receipt.matched || receipt.fingerprint != binding.fingerprint || receipt.path != payload.safePath { t.Fatalf("valid receipt did not correlate: %#v", receipt) } } }) for name, result := range map[string]workspaceResult{ "opaque": {callID: "public-receipt", status: "success"}, "error": {callID: "public-receipt", status: "error", body: []byte(`{"written":true}`)}, "embedded error": {callID: "public-receipt", status: "success", body: []byte(`{"written":true,"error":{"message":"nope"}}`)}, "trailing JSON": {callID: "public-receipt", status: "success", body: []byte(`{"written":true} {"error":"nope"}`)}, "wrong id": {callID: "other", status: "success", body: []byte(`{"written":true}`)}, "wrong body": {callID: "public-receipt", status: "success", body: []byte(`{"written":false}`)}, "arbitrary JSON": {callID: "public-receipt", status: "success", body: []byte(`{"anything":"else"}`)}, } { t.Run(name, func(t *testing.T) { if receipt := matchResultReceipt(binding, payload, result); receipt.matched { t.Fatalf("mismatched receipt was accepted: %#v", receipt) } }) } t.Run("rejects every issued payload mutation", func(t *testing.T) { mutations := map[string]func(*workspaceEncodedPayload){ "operation": func(p *workspaceEncodedPayload) { p.operation = opKindPrepare }, "path": func(p *workspaceEncodedPayload) { p.safePath = ".iop/job/r5/review.md" }, "arguments": func(p *workspaceEncodedPayload) { p.structuredArgs["content"] = "mutated" }, "guard": func(p *workspaceEncodedPayload) { p.containmentGuard = "mutated" }, } for name, mutate := range mutations { t.Run(name, func(t *testing.T) { copy := cloneWorkspacePayload(payload) mutate(copy) if receipt := matchResultReceipt(binding, copy, workspaceResult{callID: "public-receipt", status: "success", body: []byte(`{"written":true}`)}); receipt.matched { t.Fatalf("mutated payload unexpectedly matched: %#v", receipt) } }) } }) } func TestWorkspaceResultExactness(t *testing.T) { tests := []struct { name string result workspaceResult wantExact bool }{ { name: "empty success body is opaque", result: workspaceResult{status: "success", body: nil}, wantExact: false, }, { name: "whitespace success body is opaque", result: workspaceResult{status: "success", body: []byte(" \n\t ")}, wantExact: false, }, { name: "empty explicit error is exact", result: workspaceResult{status: "error", body: nil}, wantExact: true, }, { name: "non-empty matcher failure is exact", result: workspaceResult{status: "success", body: []byte(`{"written":false}`)}, wantExact: true, }, { name: "malformed json body is opaque", result: workspaceResult{status: "success", body: []byte(`not-json`)}, wantExact: false, }, { name: "trailing json body is opaque", result: workspaceResult{status: "success", body: []byte(`{"written":true} {"error":"nope"}`)}, wantExact: false, }, { name: "valid success receipt body is exact", result: workspaceResult{status: "success", body: []byte(`{"written":true}`)}, wantExact: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := workspaceResultIsExact(tt.result); got != tt.wantExact { t.Fatalf("workspaceResultIsExact() = %v, want %v", got, tt.wantExact) } }) } } func TestWorkspaceOperationMatrix(t *testing.T) { nativeSchema, err := json.Marshal(structuredSchema()) if err != nil { t.Fatalf("marshal native schema: %v", err) } for _, tc := range []struct { name string command bool tools any }{ {name: "structured", tools: []any{openAIChatTool("workspace", structuredSchema())}}, {name: "command", command: true, tools: []any{openAIChatTool("workspace", commandSchema())}}, {name: "native Anthropic", tools: []anthropicTool{{Name: "workspace", Description: "workspace tool", InputSchema: nativeSchema}}}, } { t.Run(tc.name, func(t *testing.T) { binding := mustBinding(t, fullWorkspaceAlternative(tc.name, "workspace", tc.command), tc.tools) for _, operation := range canonicalOperationOrder { args := map[string]any{"path": ".iop/job/r6/" + string(operation) + ".md"} if operation == opKindWrite { args["content"] = "content" } payload, err := encodeWorkspaceCall(binding, operation, normalizedToolCall{ID: "call-" + string(operation), Name: "workspace", Arguments: args}) if err != nil { t.Fatalf("encode %s: %v", operation, err) } if payload.operation != operation || payload.correlationDigest == "" { t.Fatalf("payload for %s is not sealed: %#v", operation, payload) } if receipt := matchResultReceipt(binding, payload, workspaceResult{callID: payload.publicCallID, status: "success", body: []byte(`{"written":true}`)}); !receipt.matched { t.Fatalf("valid %s receipt did not match: %#v", operation, receipt) } } }) } t.Run("ordered complete alternatives and missing tools", func(t *testing.T) { first := fullWorkspaceAlternative("first", "first_workspace", false) second := fullWorkspaceAlternative("second", "second_workspace", false) tools := []any{openAIChatTool("second_workspace", structuredSchema()), openAIChatTool("first_workspace", structuredSchema())} binding, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{second, first}, tools) if err != nil || binding.alternativeName != "second" { t.Fatalf("configured first complete alternative was not selected: binding=%#v err=%v", binding, err) } if _, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{first}, []any{openAIChatTool("first_workspace", structuredSchema()), unrelatedTool()}); err != nil { t.Fatalf("extra unrelated tool must not invalidate a complete alternative: %v", err) } if _, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{first}, []any{unrelatedTool()}); err == nil { t.Fatal("missing complete operation tool unexpectedly bound") } }) } func mustBinding(t *testing.T, alternative config.ExecutionWorkspaceToolAlternative, tools any) *workspaceBinding { t.Helper() binding, err := compileWorkspaceBinding([]config.ExecutionWorkspaceToolAlternative{alternative}, tools) if err != nil { t.Fatalf("compile binding: %v", err) } return binding } func workspaceAlternative(name, toolName string, command, createsParents bool) config.ExecutionWorkspaceToolAlternative { argumentMap := map[string]any{"path": "path", "content": "content"} prepareArgumentMap := map[string]any{"path": "path"} if command { argumentMap = map[string]any{"path": "path", "content": "content", "command": "command", "argv": []any{"write", "{path}", "{content}"}} prepareArgumentMap = map[string]any{"path": "path", "command": "command", "argv": []any{"mkdir", "{path}"}} } return config.ExecutionWorkspaceToolAlternative{ Name: name, Operations: map[string]config.ExecutionWorkspaceOperation{ "prepare": {ToolName: toolName, SchemaMatcher: map[string]any{"type": "object"}, ArgumentMap: prepareArgumentMap, ResultMatcher: successMatcher(), CreatesParents: true}, "write": {ToolName: toolName, SchemaMatcher: map[string]any{"type": "object"}, ArgumentMap: argumentMap, ResultMatcher: successMatcher(), CreatesParents: createsParents}, }, } } func fullWorkspaceAlternative(name, toolName string, command bool) config.ExecutionWorkspaceToolAlternative { alternative := workspaceAlternative(name, toolName, command, true) for _, operation := range []workspaceOperationKind{opKindRead, opKindDelete} { argumentMap := map[string]any{"path": "path"} if command { argumentMap = map[string]any{"path": "path", "command": "command", "argv": []any{string(operation), "{path}"}} } alternative.Operations[string(operation)] = config.ExecutionWorkspaceOperation{ ToolName: toolName, SchemaMatcher: map[string]any{"type": "object"}, ArgumentMap: argumentMap, ResultMatcher: successMatcher(), CreatesParents: true, } } return alternative } func cloneWorkspacePayload(payload *workspaceEncodedPayload) *workspaceEncodedPayload { copy := *payload copy.structuredArgs = cloneAnyMap(payload.structuredArgs) copy.commandArgv = append([]string(nil), payload.commandArgv...) return © } func successMatcher() map[string]any { return map[string]any{"status": "success", "result": map[string]any{"written": true}} } func structuredSchema() map[string]any { return map[string]any{"type": "object", "properties": map[string]any{"path": map[string]any{"type": "string"}, "content": map[string]any{}}, "required": []any{"path", "content"}} } func commandSchema() map[string]any { return map[string]any{"type": "object", "properties": map[string]any{"command": map[string]any{"type": "string"}}} } func openAIChatTool(name string, schema map[string]any) map[string]any { return map[string]any{"type": "function", "function": map[string]any{"name": name, "description": "workspace tool", "parameters": schema}} } func anthropicWorkspaceTool(name string, schema map[string]any) map[string]any { return map[string]any{"name": name, "description": "workspace tool", "input_schema": schema} } func unrelatedTool() map[string]any { return openAIChatTool("get_weather", map[string]any{"type": "object", "properties": map[string]any{"city": map[string]any{"type": "string"}}}) }