From 84beefc406ccfa91e84b553f6bb350a6a69440fe Mon Sep 17 00:00:00 2001 From: tegwick Date: Fri, 9 Oct 2026 12:09:52 +0200 Subject: [PATCH] MASON-WP-0004-T02: 27/29 descriptions applied; clip to OpenBao's byte limit Founder run 4 merged 27 accepted descriptions. Two failed with HTTP 400: used_by was 514 bytes because clipping counted characters and appended a 3-byte ellipsis. Clip and check now count bytes; manifest re-clipped. Co-Authored-By: Claude Opus 5.5 Assistant: claude-code Assistant-Model: opus Assistant-Process: 327203@bnt-lap001 Assistant-Session: 55028ae3-4914-4bd1-8f5c-815f3527aef0 --- manifests/custody-descriptions.yaml | 4 ++-- scripts/custody-describe.py | 8 ++++++-- tests/test_custody_describe.py | 6 ++++-- .../MASON-WP-0004-credential-inventory-descriptions.md | 8 ++++++++ 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/manifests/custody-descriptions.yaml b/manifests/custody-descriptions.yaml index 8c5639a..d561577 100644 --- a/manifests/custody-descriptions.yaml +++ b/manifests/custody-descriptions.yaml @@ -138,7 +138,7 @@ platform/workloads/core-hub/forgejo-source-read: feeding ExternalSecret core-hub/repo-manager-forgejo-source, which materializes Secret repo-manager-forgejo-source with the single key token (remoteRef workloads/core-hub/forgejo-source-read property FORGEJO_SOURCE_TOKEN), explicit empty target metadata template, creationPolicy Owner, deletionPolicy Retain. rapp-core-hub - then sets publisher.existingSecret to repo-manager-forgejo-source with tokenKey token. Both ma… + then sets publisher.existingSecret to repo-manager-forgejo-source with tokenKey token. Both ma platform/workloads/core-hub/runtime: description: Project the existing Core Hub protected-API token into the private railiance01 runtime through a namespace-limited ExternalSecret while preserving the token across the relocation window. @@ -458,7 +458,7 @@ platform/workloads/secrets-engine/approval-client: sso/keycape-secrets-engine-approval-client and Secret sso/keycape-secrets-engine-approval-client with key client-secret. KeyCape resolves it as KEYCAPE_SECRETS_ENGINE_APPROVAL_CLIENT_SECRET through a secretKeyRef, matching the live KEYCAPE_RAPP_QONTO_CLIENT_SECRET shape observed on image main-153258b. - Manifests: argocd/platform-addons/openbao-secretstore/openbao-keycape-approval-clients.clustersecretstor…' + Manifests: argocd/platform-addons/openbao-secretstore/openbao-keycape-approval-clients.clustersecretstor' platform/workloads/secrets-engine/approval-requester: description: T03 create-only requester KeyCape verifier custody; execute only the three fixed T03 request records. diff --git a/scripts/custody-describe.py b/scripts/custody-describe.py index ae59e80..580f0c8 100755 --- a/scripts/custody-describe.py +++ b/scripts/custody-describe.py @@ -36,8 +36,12 @@ PROPOSALS = os.path.join(os.path.dirname(__file__), "..", "docs", "credential-ow def _clip(text: str | None) -> str: + """Fit OpenBao's custom_metadata limit, which counts bytes, not characters.""" text = " ".join(str(text or "").split()) - return text if len(text) <= MAX_VALUE else text[: MAX_VALUE - 1] + "…" + if len(text.encode()) <= MAX_VALUE: + return text + cut = text.encode()[: MAX_VALUE - 3].decode(errors="ignore") + return cut + "..." def _first_sentence(text: str | None) -> str: @@ -111,7 +115,7 @@ def check(doc: dict) -> int: bad = 0 for path, e in doc.items(): missing = [k for k in REQUIRED if not e.get(k)] - long = [k for k in REQUIRED if len(str(e.get(k, ""))) > MAX_VALUE] + long = [k for k in REQUIRED if len(str(e.get(k, "")).encode()) > MAX_VALUE] state = e.get("review") if missing or long or state != "accepted": bad += 1 diff --git a/tests/test_custody_describe.py b/tests/test_custody_describe.py index d357afb..58307ce 100644 --- a/tests/test_custody_describe.py +++ b/tests/test_custody_describe.py @@ -66,8 +66,10 @@ def test_check_refuses_drafts_missing_and_overlong_fields(): assert cd.check({"p/ok": doc["p/ok"]}) == 0 -def test_clip_respects_openbao_value_limit(): - assert len(cd._clip("y" * 2000)) == cd.MAX_VALUE +def test_clip_respects_openbao_byte_limit(): + assert len(cd._clip("y" * 2000).encode()) <= cd.MAX_VALUE + assert len(cd._clip("→" * 400).encode()) <= cd.MAX_VALUE + assert cd.check({"p/x": {"review": "accepted", **dict(FULL, used_by="y" * 510 + "…")}}) == 1 def test_receipt_ignores_temporary_home_and_bao_addr_defaults(tmp_path, monkeypatch): diff --git a/workplans/MASON-WP-0004-credential-inventory-descriptions.md b/workplans/MASON-WP-0004-credential-inventory-descriptions.md index 9564532..7036ea9 100644 --- a/workplans/MASON-WP-0004-credential-inventory-descriptions.md +++ b/workplans/MASON-WP-0004-credential-inventory-descriptions.md @@ -122,6 +122,14 @@ then read `~/.local/state/railiance/receipts/custody-describe.json`. (First attempt 2026-10-09 refused by the wrapper because apply printed status lines; nothing written, all entries were still drafts. apply is now silent.) +2026-10-09 founder runs 3-4: the wrapper has a temporary HOME and the admin +policy has no `patch` capability, so apply now writes its receipt under the +real home and falls back to metadata get + merged put. Run 4 receipt: 27 of 29 +accepted entries `merged` (existing custom_metadata kept), 2 `failed put +http=400` (`core-hub/forgejo-source-read`, `secrets-engine/approval-client`): +`used_by` was 514 bytes, clipped by characters. Clipping is now by bytes; those +two need one more run. + ## Resolve the rest with their owners ```task