Implement authenticated custody observations and durable root-grant baseline
Some checks failed
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 27s
Account journey acceptance / journeys (push) Failing after 6s

Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a1029d-2c93-7500-a0e0-e3e089668b29
This commit is contained in:
tegwick 2026-10-03 19:50:15 +02:00
parent 1999a144c9
commit 0d0751d39d
18 changed files with 1129 additions and 14 deletions

View file

@ -62,8 +62,25 @@ class AccountAuthorityTests(unittest.TestCase):
self.store.find_identity = checked
with self.assertRaises(AuthorizationDenied): self.lookup()
def test_custody_mapping_only_after_independent_authorization(self):
calls = []
class Custody:
def observe(inner, **values):
calls.append(values)
return {"fixture": "observed-fact"} if values["tenant"] == "platform" else None
self.service.custody = Custody()
result = self.lookup(tenant="platform")
self.assertEqual(result.root_grant, {"fixture": "observed-fact"})
self.assertEqual(calls[-1], {"issuer": self.session.actor.issuer, "subject": self.session.actor.subject, "tenant": "platform"})
self.policy.effect = AuthorizationEffect.DENY
with self.assertRaises(AuthorizationDenied):
self.lookup(tenant="platform")
self.assertEqual(len(calls), 1)
def test_does_not_emit_root_grants_or_profile_details(self):
result = self.lookup()
self.assertIsNone(result.root_grant)
self.assertFalse(hasattr(result,'root_entitled'))
self.assertFalse(hasattr(result,'roles'))
self.assertFalse(hasattr(result,'primary_email'))

View file

@ -8,12 +8,7 @@ from datetime import datetime, timedelta, timezone
from user_engine.custody import CustodyBaseline, CustodyObservationAdapter, CustodyRead
CANON = Path(__file__).resolve().parents[2] / "net-kingdom/tools/custody-record"
try:
spec = importlib.util.spec_from_file_location("custody_canon", CANON / "validate.py")
policy = importlib.util.module_from_spec(spec)
spec.loader.exec_module(policy)
except (FileNotFoundError, ModuleNotFoundError):
policy = None
from user_engine.custody_canon import policy
class Baselines:
@ -31,7 +26,7 @@ class Baselines:
return True
@unittest.skipIf(policy is None, "optional sibling NetKingdom validator/jsonschema absent")
@unittest.skipUnless(CANON.exists(), "optional sibling NetKingdom fixtures absent")
class CustodyAdapterTests(unittest.TestCase):
def setUp(self):
self.document = json.loads((CANON / "fixtures/valid/grant.json").read_text())
@ -106,6 +101,14 @@ class CustodyAdapterTests(unittest.TestCase):
self.assertIsNone(self.observe())
self.assertIsNone(self.baselines.value)
def test_check_clock_sampled_after_owner_read(self):
self.adapter.clock = lambda: self.now + timedelta(seconds=2)
self.read_at = self.now + timedelta(seconds=1)
result = self.adapter.observe(**self.subject, tenant="platform")
self.assertIsNotNone(result)
self.assertEqual(result["observed_at"], self.read_at.isoformat().replace("+00:00", "Z"))
def test_bootstrap_and_persistence_conflict_deny(self):
self.adapter.allow_initial_baseline = False
self.assertIsNone(self.observe())

View file

@ -0,0 +1,33 @@
import hashlib
import json
import unittest
import test_custody_adapter as adapter_fixtures
CANON = adapter_fixtures.CANON
from user_engine.custody_bootstrap import initialize_baseline
@unittest.skipUnless(CANON.exists(), "optional sibling fixtures absent")
class CustodyBootstrapTests(unittest.TestCase):
def setUp(self):
self.fixture = adapter_fixtures.CustodyAdapterTests()
self.fixture.setUp()
self.fixture.adapter.clock = lambda: self.fixture.now
self.digest = hashlib.sha256(json.dumps(self.fixture.document, sort_keys=True, separators=(",", ":"), ensure_ascii=True).encode()).hexdigest()
def test_authenticated_receipt_match_initializes_once(self):
self.assertTrue(initialize_baseline(self.fixture.adapter, expected_sha256=self.digest))
self.assertFalse(initialize_baseline(self.fixture.adapter, expected_sha256=self.digest))
self.assertEqual(self.fixture.reads, 1)
def test_wrong_receipt_and_failure_do_not_seed_baseline(self):
self.assertFalse(initialize_baseline(self.fixture.adapter, expected_sha256="0" * 64))
self.fixture.failure = True
self.assertFalse(initialize_baseline(self.fixture.adapter, expected_sha256=self.digest))
self.assertIsNone(self.fixture.baselines.value)
def test_empty_approved_document_initializes_no_grant(self):
self.fixture.document["entries"] = []
digest = hashlib.sha256(json.dumps(self.fixture.document, sort_keys=True, separators=(",", ":"), ensure_ascii=True).encode()).hexdigest()
self.assertTrue(initialize_baseline(self.fixture.adapter, expected_sha256=digest))
self.assertIsNone(self.fixture.observe())

