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:
+27
-6
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user