package orchestrator

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/flothus/tmux-xterm-research/server-go/internal/harness/org"
)

// TestResolveRolePathRejectsEscapes is the V88 regression: a malicious org
// yaml must not be able to point its role `definition` at an absolute path
// (e.g. /etc/passwd) or a relative path that escapes the project tree.
// Without this guard the renderer would read the target file and feed its
// contents to the LLM as the agent's system prompt.
func TestResolveRolePathRejectsEscapes(t *testing.T) {
	tmp := t.TempDir()
	// Build a sandbox: ProjectRoot/.td/orgs/foo.yaml and ProjectRoot/.td/roles/x.md.
	root := tmp
	rolesDir := filepath.Join(root, ".td", "roles")
	if err := os.MkdirAll(rolesDir, 0o755); err != nil {
		t.Fatal(err)
	}
	rolePath := filepath.Join(rolesDir, "x.md")
	if err := os.WriteFile(rolePath, []byte("# legitimate role"), 0o644); err != nil {
		t.Fatal(err)
	}
	yamlDir := filepath.Join(root, ".td", "orgs")
	if err := os.MkdirAll(yamlDir, 0o755); err != nil {
		t.Fatal(err)
	}
	yamlPath := filepath.Join(yamlDir, "foo.yaml")

	r := &OrgRunner{
		Def: &org.Definition{
			SourcePath: yamlPath,
		},
		ProjectRoot: root,
	}

	cases := []struct {
		name string
		in   string
		want string // "" means rejected; non-empty means accepted
	}{
		{"absolute /etc/passwd", "/etc/passwd", ""},
		{"absolute project file", filepath.Join(root, ".td", "roles", "x.md"), ""},
		{"escape via ..", "../../../etc/passwd", ""},
		{"legitimate relative", "roles/x.md", rolePath},
	}
	for _, c := range cases {
		got := r.resolveRolePath(c.in)
		if c.want == "" {
			if got != "" {
				t.Errorf("%s: resolveRolePath(%q) = %q, want \"\" (rejection)", c.name, c.in, got)
			}
		} else {
			// Normalize through symlinks for compare (macOS /tmp → /private/tmp).
			gotReal, _ := filepath.EvalSymlinks(got)
			wantReal, _ := filepath.EvalSymlinks(c.want)
			if gotReal != wantReal {
				t.Errorf("%s: resolveRolePath(%q) = %q, want %q", c.name, c.in, gotReal, wantReal)
			}
		}
	}
}
