package taskexecution import ( "context" "encoding/pem" "github.com/netkingdom/approval-engine/adapters/go/approvalfact" "net/http" "net/http/httptest" "os" "path/filepath" "strings" "sync/atomic" "testing" "time" ) func TestFixedApprovalReaderRefusalBoundary(t *testing.T) { folder := t.TempDir() token := filepath.Join(folder, "token") ca := filepath.Join(folder, "ca") if err := os.WriteFile(token, []byte("synthetic-source-token"), 0440); err != nil { t.Fatal(err) } var mode atomic.Value mode.Store("ok") var foreignCalls atomic.Int64 foreign := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { foreignCalls.Add(1) t.Error("credential escaped fixed origin") })) defer foreign.Close() server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Header.Get("Authorization") != "Bearer synthetic-source-token" || r.URL.Path != "/v1/approvals/aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee/claim" || r.Method != "GET" { t.Error("wrong auth/path/method") } w.Header().Set("Content-Type", "application/json") switch mode.Load().(string) { case "redirect": w.Header().Set("Location", foreign.URL) w.WriteHeader(302) return case "status": w.WriteHeader(403) case "large": w.Write([]byte(strings.Repeat(" ", 524289))) case "duplicate": w.Write([]byte(`{"a":true,"a":false}`)) case "invalid-utf8": w.Write([]byte{'"', 255, '"'}) case "media": w.Header().Set("Content-Type", "application/json; arbitrary=authority") w.Write([]byte(`{}`)) case "duplicate-media": w.Header().Add("Content-Type", "application/json") w.Write([]byte(`{}`)) case "compressed": w.Header().Set("Content-Encoding", "gzip") w.Write([]byte(`{}`)) case "slow": select { case <-r.Context().Done(): case <-time.After(time.Second): } default: w.Write([]byte(`{}`)) } })) defer server.Close() os.WriteFile(ca, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: server.Certificate().Raw}), 0600) config := ApprovalSourceConfig{SourceID: "synthetic-source", SourceRevision: "synthetic-revision", Origin: server.URL, StoreTenant: "tenant:platform", CAFile: ca, TokenFile: token} reader, err := NewApprovalReader(config) if err != nil { t.Fatal(err) } if _, err := reader.Observe(context.Background(), "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee"); err != nil { t.Fatal(err) } for _, name := range []string{"redirect", "status", "large", "duplicate", "invalid-utf8", "media", "duplicate-media", "compressed", "slow"} { t.Run(name, func(t *testing.T) { mode.Store(name) ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) defer cancel() if _, err := reader.Observe(ctx, "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee"); err == nil { t.Fatal("invalid provider response admitted") } }) } if foreignCalls.Load() != 0 { t.Fatal("redirect followed") } mode.Store("ok") for _, bad := range []string{"../consume", "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee/consume", ""} { if _, err := reader.Observe(context.Background(), bad); err == nil { t.Fatal("request selected route") } } for _, mode := range []os.FileMode{0460, 0644, 0620} { os.Chmod(token, mode) if _, err := reader.Observe(context.Background(), "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee"); err == nil { t.Fatal("unsafe token permissions") } } for _, origin := range []string{"http://127.0.0.1", "https://user:password@localhost", "https://localhost/path", "https://localhost?query=1", "https://localhost#fragment"} { bad := config bad.Origin = origin if _, err := NewApprovalReader(bad); err == nil { t.Fatal("unsafe origin") } } bad := config bad.StoreTenant = "tenant:foreign" if _, err := NewApprovalReader(bad); err == nil { t.Fatal("foreign tenant configured") } if _, err := (ApprovalObservation{}).Validate([]byte(`{}`), approvalfact.Expected{}, time.Now()); err == nil { t.Fatal("zero observation admitted") } }