View file

@ -0,0 +1,14 @@
import hashlib
from importlib.resources import files
import json
import unittest
from user_engine.custody_canon import policy
class CustodyPolicyPackageTests(unittest.TestCase):
def test_pinned_policy_and_schema_integrity(self):
package = files("user_engine.custody_canon")
receipt = json.loads(package.joinpath("provenance.json").read_text())
self.assertEqual(hashlib.sha256(package.joinpath("policy.py").read_bytes()).hexdigest(), receipt["packaged_policy_sha256"])
self.assertEqual(hashlib.sha256(package.joinpath("custody-record_v0.1.schema.json").read_bytes()).hexdigest(), receipt["schema_sha256"])
self.assertEqual(policy.load_schema()["$id"], "https://policy.coulomb.social/schemas/custody-record/v0.1")

View file

@ -0,0 +1,130 @@
import io
import json
from pathlib import Path
import tempfile
import unittest
from datetime import datetime, timezone
from urllib.error import HTTPError
from user_engine.custody_runtime import OpenBaoCustodyReader, CustodyReadUnavailable
class Response(io.BytesIO):
def __init__(self, value, *, headers=None):
super().__init__(json.dumps(value).encode())
self.headers = headers or {}
self.status = 200
class Opener:
def __init__(self, responses):
self.responses, self.requests = list(responses), []
def open(self, request, timeout):
self.requests.append((request, timeout))
response = self.responses.pop(0)
if isinstance(response, Exception):
raise response
return response
class CustodyTransportTests(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory()
self.addCleanup(self.temp.cleanup)
self.jwt = Path(self.temp.name) / "token"
self.jwt.write_text("fixture-jwt\n")
self.now = datetime.now(timezone.utc)
self.document = {"revision": 4}
def reader(self, opener, **options):
return OpenBaoCustodyReader(base_url="https://bao.example", auth_mount="kubernetes",
role="user-engine-root-custody-reader", jwt_file=str(self.jwt), source_id="trusted",
opener=opener, clock=lambda: self.now, **options)
def login(self):
return Response({"auth": {"client_token": "fixture-reader-token"}})
def test_dedicated_login_fresh_exact_read_and_revoke(self):
opener = Opener([self.login(), Response({"data": {"data": {"document": self.document}}}), Response({})])
result = self.reader(opener).read()
self.assertEqual(result.document, self.document)
self.assertEqual(result.read_at, self.now)
login, read, revoke = [entry[0] for entry in opener.requests]
self.assertEqual(json.loads(login.data), {"role": "user-engine-root-custody-reader", "jwt": "fixture-jwt"})
self.assertEqual(read.full_url, "https://bao.example/v1/platform/data/custody/net-kingdom/platform-root")
self.assertEqual(read.get_header("X-vault-token"), "fixture-reader-token")
self.assertTrue(revoke.full_url.endswith("auth/token/revoke-self"))
self.assertTrue(all(0 < timeout <= 3 for _, timeout in opener.requests))
def test_owner_denial_errors_are_suppressed(self):
opener = Opener([HTTPError("https://secret-value.invalid", 403, "sensitive", {}, None)])
with self.assertRaises(CustodyReadUnavailable) as error:
self.reader(opener).read()
self.assertEqual(str(error.exception), "custody read unavailable")
self.assertIsNone(error.exception.__cause__)
def test_cache_hit_malformed_and_oversized_responses_deny(self):
for response in (Response({"data": {}}, headers={"Age": "1"}), Response({"wrong": "envelope"}),
Response({"data": {"data": {"document": {"padding": "x" * 2000}}}})):
opener = Opener([self.login(), response, Response({})])
with self.assertRaises(CustodyReadUnavailable):
self.reader(opener, max_bytes=1024).read()
def test_token_rotation_is_read_from_file_each_login(self):
opener = Opener([self.login(), Response({"data": {"data": {"document": self.document}}}), Response({}),
self.login(), Response({"data": {"data": {"document": self.document}}}), Response({})])
reader = self.reader(opener)
reader.read()
self.jwt.write_text("rotated-fixture-jwt")
reader.read()
self.assertEqual(json.loads(opener.requests[3][0].data)["jwt"], "rotated-fixture-jwt")
def test_plaintext_untrusted_origin_and_path_are_configuration_errors(self):
for origin in ("http://bao.example", "https://user:pass@bao.example", "https://bao.example/path"):
with self.assertRaises(ValueError):
OpenBaoCustodyReader(base_url=origin, auth_mount="kubernetes", role="reader", jwt_file="fixture", source_id="source")
with self.assertRaises(ValueError):
self.reader(Opener([]), data_path="platform/data/other")
class CustodyNestedIntegrationTests(unittest.TestCase):
def test_nested_owner_response_to_serialized_account_authority(self):
from datetime import timedelta
from dataclasses import replace
from user_engine.adapters.local import InMemoryUserEngineStore
from user_engine.custody import CustodyObservationAdapter
from user_engine.custody_canon import policy
from user_engine.service import UserEngineService
from user_engine.testing.fixtures import FixtureIdentityClaimsAdapter, StaticAuthorizationCheckPort, human_actor_claims
from user_engine.web import _jsonable
from test_custody_adapter import Baselines, CANON
if not CANON.exists():
self.skipTest("optional sibling fixtures absent")
document = json.loads((CANON / "fixtures/valid/grant.json").read_text())
now = datetime(2026, 10, 3, 12, tzinfo=timezone.utc)
claims = human_actor_claims()
claims.update(iss=document["entries"][0]["subject"]["issuer"], sub=document["entries"][0]["subject"]["subject"], tenant="platform")
with tempfile.TemporaryDirectory() as directory:
jwt_file = Path(directory) / "token"
jwt_file.write_text("fixture-openbao-audience-jwt")
opener = Opener([Response({"auth": {"client_token": "fixture-token"}}),
Response({"data": {"data": {"document": document}}}), Response({})])
source = "https://bao.example/v1/platform/data/custody/net-kingdom/platform-root#auth=kubernetes/user-engine-root-custody-reader"
reader = OpenBaoCustodyReader(base_url="https://bao.example", auth_mount="kubernetes",
role="user-engine-root-custody-reader", jwt_file=str(jwt_file), source_id=source,
opener=opener, clock=lambda: now)
adapter = CustodyObservationAdapter(reader=reader, baselines=Baselines(), policy=policy,
source_id=source, record_id=document["record_id"], allow_initial_baseline=True,
clock=lambda: now + timedelta(milliseconds=1))
service = UserEngineService(store=InMemoryUserEngineStore(), identity_adapter=FixtureIdentityClaimsAdapter(),
authorization=StaticAuthorizationCheckPort(), custody=adapter)
session = service.me(claims)
result = service.lookup_account_authority(replace(session.actor, subject="fixture-hub-reader"),
issuer=claims["iss"], subject=claims["sub"], tenant="platform")
envelope = _jsonable(result)
observation = envelope["root_grant"]
self.assertEqual(observation["source"], {"record_id": document["record_id"], "revision": 1})
self.assertEqual(observation["subject"], document["entries"][0]["subject"])
self.assertEqual(observation["observed_at"], "2026-10-03T12:00:00Z")
self.assertEqual(observation["expires_at"], "2026-10-03T12:15:00Z")
self.assertEqual(opener.requests[1][0].full_url, "https://bao.example/v1/platform/data/custody/net-kingdom/platform-root")