package debugbundle import ( "os" "path/filepath" "testing" "time" ) func TestAllocateCreatesRestrictiveSummaryAndTrace(t *testing.T) { parent := t.TempDir() fixed := time.Unix(0, 42).UTC() previous := utcNow utcNow = func() time.Time { return fixed } defer func() { utcNow = previous }() bundle, err := Allocate(parent) if err != nil { t.Fatal(err) } if bundle.RunID() != "run-42" || bundle.SummaryRoot() != filepath.Join(bundle.Path(), "summary") || bundle.TraceRoot() != filepath.Join(bundle.Path(), "trace") { t.Fatalf("bundle=%#v", bundle) } for _, path := range []string{bundle.Path(), bundle.SummaryRoot(), bundle.TraceRoot()} { info, err := os.Stat(path) if err != nil { t.Fatal(err) } if info.Mode().Perm() != 0o700 { t.Fatalf("%s mode=%#o", path, info.Mode().Perm()) } } if err := bundle.Summary().WriteError("failed"); err != nil { t.Fatal(err) } info, err := os.Stat(filepath.Join(bundle.SummaryRoot(), ArtifactErrorLog)) if err != nil { t.Fatal(err) } if info.Mode().Perm() != 0o600 { t.Fatalf("file mode=%#o", info.Mode().Perm()) } } func TestAllocateRetriesAndDoesNotDeleteBundle(t *testing.T) { parent := t.TempDir() fixed := time.Unix(0, 9).UTC() previous := utcNow defer func() { utcNow = previous }() calls := 0 utcNow = func() time.Time { calls++; return fixed.Add(time.Duration(calls-1) * time.Nanosecond) } if err := os.Mkdir(filepath.Join(parent, "run-9"), 0o700); err != nil { t.Fatal(err) } bundle, err := Allocate(parent) if err != nil { t.Fatal(err) } if bundle.RunID() != "run-10" { t.Fatalf("run id=%q", bundle.RunID()) } if _, err := os.Stat(bundle.Path()); err != nil { t.Fatal(err) } } func TestSummaryWriterConfinesArtifacts(t *testing.T) { bundle, err := Allocate(t.TempDir()) if err != nil { t.Fatal(err) } if err := bundle.Summary().WriteJSON("../outside.json", map[string]any{}); err == nil { t.Fatal("accepted traversal") } if err := bundle.Summary().WriteBytes(`trace\\x`, []byte("x")); err == nil { t.Fatal("accepted backslash") } }