Harden image admission, resource recovery and session renewal
Add exact-image compatibility policy, experimental admission, paginated build history and shared reauthentication checks. Preserve uncertain Docker creation records, bound frontend resource waits and renew runtime sessions proactively. Lazy-load and split Monaco, add regression and opt-in live Docker fault tests, and record full race and real-browser acceptance results.
This commit is contained in:
+31
-28
@@ -26,7 +26,7 @@ func imageTestAPI(t *testing.T, h http.HandlerFunc) (*API, string) {
|
||||
t.Cleanup(func() { buildDiskAvailable = oldDiskAvailable })
|
||||
oldClient := npmBuildClient
|
||||
npmBuildClient = &http.Client{Transport: imageRoundTrip(func(r *http.Request) (*http.Response, error) {
|
||||
return &http.Response{StatusCode: 200, Header: make(http.Header), Body: io.NopCloser(strings.NewReader(`{"version":"1.2.3"}`))}, nil
|
||||
return &http.Response{StatusCode: 200, Header: make(http.Header), Body: io.NopCloser(strings.NewReader(`{"version":"0.2.0-rc.1"}`))}, nil
|
||||
})}
|
||||
t.Cleanup(func() { npmBuildClient = oldClient })
|
||||
root := t.TempDir()
|
||||
@@ -86,19 +86,19 @@ func imageRequest(h http.HandlerFunc, sid, method, body string) *httptest.Respon
|
||||
func TestImageListContract(t *testing.T) {
|
||||
a, sid := imageTestAPI(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/v1.47/images/unverified/json" {
|
||||
writeImageInspect(w, "unverified", "1.2.3")
|
||||
writeImageInspect(w, "unverified", "0.2.0-rc.1")
|
||||
return
|
||||
}
|
||||
if r.URL.Path == "/v1.47/images/sha256:abc/json" {
|
||||
writeImageInspect(w, "sha256:abc", "1.2.3")
|
||||
writeImageInspect(w, "sha256:abc", "0.2.0-rc.1")
|
||||
return
|
||||
}
|
||||
if !strings.Contains(r.URL.Query().Get("filters"), "dsh-mgr.role=runtime") {
|
||||
t.Error("missing label filter")
|
||||
}
|
||||
io.WriteString(w, `[{"Id":"sha256:abc","Labels":{"dsh-mgr.role":"runtime","dsh-mgr.version":"1.2.3","dsh-mgr.recipe":"`+imageRecipeRev+`"},"RepoTags":["runtime:1.2.3"]},{"Id":"other","Labels":{}},{"Id":"unverified","Labels":{"dsh-mgr.role":"runtime","dsh-mgr.version":"1.2.3","dsh-mgr.recipe":"`+imageRecipeRev+`"}},{"Id":"sha256:abc","Labels":{"dsh-mgr.role":"runtime","dsh-mgr.version":"9.9.9"}}]`)
|
||||
io.WriteString(w, `[{"Id":"sha256:abc","Labels":{"dsh-mgr.role":"runtime","dsh-mgr.version":"0.2.0-rc.1","dsh-mgr.recipe":"`+imageRecipeRev+`"},"RepoTags":["runtime:0.2.0-rc.1"]},{"Id":"other","Labels":{}},{"Id":"unverified","Labels":{"dsh-mgr.role":"runtime","dsh-mgr.version":"0.2.0-rc.1","dsh-mgr.recipe":"`+imageRecipeRev+`"}},{"Id":"sha256:abc","Labels":{"dsh-mgr.role":"runtime","dsh-mgr.version":"9.9.9"}}]`)
|
||||
})
|
||||
seedVerifiedImage(t, a, "sha256:abc", "1.2.3")
|
||||
seedVerifiedImage(t, a, "sha256:abc", "0.2.0-rc.1")
|
||||
if w := imageRequest(a.images, "", "GET", ""); w.Code != 401 {
|
||||
t.Fatal(w.Code)
|
||||
}
|
||||
@@ -125,6 +125,9 @@ func seedVerifiedImage(t *testing.T, a *API, id, version string) {
|
||||
if _, err := a.s.DB.Exec("INSERT INTO image_builds(id,version,status,image_id,created_at,recipe_rev,platform) VALUES(?,?,'success',?,'now',?,?)", store.ID(), version, id, imageRecipeRev, imagePlatform); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := a.s.DB.Exec("INSERT OR REPLACE INTO image_admissions(image_id,version,recipe_rev,platform,state,evidence,admitted_by,admitted_at) VALUES(?,?,?,?,'compatible','test fixture explicit acceptance','test','now')", id, version, imageRecipeRev, imagePlatform); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
func TestImageContextAndSanitizing(t *testing.T) {
|
||||
r, err := imageBuildContext()
|
||||
@@ -163,12 +166,12 @@ func TestImageContextAndSanitizing(t *testing.T) {
|
||||
if len(sanitizeBuildLog(strings.Repeat("x", 2*buildLogLimit))) > buildLogLimit {
|
||||
t.Fatal("unbounded")
|
||||
}
|
||||
for _, v := range []string{"latest", "*", "^1.2.3", "1.2", "1.2.3;id", "https://example.com", ""} {
|
||||
for _, v := range []string{"latest", "*", "^0.2.0-rc.1", "1.2", "0.2.0-rc.1;id", "https://example.com", ""} {
|
||||
if validBuildVersion(v) {
|
||||
t.Fatal(v)
|
||||
}
|
||||
}
|
||||
if !validBuildVersion("1.2.3-beta.1") {
|
||||
if !validBuildVersion("0.2.0-rc.1-beta.1") {
|
||||
t.Fatal("fixed prerelease rejected")
|
||||
}
|
||||
}
|
||||
@@ -181,10 +184,10 @@ func TestLatestOfficialRegistry(t *testing.T) {
|
||||
if r.URL.Host != "registry.npmjs.org" || r.URL.Scheme != "https" {
|
||||
t.Fatal(r.URL)
|
||||
}
|
||||
return &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(`{"version":"1.2.3"}`)), Header: make(http.Header)}, nil
|
||||
return &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(`{"version":"0.2.0-rc.1"}`)), Header: make(http.Header)}, nil
|
||||
})}
|
||||
v, err := fetchLatest(context.Background(), client)
|
||||
if err != nil || v != "1.2.3" {
|
||||
if err != nil || v != "0.2.0-rc.1" {
|
||||
t.Fatalf("%s %v", v, err)
|
||||
}
|
||||
}
|
||||
@@ -193,21 +196,21 @@ func TestBuildDedupAndVerification(t *testing.T) {
|
||||
a, sid := imageTestAPI(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/v1.47/images/sha256:abc/json", "/v1.47/images/sha256:reuse/json":
|
||||
writeImageInspect(w, strings.TrimSuffix(strings.TrimPrefix(r.URL.Path, "/v1.47/images/"), "/json"), "1.2.3")
|
||||
writeImageInspect(w, strings.TrimSuffix(strings.TrimPrefix(r.URL.Path, "/v1.47/images/"), "/json"), "0.2.0-rc.1")
|
||||
case "/v1.47/images/json":
|
||||
if calls.Load() == 0 {
|
||||
io.WriteString(w, "[]")
|
||||
} else {
|
||||
io.WriteString(w, `[{"Id":"sha256:abc","Labels":{"dsh-mgr.role":"runtime","dsh-mgr.version":"1.2.3","dsh-mgr.recipe":"`+imageRecipeRev+`"}}]`)
|
||||
io.WriteString(w, `[{"Id":"sha256:abc","Labels":{"dsh-mgr.role":"runtime","dsh-mgr.version":"0.2.0-rc.1","dsh-mgr.recipe":"`+imageRecipeRev+`"}}]`)
|
||||
}
|
||||
case "/v1.47/build":
|
||||
calls.Add(1)
|
||||
if r.URL.Query().Get("t") != "dsh-web:1.2.3-"+imageRecipeRev {
|
||||
if r.URL.Query().Get("t") != "dsh-web:0.2.0-rc.1-"+imageRecipeRev {
|
||||
t.Error("unexpected tag", r.URL.Query())
|
||||
}
|
||||
var args map[string]string
|
||||
json.Unmarshal([]byte(r.URL.Query().Get("buildargs")), &args)
|
||||
if args["DSH_VERSION"] != "1.2.3" {
|
||||
if args["DSH_VERSION"] != "0.2.0-rc.1" {
|
||||
t.Error(args)
|
||||
}
|
||||
io.Copy(io.Discard, r.Body)
|
||||
@@ -230,7 +233,7 @@ func TestBuildDedupAndVerification(t *testing.T) {
|
||||
w.WriteHeader(204)
|
||||
case "/v1.47/containers/check/exec":
|
||||
var cfg struct{ Cmd []string }
|
||||
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!=="1.2.3"`) {
|
||||
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!=="0.2.0-rc.1"`) {
|
||||
t.Errorf("missing version verification: %+v %v", cfg, err)
|
||||
}
|
||||
io.WriteString(w, `{"Id":"probe"}`)
|
||||
@@ -252,7 +255,7 @@ func TestBuildDedupAndVerification(t *testing.T) {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
responses <- imageRequest(a.builds, sid, "POST", `{"version":"1.2.3"}`)
|
||||
responses <- imageRequest(a.builds, sid, "POST", `{"version":"0.2.0-rc.1"}`)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
@@ -290,7 +293,7 @@ func TestBuildDedupAndVerification(t *testing.T) {
|
||||
if calls.Load() != 1 || deleted.Load() != 1 {
|
||||
t.Fatalf("builds %d cleanup %d", calls.Load(), deleted.Load())
|
||||
}
|
||||
for _, body := range []string{`{"version":"latest"}`, `{"version":"1.2.3","url":"bad"}`, `{"version":"1.2.3"} {}`} {
|
||||
for _, body := range []string{`{"version":"latest"}`, `{"version":"0.2.0-rc.1","url":"bad"}`, `{"version":"0.2.0-rc.1"} {}`} {
|
||||
if w := imageRequest(a.builds, sid, "POST", body); w.Code != 400 {
|
||||
t.Fatal(w.Code)
|
||||
}
|
||||
@@ -310,7 +313,7 @@ func TestVerificationFailureCleansUp(t *testing.T) {
|
||||
io.WriteString(w, `{"message":"cannot start"}`)
|
||||
}
|
||||
})
|
||||
if err := a.verifyBuiltImage(context.Background(), "bad", "1.2.3"); err == nil {
|
||||
if err := a.verifyBuiltImage(context.Background(), "bad", "0.2.0-rc.1"); err == nil {
|
||||
t.Fatal("accepted failed start")
|
||||
}
|
||||
if !deleted.Load() {
|
||||
@@ -325,10 +328,10 @@ func TestBuildReuseAndMissingImage(t *testing.T) {
|
||||
a, sid := imageTestAPI(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/v1.47/images/sha256:abc/json", "/v1.47/images/sha256:reuse/json":
|
||||
writeImageInspect(w, strings.TrimSuffix(strings.TrimPrefix(r.URL.Path, "/v1.47/images/"), "/json"), "1.2.3")
|
||||
writeImageInspect(w, strings.TrimSuffix(strings.TrimPrefix(r.URL.Path, "/v1.47/images/"), "/json"), "0.2.0-rc.1")
|
||||
case "/v1.47/images/json":
|
||||
if exists.Load() {
|
||||
io.WriteString(w, `[{"Id":"sha256:reuse","Labels":{"dsh-mgr.role":"runtime","dsh-mgr.version":"1.2.3","dsh-mgr.recipe":"`+imageRecipeRev+`"}}]`)
|
||||
io.WriteString(w, `[{"Id":"sha256:reuse","Labels":{"dsh-mgr.role":"runtime","dsh-mgr.version":"0.2.0-rc.1","dsh-mgr.recipe":"`+imageRecipeRev+`"}}]`)
|
||||
} else {
|
||||
io.WriteString(w, "[]")
|
||||
}
|
||||
@@ -373,7 +376,7 @@ func TestBuildReuseAndMissingImage(t *testing.T) {
|
||||
}
|
||||
post := func() buildRecord {
|
||||
t.Helper()
|
||||
w := imageRequest(a.builds, sid, "POST", `{"version":"1.2.3"}`)
|
||||
w := imageRequest(a.builds, sid, "POST", `{"version":"0.2.0-rc.1"}`)
|
||||
if w.Code != 202 {
|
||||
t.Fatal(w.Body.String())
|
||||
}
|
||||
@@ -405,7 +408,7 @@ func TestBuildRestartRecovery(t *testing.T) {
|
||||
if err := a.ensureBuilds(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := a.s.DB.Exec("INSERT INTO image_builds(id,version,status,created_at) VALUES('old','1.2.3','running','now')"); err != nil {
|
||||
if _, err := a.s.DB.Exec("INSERT INTO image_builds(id,version,status,created_at) VALUES('old','0.2.0-rc.1','running','now')"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
delete(buildQueue.initialized, a.s.DB)
|
||||
@@ -427,9 +430,9 @@ func TestFailedVerificationNeverAvailable(t *testing.T) {
|
||||
a, sid := imageTestAPI(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/v1.47/images/sha256:abc/json", "/v1.47/images/sha256:reuse/json":
|
||||
writeImageInspect(w, strings.TrimSuffix(strings.TrimPrefix(r.URL.Path, "/v1.47/images/"), "/json"), "1.2.3")
|
||||
writeImageInspect(w, strings.TrimSuffix(strings.TrimPrefix(r.URL.Path, "/v1.47/images/"), "/json"), "0.2.0-rc.1")
|
||||
case "/v1.47/images/json":
|
||||
writeJSON(w, []any{map[string]any{"Id": imageID, "Labels": map[string]string{"dsh-mgr.role": "runtime", "dsh-mgr.version": "1.2.3", "dsh-mgr.recipe": imageRecipeRev}}})
|
||||
writeJSON(w, []any{map[string]any{"Id": imageID, "Labels": map[string]string{"dsh-mgr.role": "runtime", "dsh-mgr.version": "0.2.0-rc.1", "dsh-mgr.recipe": imageRecipeRev}}})
|
||||
case "/v1.47/containers/create":
|
||||
io.WriteString(w, `{"Id":"check"}`)
|
||||
case "/v1.47/containers/check/start", "/v1.47/exec/probe/start":
|
||||
@@ -442,13 +445,13 @@ func TestFailedVerificationNeverAvailable(t *testing.T) {
|
||||
deleted.Store(true)
|
||||
w.WriteHeader(204)
|
||||
case "/v1.47/images/" + imageID + "/json":
|
||||
writeImageInspect(w, imageID, "1.2.3")
|
||||
writeImageInspect(w, imageID, "0.2.0-rc.1")
|
||||
default:
|
||||
t.Errorf("unexpected Docker call %s", r.URL)
|
||||
w.WriteHeader(500)
|
||||
}
|
||||
})
|
||||
w := imageRequest(a.builds, sid, "POST", `{"version":"1.2.3"}`)
|
||||
w := imageRequest(a.builds, sid, "POST", `{"version":"0.2.0-rc.1"}`)
|
||||
if w.Code != 202 {
|
||||
t.Fatal(w.Body.String())
|
||||
}
|
||||
@@ -481,12 +484,12 @@ func TestFailedVerificationNeverAvailable(t *testing.T) {
|
||||
func TestLocalBuildImagePrefersPersistedID(t *testing.T) {
|
||||
a, _ := imageTestAPI(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/v1.47/images/verified/json" {
|
||||
writeImageInspect(w, "verified", "1.2.3")
|
||||
writeImageInspect(w, "verified", "0.2.0-rc.1")
|
||||
return
|
||||
}
|
||||
io.WriteString(w, `[{"Id":"newer","Labels":{"dsh-mgr.role":"runtime","dsh-mgr.version":"1.2.3","dsh-mgr.recipe":"`+imageRecipeRev+`"}},{"Id":"verified","Labels":{"dsh-mgr.role":"runtime","dsh-mgr.version":"1.2.3","dsh-mgr.recipe":"`+imageRecipeRev+`"}}]`)
|
||||
io.WriteString(w, `[{"Id":"newer","Labels":{"dsh-mgr.role":"runtime","dsh-mgr.version":"0.2.0-rc.1","dsh-mgr.recipe":"`+imageRecipeRev+`"}},{"Id":"verified","Labels":{"dsh-mgr.role":"runtime","dsh-mgr.version":"0.2.0-rc.1","dsh-mgr.recipe":"`+imageRecipeRev+`"}}]`)
|
||||
})
|
||||
id, err := a.localBuildImage(context.Background(), "1.2.3", "verified")
|
||||
id, err := a.localBuildImage(context.Background(), "0.2.0-rc.1", "verified")
|
||||
if err != nil || id != "verified" {
|
||||
t.Fatalf("id=%s err=%v", id, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user