forgectrl.panel-serves: the page lets no frame navigate

The panel page now carries Content-Security-Policy: frame-src 'none'
(forgectrl 95970cf), the one thing that keeps a package's page from
navigating its own frame to another address with what it was shown in
the URL. What the header does in each browser is the frame-isolation
harness's to prove (forgectrl tools/frame_isolation.py); this test holds
the machine's own served page to carrying it, read with the headers from
the loopback listener. The edit is inside the test's own function, so no
other test's fingerprint moves.

Proof: on the bench reference, image 20260922225653, PASS with forgectrl
95970cf bind-mounted ("GET / Content-Security-Policy: frame-src 'none'"),
and FAIL against the image's own daemon: "the panel page lets a frame
navigate: 200 None".
This commit is contained in:
ScottW514
2026-09-22 20:00:38 -04:00
parent 1bdc11f6fe
commit d9cc61f198
+12 -1
View File
@@ -322,7 +322,12 @@ def settings_bounds(ctx):
("forgectrl", "src/cam.c"), ("forgectrl", "src/main.c"), ("forgectrl", "src/super.c"),
("grblhal-glowforge", "src/glowforge_status.c"), ("grblhal-glowforge", "src/serial.c"),
("forgectrl", "src/curverec.*")],
description="The panel page is served, /status carries the machine telemetry the panel and "
description="The panel page is served, with a policy that lets no frame navigate anywhere "
"(frame-src 'none': a package's page renders in a frame of it, and a frame that "
"could go to another address could carry what it was shown in the URL; what the "
"header does in each browser is the frame-isolation harness's to prove, and this "
"holds the machine's own page to carrying it), /status carries the machine "
"telemetry the panel and "
"the acceptance tool read (including the sys block: CPU busy percent over the "
"interval since the previous read, memory used percent; and homed_axes, "
"the axes that carry a reference, Z alone once the lens has taken its "
@@ -350,6 +355,12 @@ def panel_serves(ctx):
# the head script sets and the one save bar every settings tab shares.
ctx.check("data-bs-theme" in text, "the panel lacks the theme attribute (inflate failed?)")
ctx.check('id="savebar"' in text, "the panel lacks the save bar")
from .setup import request
st_h, _page, hdrs = request(fc.base, "GET", "/", headers={"Host": fc.host_header()})
ev["page_policy"] = hdrs.get("content-security-policy")
ctx.log("GET / Content-Security-Policy: %s", ev["page_policy"])
ctx.check(st_h == 200 and "frame-src 'none'" in (ev["page_policy"] or ""),
"the panel page lets a frame navigate: %s %r", st_h, ev["page_policy"])
s = fc.status()
for key in ("state", "switches", "coolant", "fans"):