package api import ( "archive/tar" "bytes" "context" "encoding/json" "errors" "io" "net/http" "strings" "testing" ) func testReleaseArchive(t *testing.T, m string, files map[string]string) []byte { t.Helper() var b bytes.Buffer tw := tar.NewWriter(&b) files["release.json"] = m for name, data := range files { if err := tw.WriteHeader(&tar.Header{Name: name, Size: int64(len(data)), Mode: 0644}); err != nil { t.Fatal(err) } if _, err := tw.Write([]byte(data)); err != nil { t.Fatal(err) } } if err := tw.Close(); err != nil { t.Fatal(err) } return b.Bytes() } func releaseFixture() releaseInfo { return releaseInfo{releaseManifest: releaseManifest{SchemaVersion: 1, ReleaseID: "runtime-7.1", Version: "0.2.0-rc.3", DeploymentSchema: 7, Platforms: []string{imagePlatform}}, Repository: "https://git.misaka.ren/m1saka/dsh-web.git", Commit: strings.Repeat("a", 40)} } func TestReleaseManifestAndContext(t *testing.T) { info := releaseFixture() data, _ := json.Marshal(info.releaseManifest) for _, tc := range []struct { name, manifest string files map[string]string wantErr bool }{ {"valid", string(data), map[string]string{"image/Dockerfile": "FROM scratch", "image/nested/helper": "complete", "image/.git/config": "secret", "image/.env": "secret"}, false}, {"malformed", "{", map[string]string{"image/Dockerfile": "FROM scratch"}, true}, {"unknown", strings.Replace(string(data), "schema_version", "unknown", 1), map[string]string{"image/Dockerfile": "FROM scratch"}, true}, {"incompatible", strings.Replace(string(data), "deployment_schema\":7", "deployment_schema\":8", 1), map[string]string{"image/Dockerfile": "FROM scratch"}, true}, {"missing Dockerfile", string(data), map[string]string{"image/helper": "x"}, true}, {"unsafe path", string(data), map[string]string{"image/Dockerfile": "FROM scratch", "image/../escape": "x"}, true}, } { t.Run(tc.name, func(t *testing.T) { _, r, err := parseReleaseArchive(info, testReleaseArchive(t, tc.manifest, tc.files)) if (err != nil) != tc.wantErr { t.Fatalf("err=%v", err) } if err != nil { return } tr := tar.NewReader(r) seen := map[string]bool{} for { h, e := tr.Next() if e == io.EOF { break } if e != nil { t.Fatal(e) } seen[h.Name] = true } if !seen["nested/helper"] || seen[".env"] || seen[".git/config"] { t.Fatal(seen) } }) } } func TestReleaseQueueIdentityRecoveryAndFailure(t *testing.T) { a, _ := imageTestAPI(t, func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(404) }) info := releaseFixture() b, err := a.enqueueRelease("u", info) if err != nil { t.Fatal(err) } again, err := a.enqueueRelease("u", info) if err != nil || again.ID != b.ID { t.Fatalf("repeat %v %v", again, err) } info.Commit = strings.Repeat("b", 40) info.ReleaseID = "runtime-7.2" next, err := a.enqueueRelease("u", info) if err != nil || next.ID == b.ID || next.Version != b.Version { t.Fatalf("next %v %v", next, err) } buildQueue.Lock() delete(buildQueue.initialized, a.s.DB) err = a.ensureBuilds() buildQueue.Unlock() if err != nil { t.Fatal(err) } var recovered buildRecord if err = scanBuildSummary(a.s.DB.QueryRow("SELECT "+buildSummaryColumns+" FROM image_builds WHERE id=?", next.ID), &recovered); err != nil { t.Fatal(err) } if recovered.Status != "queued" || recovered.SourceCommit != info.Commit { t.Fatal(recovered) } if _, err = a.s.DB.Exec("UPDATE image_builds SET status='failed' WHERE id=?", next.ID); err != nil { t.Fatal(err) } retry, err := a.enqueueRelease("u", info) if err != nil || retry.ID == next.ID { t.Fatalf("retry %v %v", retry, err) } } func TestReleaseEndpointsAuthorizationFailureAndMismatch(t *testing.T) { a, sid := imageTestAPI(t, func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(404) }) if w := imageRequest(a.latestRelease, sid, "GET", ""); w.Code != 403 { t.Fatal(w.Code) } if _, err := a.s.DB.Exec("UPDATE users SET admin=1 WHERE id='u'"); err != nil { t.Fatal(err) } old := fetchRelease t.Cleanup(func() { fetchRelease = old }) fetchRelease = func(context.Context, string, string) (releaseInfo, io.Reader, error) { return releaseInfo{}, nil, errors.New("network failure") } if w := imageRequest(a.latestRelease, sid, "GET", ""); w.Code != 502 { t.Fatalf("%d %s", w.Code, w.Body.String()) } fetchRelease = func(context.Context, string, string) (releaseInfo, io.Reader, error) { return releaseFixture(), nil, nil } if w := imageRequest(a.releaseBuild, sid, "POST", `{"commit":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}`); w.Code != 409 { t.Fatalf("%d %s", w.Code, w.Body.String()) } fetchRelease = func(context.Context, string, string) (releaseInfo, io.Reader, error) { return releaseFixture(), nil, errReleaseIncompatible } if w := imageRequest(a.latestRelease, sid, "GET", ""); w.Code != 200 || !strings.Contains(w.Body.String(), `"compatible":false`) { t.Fatalf("%d %s", w.Code, w.Body.String()) } } func TestReleaseGitEnvironmentAndFailure(t *testing.T) { out, err := gitReleaseCommand(context.Background(), t.TempDir(), "--version") if err != nil || !strings.HasPrefix(string(out), "git version") { t.Fatalf("%q %v", out, err) } ctx, cancel := context.WithCancel(context.Background()) cancel() if _, err = gitReleaseCommand(ctx, t.TempDir(), "--version"); err == nil { t.Fatal("cancel ignored") } for _, repository := range []string{"http://example.test/repo", "https://user:password@example.test/repo", "https://example.test/repo?token=secret"} { t.Setenv("DSH_RELEASE_REPOSITORY", repository) if _, _, err = releaseSource(); err == nil { t.Fatal("accepted unsafe source") } } } func TestPinnedReleaseWorkerAdmissionAndBlock(t *testing.T) { testPinnedReleaseWorkerAdmissionAndBlock(t, "") } func TestPinnedReleaseWorkerARM64V8AdmissionAndBlock(t *testing.T) { previous := imagePlatform imagePlatform = "linux/arm64" t.Cleanup(func() { imagePlatform = previous }) testPinnedReleaseWorkerAdmissionAndBlock(t, "v8") } func testPinnedReleaseWorkerAdmissionAndBlock(t *testing.T, variant string) { t.Helper() info := releaseFixture() labels := map[string]string{"dsh-mgr.role": "runtime", "dsh-mgr.version": info.Version, "dsh-mgr.recipe": "7", "dsh-mgr.release": info.ReleaseID, "dsh-mgr.source": info.Repository, "dsh-mgr.commit": info.Commit} a, _ := imageTestAPI(t, func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case "/v1.47/build": var got map[string]string if err := json.Unmarshal([]byte(r.URL.Query().Get("labels")), &got); err != nil { t.Error(err) } if got["dsh-mgr.commit"] != info.Commit || r.URL.Query().Get("t") != "dsh-web:release-"+info.Commit { t.Error("missing provenance", r.URL) } data, _ := io.ReadAll(r.Body) if !bytes.Contains(data, []byte("pinned context")) { t.Error("wrong build context") } io.WriteString(w, `{"aux":{"ID":"sha256:release"}}`) case "/v1.47/images/sha256:release/json": parts := strings.Split(imagePlatform, "/") writeJSON(w, map[string]any{"Id": "sha256:release", "Os": parts[0], "Architecture": parts[1], "Variant": variant, "Config": map[string]any{"Labels": labels}}) case "/v1.47/containers/create": var cfg struct { Image, User string HostConfig struct { NetworkMode string ReadonlyRootfs bool Tmpfs map[string]string } } if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil || cfg.Image != "sha256:release" || cfg.User != "1000:1000" || cfg.HostConfig.NetworkMode != "none" || !cfg.HostConfig.ReadonlyRootfs || !strings.Contains(cfg.HostConfig.Tmpfs["/tmp"], "exec") { t.Errorf("unsafe verification config %+v err=%v", cfg, err) } io.WriteString(w, `{"Id":"check"}`) case "/v1.47/containers/check/start", "/v1.47/exec/probe/start", "/v1.47/containers/check": w.WriteHeader(204) case "/v1.47/containers/check/exec": var cfg struct{ Cmd []string } expected, _ := json.Marshal(info.Version) if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil || len(cfg.Cmd) != 3 || !strings.Contains(cfg.Cmd[2], "execFileSync('dsh',['--version']") || !strings.Contains(cfg.Cmd[2], "actual!=="+string(expected)) { t.Errorf("missing exact version check %+v err=%v", cfg, err) } io.WriteString(w, `{"Id":"probe"}`) case "/v1.47/exec/probe/json": io.WriteString(w, `{"Running":false,"ExitCode":0}`) case "/v1.47/containers/check/json": io.WriteString(w, `{"State":{"Running":true}}`) default: t.Errorf("unexpected %s", r.URL) w.WriteHeader(500) } }) if _, err := a.s.DB.Exec("UPDATE users SET admin=1 WHERE id='u'"); err != nil { t.Fatal(err) } old := fetchRelease t.Cleanup(func() { fetchRelease = old }) fetchRelease = func(ctx context.Context, repository, ref string) (releaseInfo, io.Reader, error) { if repository != info.Repository || ref != info.Commit { t.Error("not pinned", repository, ref) } return info, strings.NewReader("pinned context"), nil } b, err := a.enqueueRelease("u", info) if err != nil { t.Fatal(err) } a.runImageBuild(b) if err = scanBuildSummary(a.s.DB.QueryRow("SELECT "+buildSummaryColumns+" FROM image_builds WHERE id=?", b.ID), &b); err != nil { t.Fatal(err) } if b.Status != "success" { t.Fatalf("%+v", b) } records := []buildRecord{b} if err = a.reconcileBuilds(context.Background(), records); err != nil || records[0].Status != "success" { t.Fatalf("reconciliation: %+v %v", records, err) } im, err := a.evaluateImage(context.Background(), b.ImageID) if err != nil || !im.Selectable { t.Fatalf("%+v %v", im, err) } if _, err = a.s.DB.Exec("INSERT INTO image_admissions(image_id,version,recipe_rev,platform,state,evidence,admitted_by,admitted_at) VALUES(?,?,?,?,?,?,?,?)", b.ImageID, b.Version, "7", imagePlatform, "blocked", "explicit block", "u", "now"); err != nil { t.Fatal(err) } im, err = a.evaluateImage(context.Background(), b.ImageID) if err != nil || im.Selectable || im.Admission != "blocked" { t.Fatalf("%+v %v", im, err) } } func TestReleaseRateLimitDedup(t *testing.T) { a, _ := imageTestAPI(t, func(w http.ResponseWriter, r *http.Request) { t.Error("queued release contacted Docker") }) info := releaseFixture() first, err := a.enqueueRelease("u", info) if err != nil { t.Fatal(err) } for _, commit := range []string{strings.Repeat("b", 40), strings.Repeat("c", 40)} { next := info next.Commit = commit if _, err := a.enqueueRelease("u", next); err != nil { t.Fatal(err) } } again, err := a.enqueueRelease("u", info) if err != nil || again.ID != first.ID { t.Fatal(again, err) } info.Commit = strings.Repeat("d", 40) if _, err := a.enqueueRelease("u", info); err != errBuildRateLimited { t.Fatal(err) } var count int if err := a.s.DB.QueryRow("SELECT count(*) FROM image_build_requests").Scan(&count); err != nil || count != 3 { t.Fatal(count, err) } } func TestReleaseUnknownDiskBlocksBuild(t *testing.T) { a, _ := imageTestAPI(t, func(w http.ResponseWriter, r *http.Request) { t.Errorf("unexpected Docker request %s", r.URL) }) t.Setenv("DSH_DOCKER_ROOT_VISIBLE", "") if _, err := a.s.DB.Exec("UPDATE users SET admin=1 WHERE id='u'"); err != nil { t.Fatal(err) } info := releaseFixture() old := fetchRelease t.Cleanup(func() { fetchRelease = old }) fetchRelease = func(context.Context, string, string) (releaseInfo, io.Reader, error) { return info, strings.NewReader("context"), nil } b, err := a.enqueueRelease("u", info) if err != nil { t.Fatal(err) } a.runImageBuild(b) if err := scanBuildSummary(a.s.DB.QueryRow("SELECT "+buildSummaryColumns+" FROM image_builds WHERE id=?", b.ID), &b); err != nil { t.Fatal(err) } if b.Status != "failed" || !strings.Contains(b.Error, "capacity unknown") { t.Fatalf("%+v", b) } }