controller v0.242.0: a removed app is listed with its kept backup; five small ones (R-487 R-491 R-490 R-489 R-476 R-456)
gates / gates (push) Successful in 14s
gates / gates (push) Successful in 14s
R-487: the local backup lists are keyed on the drives, not on what is deployed — a removed app whose unit was kept is listed with the restore that reinstalls it, the picker answers for it, and the restore opens the unit where it sits. R-491: a removal clears the app's update hold. R-490: /api/system/info reaches the API router and reads the default storage path. R-489: volumes_removed is the real before/after difference, [] when none. R-476: a Tier-2 copy is dated by its data, not its manifest. R-456: the boot-orphan rule is pinned. Every fix red-proofed.
This commit is contained in:
@@ -1747,6 +1747,10 @@ func main() {
|
||||
mux.Handle("/api/sharing/", webServer.RequireAuth(webServer.CsrfProtect(http.HandlerFunc(webServer.ServeSharingAPI))))
|
||||
// Guest RAM resize (v0.143.0, R-24): read current allocation/bounds + apply a bounded resize.
|
||||
mux.Handle("/api/system/", webServer.RequireAuth(webServer.CsrfProtect(http.HandlerFunc(webServer.ServeSystemAPI))))
|
||||
// R-490 (v0.242.0): the web layer's /api/system/ prefix knows only the memory routes and answered
|
||||
// 404 to /api/system/info, so the monitoring page's memory-distribution card never rendered. An
|
||||
// exact pattern wins over the prefix in ServeMux. Pinned by TestR490_SystemInfoIsMountedAheadOfTheWebPrefix.
|
||||
mux.Handle("/api/system/info", webServer.RequireAuth(webServer.CsrfProtect(http.HandlerFunc(apiRouter.ServeHTTP))))
|
||||
// Standalone full-server (guest) restart — the "Kiszolgáló újraindítása" maintenance affordance,
|
||||
// a sibling to the controller-only /api/selfrestart. Reuses the agent GuestReboot primitive.
|
||||
mux.Handle("/api/server/reboot", webServer.RequireAuth(webServer.CsrfProtect(http.HandlerFunc(webServer.HandleServerReboot))))
|
||||
|
||||
@@ -73,3 +73,52 @@ func TestR475_AdapterReadsEveryTier(t *testing.T) {
|
||||
t.Errorf("the hold must carry UpdateCopyHolds through HoldAfterFailedUpdateHolding (R-479); selectors:%s", h)
|
||||
}
|
||||
}
|
||||
|
||||
// R-490 — /api/system/info reaches the API router; the web layer's /api/system/ prefix used to eat it.
|
||||
//
|
||||
// COMPANION RED-PROOF (REPORT.md): delete the exact-path mount — this fails.
|
||||
func TestR490_SystemInfoIsMountedAheadOfTheWebPrefix(t *testing.T) {
|
||||
src, err := parser.ParseFile(token.NewFileSet(), "main.go", nil, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var exact, prefix bool
|
||||
ast.Inspect(src, func(n ast.Node) bool {
|
||||
call, ok := n.(*ast.CallExpr)
|
||||
if !ok || len(call.Args) < 2 {
|
||||
return true
|
||||
}
|
||||
sel, ok := call.Fun.(*ast.SelectorExpr)
|
||||
if !ok || sel.Sel.Name != "Handle" {
|
||||
return true
|
||||
}
|
||||
lit, ok := call.Args[0].(*ast.BasicLit)
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
switch lit.Value {
|
||||
case `"/api/system/info"`:
|
||||
exact = strings.Contains(fmtNode(call.Args[1]), "apiRouter")
|
||||
case `"/api/system/"`:
|
||||
prefix = true
|
||||
}
|
||||
return true
|
||||
})
|
||||
if !prefix {
|
||||
t.Fatal("the /api/system/ prefix mount is gone — this test's premise moved")
|
||||
}
|
||||
if !exact {
|
||||
t.Error("/api/system/info must be mounted on the API router ahead of the web layer's /api/system/ prefix (R-490)")
|
||||
}
|
||||
}
|
||||
|
||||
func fmtNode(n ast.Node) string {
|
||||
var names []string
|
||||
ast.Inspect(n, func(x ast.Node) bool {
|
||||
if id, ok := x.(*ast.Ident); ok {
|
||||
names = append(names, id.Name)
|
||||
}
|
||||
return true
|
||||
})
|
||||
return strings.Join(names, " ")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user