mirror of
https://github.com/openglow-org/forgefirm.git
synced 2026-09-27 08:41:13 -07:00
forgetest: exthost.catalog on the catalog's own repository and its judged index
The address is the catalog repository's index-1.ffi. On the scratch root the index lists the probe in two versions: 1.1.0 asks for a capability no firmware has, and read back it is kept and not offered, the offer being 1.0.0. An older index is refused however well signed, and the one kept stays. An index withdrawing the probe's 1.0.0 makes inspect refuse it in OpenGlow's words. GET /ext/catalog carries core_checked. The covers widen from forgeext src/install.c to src/install.*. The test still never requests the index's address. Its own module (suite/extcat.py), so only exthost.catalog's fingerprint moves. forgetest's 500 unit tests pass; the function was read against _forgeext, fc.get and fc.post, and ctx.check, since no host test runs a suite function.
This commit is contained in:
@@ -5,10 +5,12 @@
|
||||
|
||||
"""The catalog: the signed index, on the machine.
|
||||
|
||||
Its own module, for the reason extcore.py gives. The endorsement is shown
|
||||
on a scratch root under /tmp with a throwaway key standing in for the
|
||||
OpenGlow extension key, because only OpenGlow holds the real one; the
|
||||
machine's own root is where every index that key did not sign is refused.
|
||||
Its own module, for the reason extcore.py gives. The endorsement, the
|
||||
judgment of each listed version, the index that never goes back, and a
|
||||
withdrawn version are shown on a scratch root under /tmp with a throwaway
|
||||
key standing in for the OpenGlow extension key, because only OpenGlow holds
|
||||
the real one; the machine's own root is where every index that key did not
|
||||
sign is refused.
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
@@ -23,7 +25,7 @@ import tempfile
|
||||
from ..catalog import test
|
||||
from .exthost import FWUP, _forgeext, _write
|
||||
|
||||
INDEX_URL = "https://github.com/openglow-org/forgefirm-extensions/releases/latest/download/index.ffi"
|
||||
INDEX_URL = "https://github.com/openglow-org/forgefirm-extensions-catalog/releases/latest/download/index-1.ffi"
|
||||
STAGE_DIR = "/data/forgefirm/tmp"
|
||||
PROBE_ID, OTHER_ID = "org.example.catprobe", "org.example.catother"
|
||||
|
||||
@@ -58,9 +60,8 @@ def _package(work, id_, key):
|
||||
return _archive(work, id_, "ForgeFIRM extension", {"manifest.json": json.dumps(m)}, "1.0.0", key)
|
||||
|
||||
|
||||
def _index(work, entries, key):
|
||||
return _archive(work, "index", "ForgeFIRM extension index", {"index.json": json.dumps({"index": 1, "packages": entries})},
|
||||
"2026.9.23", key)
|
||||
def _index(work, doc, key, version):
|
||||
return _archive(work, "index-" + version, "ForgeFIRM extension index", {"index.json": json.dumps(doc)}, version, key)
|
||||
|
||||
|
||||
def _staged():
|
||||
@@ -70,24 +71,28 @@ def _staged():
|
||||
return []
|
||||
|
||||
|
||||
@test("exthost.catalog", title="The catalog: the signed index verified, kept, and endorsing one key for one id",
|
||||
@test("exthost.catalog", title="The catalog: the signed index verified, kept, judged, and endorsing one key for one id",
|
||||
subsystem="exthost", kind="auto", hardware="api", est_min=2,
|
||||
covers=[("forgectrl", "src/extpkg.*"), ("forgectrl", "src/main.c"), ("forgeext", "src/index.*"),
|
||||
("forgeext", "src/pkg.*"), ("forgeext", "src/install.c"), ("forgeext", "src/main.c")],
|
||||
description="GET /ext/catalog answers the index the host keeps (or null) and the one address it is fetched "
|
||||
"from. On a scratch root, with a throwaway key standing in for the OpenGlow extension key, the "
|
||||
"machine's own forgeext keeps an index signed with it, and the author key it names for one id "
|
||||
"makes a package of that id signed with it read as community and endorsed, where before it was "
|
||||
"unverified; the same key on another id counts for nothing. On the machine's own root, that "
|
||||
"index (signed by a key that is not the OpenGlow extension key) is refused in words, a package "
|
||||
"handed over as an index is refused by the product gate, and the index kept is left as it was. "
|
||||
"POST /ext/catalog/get refuses an id with no such form (400), and one the kept index does not "
|
||||
"list (404, or 409 with no index kept), before anything is fetched. Nothing is left in the "
|
||||
"staging directory. POST /ext/catalog/refresh is not asked here: GitHub counts every request "
|
||||
"of the index's address as a download, and that count is the operators'. The refresh (curl, "
|
||||
"https alone and bounded, 502 in curl's words, 409 in the host's, the file removed), the fetch "
|
||||
"of a listed package held to its size and SHA-256, and the tiers an install takes from it, "
|
||||
"are forgectrl's extpkg_test and forgeext's install_test.")
|
||||
("forgeext", "src/pkg.*"), ("forgeext", "src/install.*"), ("forgeext", "src/main.c")],
|
||||
description="GET /ext/catalog answers the index the host keeps (or null), judged against this firmware, and "
|
||||
"the one address it is fetched from. On a scratch root, with a throwaway key standing in for the "
|
||||
"OpenGlow extension key, the machine's own forgeext keeps an index signed with it, and the author "
|
||||
"key it names for one id makes a package of that id signed with it read as community and "
|
||||
"endorsed, where before it was unverified; the same key on another id counts for nothing. Read "
|
||||
"back, each listed version is judged on the machine: one that asks for a capability this "
|
||||
"firmware does not have is kept and not offered, and the offer is the newest it runs. An index "
|
||||
"older than the one kept is refused however well signed, and one that withdraws the probe's "
|
||||
"version makes the machine refuse to install it, in OpenGlow's words. On the machine's own root, "
|
||||
"the stand-in's index (signed by a key that is not the OpenGlow extension key) is refused in "
|
||||
"words, a package handed over as an index is refused by the product gate, and the index kept "
|
||||
"is left as it was. POST /ext/catalog/get refuses an id with no such form (400), and one the "
|
||||
"kept index does not list (404, or 409 with no index kept), before anything is fetched. Nothing "
|
||||
"is left in the staging directory. POST /ext/catalog/refresh is not asked here: GitHub counts "
|
||||
"every request of the index's address as a download, and that count is the operators'. The "
|
||||
"refresh (curl, https alone and bounded, 502 in curl's words, 409 in the host's, the file "
|
||||
"removed), the fetch of the offered version held to its size and SHA-256, and the tiers an "
|
||||
"install takes from it, are forgectrl's extpkg_test and forgeext's install_test.")
|
||||
def catalog(ctx):
|
||||
fc = ctx.forgectrl
|
||||
ev = ctx.evidence
|
||||
@@ -100,7 +105,8 @@ def catalog(ctx):
|
||||
try:
|
||||
st, doc = fc.get("/ext/catalog")
|
||||
ctx.check(st == 200 and isinstance(doc, dict) and doc.get("url") == INDEX_URL and "index" in doc
|
||||
and doc.get("index") == kept.get("index"), "GET /ext/catalog -> %s %s", st, doc)
|
||||
and doc.get("index") == kept.get("index") and "core_checked" in doc,
|
||||
"GET /ext/catalog -> %s %s", st, doc)
|
||||
|
||||
# The endorsement, on a scratch root with a stand-in for the OpenGlow extension key.
|
||||
root = os.path.join(work, "root")
|
||||
@@ -111,9 +117,13 @@ def catalog(ctx):
|
||||
data = f.read()
|
||||
with open(author + ".pub") as f:
|
||||
author_pub = f.read().strip()
|
||||
idx = _index(work, [{"id": PROBE_ID, "name": "catalog probe", "author": "forgetest", "version": "1.0.0",
|
||||
"url": "https://example.org/catprobe.ffx", "sha256": hashlib.sha256(data).hexdigest(),
|
||||
"size": len(data), "capabilities": [], "key": author_pub}], og)
|
||||
listed = {"version": "1.0.0", "url": "https://example.org/catprobe.ffx", "sha256": hashlib.sha256(data).hexdigest(),
|
||||
"size": len(data), "capabilities": [], "api": "0.1"}
|
||||
later = dict(listed, version="1.1.0", url="https://example.org/catprobe-1.1.0.ffx",
|
||||
capabilities=["forgetest.not-a-capability"])
|
||||
entry = {"id": PROBE_ID, "name": "catalog probe", "author": "forgetest", "key": author_pub,
|
||||
"versions": [later, listed]}
|
||||
idx = _index(work, {"index": 1, "packages": [entry]}, og, "2026.923.2")
|
||||
|
||||
def scratch(*args):
|
||||
return _forgeext("--root", root, "--official-key", og + ".pub", "--no-reserve", *args)
|
||||
@@ -121,10 +131,17 @@ def catalog(ctx):
|
||||
ctx.check(r.get("ok") is True and r.get("tier") == "unverified", "before an index: %s %s", r.get("tier"), r.get("error"))
|
||||
r = scratch("index-verify", idx)
|
||||
ev["scratch_verify"] = r
|
||||
ctx.check(r.get("ok") is True and r.get("packages") == 1 and r.get("version") == "2026.9.23",
|
||||
ctx.check(r.get("ok") is True and r.get("packages") == 1 and r.get("version") == "2026.923.2",
|
||||
"the stand-in's index is kept on the scratch root: %s", r)
|
||||
listed = ((scratch("index").get("index") or {}).get("packages") or [{}])[0]
|
||||
ctx.check(listed.get("id") == PROBE_ID and len(listed.get("key_id", "")) == 64, "and read back: %s", listed)
|
||||
read = scratch("index")
|
||||
mine = ((read.get("index") or {}).get("packages") or [{}])[0]
|
||||
vs = {v.get("version"): v for v in mine.get("versions", [])}
|
||||
ev["judged"] = {"offer": mine.get("offer"), "1.1.0": vs.get("1.1.0", {}).get("why"),
|
||||
"core_checked": read.get("core_checked")}
|
||||
ctx.check(mine.get("id") == PROBE_ID and len(mine.get("key_id", "")) == 64, "and read back: %s", mine)
|
||||
ctx.check(vs.get("1.1.0", {}).get("usable") is False and "not a capability" in vs.get("1.1.0", {}).get("why", "")
|
||||
and vs.get("1.0.0", {}).get("usable") is True and mine.get("offer") == "1.0.0",
|
||||
"judged on the machine: 1.1.0 kept and not offered, 1.0.0 offered: %s", ev["judged"])
|
||||
r = scratch("inspect", probe)
|
||||
ev["endorsed"] = {"tier": r.get("tier"), "endorsed": r.get("endorsed")}
|
||||
ctx.check(r.get("tier") == "community" and r.get("endorsed") is True,
|
||||
@@ -133,6 +150,21 @@ def catalog(ctx):
|
||||
ctx.check(r.get("tier") == "unverified" and r.get("endorsed") is False,
|
||||
"the same key on another id: %s %s", r.get("tier"), r.get("endorsed"))
|
||||
|
||||
# Never back: an older index is refused, and the one kept stays.
|
||||
r = scratch("index-verify", _index(work, {"index": 1, "packages": []}, og, "2026.923.1"))
|
||||
ev["older"] = r.get("error")
|
||||
ctx.check(r.get("ok") is False and "never goes back" in (r.get("error") or ""), "an older index -> %s", r.get("error"))
|
||||
ctx.check((scratch("index").get("index") or {}).get("version") == "2026.923.2", "and the one kept stays")
|
||||
|
||||
# A withdrawn version does not install, from the catalog or from anywhere else.
|
||||
gone = dict(entry, versions=[later], withdrawn=[{"version": "1.0.0", "reason": "forgetest withdrew it"}])
|
||||
r = scratch("index-verify", _index(work, {"index": 1, "packages": [gone]}, og, "2026.923.3"))
|
||||
ctx.check(r.get("ok") is True, "an index withdrawing the probe's version is kept: %s", r.get("error"))
|
||||
r = scratch("inspect", probe)
|
||||
ev["withdrawn"] = r.get("error")
|
||||
ctx.check(r.get("ok") is False and "OpenGlow withdrew %s 1.0.0 from its catalog: forgetest withdrew it" % PROBE_ID
|
||||
in (r.get("error") or ""), "the withdrawn version -> %s", r.get("error"))
|
||||
|
||||
# The machine's own root keeps no index but OpenGlow's.
|
||||
refused = {}
|
||||
for name, path, words in (("the stand-in's index", idx, "not signed with the OpenGlow extension key"),
|
||||
|
||||
Reference in New Issue
Block a user