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:
2026-10-14 13:41:54 +08:00
parent 66abb76318
commit 9a71772771
62 changed files with 4679 additions and 332 deletions
+27 -6
View File
@@ -16,7 +16,6 @@ import (
"git.misaka.ren/m1saka/dsh-web/internal/backup"
"git.misaka.ren/m1saka/dsh-web/internal/store"
"golang.org/x/crypto/bcrypt"
)
const upgradeSnapshotLimit int64 = 1 << 30
@@ -52,10 +51,31 @@ func upgradeWorkspace(config, host map[string]json.RawMessage, recipe, home, sha
if homeIndex == -1 {
return errors.New("instance home mount required")
}
if !supportedLayout(recipe) {
return errors.New("unsupported template layout")
}
if recipe != "7" {
if get(mounts[homeIndex], "Target") == "/workspace" {
return errors.New("workspace home requires template 7")
return errors.New("workspace home cannot be downgraded to legacy shared layout")
}
if sharedIndex == -1 || get(mounts[sharedIndex], "Target") != "/workspace" {
return errors.New("legacy shared workspace mount required")
}
var env []string
if raw := config["Env"]; len(raw) != 0 {
if err := json.Unmarshal(raw, &env); err != nil {
return err
}
}
kept := []string{}
for _, entry := range env {
key, _, _ := strings.Cut(entry, "=")
if key != "DSH_HOME" && key != "HOME" && key != "XDG_DATA_HOME" && key != "XDG_CONFIG_HOME" {
kept = append(kept, entry)
}
}
kept = append(kept, "DSH_HOME=/data/dsh-home", "HOME=/data/dsh-home", "XDG_DATA_HOME=/data/dsh-home/.local/share", "XDG_CONFIG_HOME=/data/dsh-home/.config")
config["Env"], _ = json.Marshal(kept)
return nil
}
for _, key := range []string{"Binds", "VolumesFrom"} {
@@ -271,6 +291,7 @@ func (a *API) upgrade(w http.ResponseWriter, r *http.Request, i store.Instance)
Password string `json:"password"`
}
dec := json.NewDecoder(http.MaxBytesReader(w, r.Body, 64<<10))
dec.DisallowUnknownFields()
if dec.Decode(&in) != nil || !runtimeImageID.MatchString(in.ImageID) || dec.Decode(new(any)) != io.EOF {
fail(w, 400, "invalid image_id")
return
@@ -286,6 +307,8 @@ func (a *API) upgrade(w http.ResponseWriter, r *http.Request, i store.Instance)
}
user := a.userLocks.Acquire(i.UID)
defer user.Release()
admissionMu.RLock()
defer admissionMu.RUnlock()
current, err := a.s.GetInstance(i.ID)
if err != nil || current.UID != i.UID {
fail(w, 404, "not found")
@@ -296,9 +319,7 @@ func (a *API) upgrade(w http.ResponseWriter, r *http.Request, i store.Instance)
fail(w, 400, "login password required for pre-upgrade backup")
return
}
var passwordHash string
if a.s.DB.QueryRow("SELECT pass_hash FROM users WHERE id=?", i.UID).Scan(&passwordHash) != nil || bcrypt.CompareHashAndPassword([]byte(passwordHash), []byte(in.Password)) != nil {
fail(w, 403, "incorrect login password")
if !a.reauthenticate(w, i.UID, in.Password) {
return
}
if a.upgradeRecoveryRequired(i) || i.Status == "error" {
@@ -337,7 +358,7 @@ func (a *API) upgrade(w http.ResponseWriter, r *http.Request, i store.Instance)
ID string `json:"Id"`
Config struct{ Labels map[string]string }
}
if a.docker.Do(ctx, "GET", "/images/"+url.PathEscape(in.ImageID)+"/json", nil, &image) != nil || image.ID != in.ImageID || image.Config.Labels["dsh-mgr.role"] != "runtime" || image.Config.Labels["dsh-mgr.recipe"] != imageRecipeRev || verified[image.ID] == "" || verified[image.ID] != image.Config.Labels["dsh-mgr.version"] {
if a.docker.Do(ctx, "GET", "/images/"+url.PathEscape(in.ImageID)+"/json", nil, &image) != nil || image.ID != in.ImageID || image.Config.Labels["dsh-mgr.role"] != "runtime" || !supportedLayout(image.Config.Labels["dsh-mgr.recipe"]) || verified[image.ID] == "" || verified[image.ID] != image.Config.Labels["dsh-mgr.version"] {
fail(w, 400, "local runtime image required")
return
}