kv_duplicate_retire: block only on data-path grants
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

The founder dry-run refused on mount-wide platform/metadata/* grants held by
ops-mason-survey and platform-readonly. Those cannot read the value, so they
are now recorded as metadata_only_policies and no longer block retirement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 469992@bnt-lap001
Assistant-Session: e4b8e420-df0a-441d-83ae-7f19130594d9
This commit is contained in:
codex 2026-10-09 12:27:43 +02:00
parent bed91ceaf2
commit 64ae5946d9
2 changed files with 19 additions and 4 deletions

View file

@ -10,7 +10,10 @@ no source references it. Before the metadata delete this process proves:
* the canonical entry exists with a live current version;
* the duplicate exists with exactly the expected version count;
* no live ACL policy other than platform-admin grants a non-deny capability on
the duplicate's data or metadata path (exact, ``+`` and trailing ``*`` globs).
the duplicate's data path (exact, ``+`` and trailing ``*`` globs). Grants on
the metadata path only (e.g. mount-wide ``platform/metadata/*`` survey and
read-only inventory policies) cannot read the value, so they are recorded in
the receipt as ``metadata_only_policies`` but do not block.
No value is read. Run from a railiance-platform checkout:
@ -103,18 +106,24 @@ def run(args, receipt):
if duplicate.get('current_version') != EXPECTED_VERSIONS or receipt['duplicate_versions'] != EXPECTED_VERSIONS:
raise Exit(2, 'duplicate_version_unexpected')
paths = ['platform/data/' + DUPLICATE, 'platform/metadata/' + DUPLICATE]
granting = {}
data_path, metadata_path = 'platform/data/' + DUPLICATE, 'platform/metadata/' + DUPLICATE
granting, metadata_only = {}, {}
for name in policy_names():
if name in EXEMPT_POLICIES:
continue
result = bao(['policy', 'read', name])
if result.returncode != 0:
raise Exit(2, 'policy_read_failed')
hits = granting_stanzas(result.stdout.decode(), paths)
text = result.stdout.decode()
hits = granting_stanzas(text, [data_path])
if hits:
granting[name] = hits
else:
meta_hits = granting_stanzas(text, [metadata_path])
if meta_hits:
metadata_only[name] = meta_hits
receipt['granting_policies'] = granting
receipt['metadata_only_policies'] = metadata_only
if granting:
raise Exit(3, 'live_policy_grants_duplicate')
if args.dry_run:

View file

@ -101,6 +101,12 @@ class Retire(unittest.TestCase):
self.assertEqual(list(receipt['granting_policies']), ['coding-agent'])
self.assertIn(DUP, self.state['kv'])
def test_mount_wide_metadata_survey_does_not_block(self):
self.state['policies']['platform-readonly'] = 'path "platform/metadata/*" { capabilities = ["read", "list"] }'
code, receipt = self.run_helper('--dry-run')
self.assertEqual((code, receipt['outcome']), (0, 'dry_run_would_retire'))
self.assertEqual(receipt['metadata_only_policies'], {'platform-readonly': ['platform/metadata/*']})
def test_unexpected_versions_or_missing_canonical_refuse(self):
self.state['kv'][DUP] = 2
code, receipt = self.run_helper()