exthost: the effective capability list, and a disabled package's page

exthost.package-routes reads the new `effective` field beside the
manifest's own list: what the package may use is never wider than what it
asked for, holds everything the operator granted, and the panel's list
and the host's own command line say the same thing. That is the list the
panel's bridge decides on, so it is the one the case has to hold.

exthost.ui-delivery gains the disabled package: its page is refused in
words, and served again once the operator enables it. Disabling a package
is the way out of everything it does, and its interface was the one door
that stayed open.

Both are changes inside the tests' own functions, so no other case's
fingerprint moves.
This commit is contained in:
ScottW514
2026-09-22 09:57:20 -04:00
parent 59887ac742
commit 5915408147
+37 -2
View File
@@ -1800,7 +1800,9 @@ def motion_jog(ctx):
description="A package that asks for ui must ship ui/index.html, and one that ships the file must "
"ask: the install refuses each of those the other way round, in words. With both, GET "
"/ext/ui hands the page back as a JSON string, byte for byte what the package shipped, "
"and a package that is not installed is refused. The page is a string in JSON and never "
"and a package that is not installed is refused, as is one the operator disabled - "
"disabling a package is the way out of everything it does, its interface included. "
"The page is a string in JSON and never "
"markup this daemon composed. Nothing runs and nothing moves: the machine is only asked "
"for files. The frame the panel builds around the page is a browser's to judge, and that "
"is exthost.ui-frame-isolation's, which is a browser harness and not this catalog.")
@@ -1856,6 +1858,20 @@ def ui_delivery(ctx):
st_, why = fc.get("/ext/ui", params={"id": "org.forgetest.nothere"})
ev["ui_absent"] = [st_, why]
ctx.check(st_ >= 400, "a package that is not installed -> %s %s", st_, why)
# Disabled, it has no page. Disabling a package is the operator's
# way out of everything it does, and the interface is part of
# that: the page reaches the machine through the panel's bridge,
# and a door that is shut is shut.
r = _forgeext("disable", REF_ID)
ctx.check(r.get("ok") is True, "disable -> %s", r.get("error"))
st_, why = fc.get("/ext/ui", params={"id": REF_ID})
ev["ui_disabled"] = [st_, why]
ctx.check(st_ >= 400 and "disabled" in json.dumps(why), "a disabled package's page -> %s %s", st_, why)
r = _forgeext("enable", REF_ID)
ctx.check(r.get("ok") is True, "enable -> %s", r.get("error"))
st_, doc = fc.get("/ext/ui", params={"id": REF_ID})
ctx.check(st_ == 200 and (doc or {}).get("ok"), "enabled again, its page is served -> %s", st_)
finally:
_put_back(ctx, fc, work, prior, etag, raw, dir_mode)
_as_found(ctx, fc, prior, raw, dir_mode, found_tree)
@@ -2009,7 +2025,9 @@ def motion_job(ctx):
description="Extensions stay as found (the package is installed and never runs). The reference package is "
"installed with the hold grant through the host's command line. GET /ext/status without "
"the login is refused (403); with it, it lists the package as the host does (tier "
"community, enabled, the hold advisory) beside enabled, safe_mode, and the host's own "
"community, enabled, the hold advisory, and the capabilities it may use - what needs no "
"grant and what the operator granted, which is what the panel's bridge decides on and "
"is never wider than what the manifest asked for) beside enabled, safe_mode, and the host's own "
"status with running true. POST /ext/package: hold-required names the package under "
"required-holds and the list says required; disable and enable change the host's state "
"file; an action outside the closed list and an id that has not the form of one are 400 "
@@ -2074,6 +2092,23 @@ def package_routes(ctx):
and pkg.get("grants") == ["hold"] and (pkg.get("package") or {}).get("name") == "forgetest reference",
"the package is not listed as the host lists it: %s", pkg)
# What the package may use, beside what it asked for. The panel's
# bridge decides on this list and not on the manifest's, so a
# capability the operator did not grant must not be in it.
asked = set((pkg.get("package") or {}).get("capabilities") or [])
effective = set(pkg.get("effective") or [])
granted = set(pkg.get("grants") or [])
ev["capabilities"] = {"asked": sorted(asked), "effective": sorted(effective), "granted": sorted(granted)}
ctx.log("the reference package asked for %s, may use %s", sorted(asked), sorted(effective))
ctx.check(effective and effective <= asked, "it may use what it did not ask for: %s", ev["capabilities"])
ctx.check(granted <= effective, "a capability the operator granted is not in what it may use: %s",
ev["capabilities"])
st, reply = act("hold-advisory") # no change; the grant stands either way
r = _forgeext("list", REF_ID)
host_eff = set(((r.get("packages") or [{}])[0]).get("effective") or [])
ctx.check(host_eff == effective, "the panel's list and the host's own do not agree: %s vs %s",
sorted(effective), sorted(host_eff))
st, reply = act("hold-required")
ctx.check(st == 200 and os.listdir(REQUIRED_HOLDS) == [REF_ID] and listed()[1].get("hold") == "required",
"hold-required -> %s, named %s", st, os.listdir(REQUIRED_HOLDS))