Verify scoped approval client delivery through attended reader session
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a09cbb-87c6-7900-a145-4ce53ba9f1a6
This commit is contained in:
parent
bbff2bfb93
commit
525664efa3
6 changed files with 301 additions and 0 deletions
26
docs/evidence/2026-09-14-ccr0019-delivery-check.json
Normal file
26
docs/evidence/2026-09-14-ccr0019-delivery-check.json
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"observed_at": "2026-09-13T23:44:04.757286+00:00",
|
||||
"ccr_id": "CCR-2026-0019",
|
||||
"status": "passed",
|
||||
"approval_mutations": false,
|
||||
"checks": {
|
||||
"private_delivery_existing_version_1": true,
|
||||
"approval:read": {
|
||||
"native_claim_http_status": 404,
|
||||
"profile_checked": true
|
||||
},
|
||||
"approval:consume": {
|
||||
"native_claim_http_status": 403,
|
||||
"profile_checked": true
|
||||
}
|
||||
},
|
||||
"cleanup": true,
|
||||
"warden_session": "exited_0_after_self_revocation_and_helper_cleanup",
|
||||
"approval_engine_pod_uid": "7b8c05d9-f1d5-403d-abb3-2250bff9db5e",
|
||||
"approval_engine_image": "sha256:251941a5cb2724b57cc32cff6b693b1ab0be695bee4f56f02d51961189c0fa49",
|
||||
"limits": [
|
||||
"Read request used a fresh nonexistent approval id; 404 proves authenticated routing, not a usable claim.",
|
||||
"Consume-only token was denied the read route; no real approval was consumed.",
|
||||
"Wrong-group human login remains untested."
|
||||
]
|
||||
}
|
||||
34
docs/evidence/2026-09-14-ccr0019-reader-preflight.json
Normal file
34
docs/evidence/2026-09-14-ccr0019-reader-preflight.json
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"observed_at": "2026-09-13T23:44:04.757314+00:00",
|
||||
"ccr_id": "CCR-2026-0019",
|
||||
"secret_values_read": false,
|
||||
"status": "passed",
|
||||
"checks": {
|
||||
"platform/data/workloads/secrets-engine/approval-client": [
|
||||
"read"
|
||||
],
|
||||
"platform/metadata/workloads/secrets-engine/approval-client": [
|
||||
"read"
|
||||
],
|
||||
"platform/data/workloads/approval-engine/operator-client": [
|
||||
"deny"
|
||||
],
|
||||
"platform/metadata/workloads/secrets-engine": [
|
||||
"deny"
|
||||
],
|
||||
"platform/metadata/workloads": [
|
||||
"deny"
|
||||
],
|
||||
"platform/data/workloads/activity-core/llm-connect/llm-connect-provider-secrets": [
|
||||
"deny"
|
||||
],
|
||||
"sys/policies/acl/workload-kv-read-secrets-engine-approval-client": [
|
||||
"deny"
|
||||
],
|
||||
"auth/netkingdom/role/secrets-engine-approval-client-workload-kv-read": [
|
||||
"deny"
|
||||
]
|
||||
},
|
||||
"identity_policy_scope_verified": true,
|
||||
"warden_session": "exited_0_after_self_revocation_and_helper_cleanup"
|
||||
}
|
||||
106
scripts/approval-client-delivery-check.py
Normal file
106
scripts/approval-client-delivery-check.py
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
"""Silent bounded CCR-2026-0019 acceptance; never creates or consumes approvals."""
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import signal
|
||||
import stat
|
||||
import tempfile
|
||||
from datetime import datetime, timezone
|
||||
from urllib.request import Request, build_opener, ProxyHandler, HTTPRedirectHandler
|
||||
from urllib.error import HTTPError
|
||||
from uuid import uuid4
|
||||
|
||||
import importlib.util
|
||||
_spec = importlib.util.spec_from_file_location('reader_preflight', Path(__file__).with_name('approval-client-reader-preflight.py'))
|
||||
preflight = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(preflight)
|
||||
|
||||
RECEIPT = Path('/home/worsch/railiance-platform/docs/evidence/2026-09-14-ccr0019-delivery-check.json')
|
||||
class NoRedirect(HTTPRedirectHandler):
|
||||
def redirect_request(self, *args, **kwargs):
|
||||
return None
|
||||
|
||||
def transport(request, *, timeout):
|
||||
return build_opener(ProxyHandler({}), NoRedirect()).open(request, timeout=timeout)
|
||||
|
||||
def private(path, mode, directory=False):
|
||||
info = path.lstat()
|
||||
if stat.S_IMODE(info.st_mode) != mode or info.st_uid != os.getuid():
|
||||
raise ValueError('private_path_required')
|
||||
if not (stat.S_ISDIR(info.st_mode) if directory else stat.S_ISREG(info.st_mode)):
|
||||
raise ValueError('private_path_required')
|
||||
|
||||
def main():
|
||||
receipt = {'observed_at':datetime.now(timezone.utc).isoformat(), 'ccr_id':'CCR-2026-0019',
|
||||
'status':'refused', 'approval_mutations':False, 'checks':{}, 'cleanup':False}
|
||||
directory = None
|
||||
secret_file = None
|
||||
try:
|
||||
preflight.main()
|
||||
from secrets_engine.approval_auth import KeyCapeApprovalAuthConfig
|
||||
from secrets_engine.service_auth import KeyCapeServiceAuthProvider
|
||||
runtime = Path('/run/user') / str(os.getuid())
|
||||
private(runtime, 0o700, True)
|
||||
if runtime.resolve() != runtime:
|
||||
raise ValueError('private_path_required')
|
||||
result = preflight.subprocess.run(['findmnt','-n','-o','FSTYPE','-T',str(runtime)],capture_output=True,text=True,timeout=10)
|
||||
if result.returncode or result.stdout.strip() != 'tmpfs':
|
||||
raise ValueError('runtime_tmpfs_required')
|
||||
directory = Path(tempfile.mkdtemp(prefix='secrets-approval-',dir=runtime))
|
||||
private(directory, 0o700, True)
|
||||
secret_file = directory/'client-secret'
|
||||
helper = Path.home()/'.vault-token'
|
||||
private(helper, 0o600)
|
||||
token = helper.read_text().strip()
|
||||
req = Request('https://bao.coulomb.social/v1/platform/data/workloads/secrets-engine/approval-client?version=1',headers={'X-Vault-Token':token})
|
||||
with transport(req,timeout=20) as response:
|
||||
data = response.read(65537)
|
||||
if len(data)>65536:
|
||||
raise ValueError('custody_response_invalid')
|
||||
data=json.loads(data)
|
||||
if data['data']['metadata']['version'] != 1:
|
||||
raise ValueError('custody_response_invalid')
|
||||
value=data['data']['data']['CLIENT_SECRET']
|
||||
if not isinstance(value,str) or not value or len(value)>16384:
|
||||
raise ValueError('custody_response_invalid')
|
||||
fd=os.open(secret_file,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600)
|
||||
with os.fdopen(fd,'w') as stream:
|
||||
stream.write(value)
|
||||
del value, data, token, req
|
||||
private(secret_file,0o600)
|
||||
receipt['checks']['private_delivery_existing_version_1']=True
|
||||
approval_id=str(uuid4())
|
||||
for scope in ('approval:read','approval:consume'):
|
||||
config=KeyCapeApprovalAuthConfig(token_url='https://kc.coulomb.social/token',issuer='https://kc.coulomb.social',client_secret_file=secret_file,scope=scope)
|
||||
jwt=KeyCapeServiceAuthProvider(config,transport=transport).exchange()
|
||||
request=Request('http://127.0.0.1:18281/v1/approvals/'+approval_id+'/claim',headers={'Authorization':'Bearer '+jwt.token})
|
||||
try:
|
||||
with transport(request,timeout=20) as response:
|
||||
status=response.status
|
||||
except HTTPError as error:
|
||||
status=error.code
|
||||
error.close()
|
||||
expected=404 if scope=='approval:read' else 403
|
||||
if status != expected:
|
||||
raise ValueError('native_scope_check_failed')
|
||||
receipt['checks'][scope]={'native_claim_http_status':status,'profile_checked':True}
|
||||
del jwt, request
|
||||
receipt['status']='passed'
|
||||
except Exception:
|
||||
receipt['failure']='delivery_check_failed'
|
||||
raise
|
||||
finally:
|
||||
if secret_file is not None and secret_file.exists():
|
||||
secret_file.unlink()
|
||||
if directory is not None:
|
||||
directory.rmdir()
|
||||
receipt['cleanup']=directory is None or not directory.exists()
|
||||
RECEIPT.write_text(json.dumps(receipt,indent=2)+'\n')
|
||||
|
||||
if __name__=='__main__':
|
||||
for sig in (signal.SIGINT,signal.SIGTERM):
|
||||
signal.signal(sig,lambda *_: (_ for _ in ()).throw(SystemExit(130)))
|
||||
try:
|
||||
main()
|
||||
except Exception:
|
||||
raise SystemExit(1) from None
|
||||
62
scripts/approval-client-reader-preflight.py
Normal file
62
scripts/approval-client-reader-preflight.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
"""Silent exact-reader metadata preflight under the Warden login envelope."""
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
from datetime import datetime, timezone
|
||||
|
||||
POLICY = 'workload-kv-read-secrets-engine-approval-client'
|
||||
DATA = 'platform/data/workloads/secrets-engine/approval-client'
|
||||
META = 'platform/metadata/workloads/secrets-engine/approval-client'
|
||||
EXPECTED = {
|
||||
DATA: ['read'], META: ['read'],
|
||||
'platform/data/workloads/approval-engine/operator-client': ['deny'],
|
||||
'platform/metadata/workloads/secrets-engine': ['deny'],
|
||||
'platform/metadata/workloads': ['deny'],
|
||||
'platform/data/workloads/activity-core/llm-connect/llm-connect-provider-secrets': ['deny'],
|
||||
'sys/policies/acl/' + POLICY: ['deny'],
|
||||
'auth/netkingdom/role/secrets-engine-approval-client-workload-kv-read': ['deny'],
|
||||
}
|
||||
RECEIPT = Path('/home/worsch/railiance-platform/docs/evidence/2026-09-14-ccr0019-reader-preflight.json')
|
||||
|
||||
def validate_identity(identity):
|
||||
policies = set(identity.get('policies', [])) | set(identity.get('identity_policies', []))
|
||||
if POLICY not in policies or policies - {POLICY, 'default'}:
|
||||
raise ValueError('unexpected_effective_policies')
|
||||
if not identity.get('entity_id') or not 0 < identity.get('ttl', 0) <= 900:
|
||||
raise ValueError('unbounded_or_unidentified_reader')
|
||||
|
||||
def bao(*args):
|
||||
result = subprocess.run(['bao', *args], capture_output=True, text=True, timeout=30)
|
||||
if result.returncode:
|
||||
raise ValueError('metadata_request_failed')
|
||||
return json.loads(result.stdout)
|
||||
|
||||
def main():
|
||||
receipt = {'observed_at': datetime.now(timezone.utc).isoformat(),
|
||||
'ccr_id': 'CCR-2026-0019', 'secret_values_read': False,
|
||||
'status': 'refused', 'checks': {}}
|
||||
try:
|
||||
if Path.home().parent.name != '.warden-attended-login' or os.getenv('BAO_TOKEN') or os.getenv('VAULT_TOKEN'):
|
||||
raise ValueError('attended_envelope_required')
|
||||
identity = bao('token', 'lookup', '-format=json')['data']
|
||||
validate_identity(identity)
|
||||
receipt['identity_policy_scope_verified'] = True
|
||||
for path, expected in EXPECTED.items():
|
||||
values = bao('token', 'capabilities', '-format=json', path)
|
||||
if sorted(values) != expected:
|
||||
raise ValueError('capabilities_mismatch')
|
||||
receipt['checks'][path] = expected
|
||||
receipt['status'] = 'passed'
|
||||
except Exception as exc:
|
||||
code = str(exc)
|
||||
receipt['failure'] = code if code in {'attended_envelope_required', 'unexpected_effective_policies', 'unbounded_or_unidentified_reader', 'metadata_request_failed', 'capabilities_mismatch'} else 'preflight_failed'
|
||||
raise
|
||||
finally:
|
||||
RECEIPT.write_text(json.dumps(receipt, indent=2) + '\n')
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except Exception:
|
||||
raise SystemExit(1) from None
|
||||
47
tests/test_approval_client_reader.py
Normal file
47
tests/test_approval_client_reader.py
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import importlib.util
|
||||
import json
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
ROOT=Path(__file__).resolve().parents[1]
|
||||
def load(name, filename):
|
||||
spec=importlib.util.spec_from_file_location(name, ROOT/'scripts'/filename)
|
||||
module=importlib.util.module_from_spec(spec); spec.loader.exec_module(module)
|
||||
return module
|
||||
reader=load('reader','approval-client-reader-preflight.py')
|
||||
delivery=load('delivery','approval-client-delivery-check.py')
|
||||
|
||||
class ReaderBoundary(unittest.TestCase):
|
||||
def test_additive_identity_admin_policy_is_refused(self):
|
||||
base={'policies':[reader.POLICY,'default'],'entity_id':'fixture','ttl':899}
|
||||
reader.validate_identity(base)
|
||||
for change in ({'identity_policies':['platform-admin']},{'policies':['default']},{'ttl':901},{'entity_id':''}):
|
||||
with self.subTest(change=change), self.assertRaises(ValueError):
|
||||
reader.validate_identity(base|change)
|
||||
|
||||
def test_refused_preflight_never_fetches_credentials(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
receipt=Path(directory)/'receipt.json'
|
||||
with patch.object(delivery,'RECEIPT',receipt), patch.object(delivery.preflight,'main',side_effect=ValueError('fixture refusal')), patch.object(delivery,'transport') as transport:
|
||||
with self.assertRaises(ValueError): delivery.main()
|
||||
transport.assert_not_called()
|
||||
recorded=json.loads(receipt.read_text())
|
||||
self.assertEqual(recorded['status'],'refused')
|
||||
self.assertTrue(recorded['cleanup'])
|
||||
self.assertNotIn('fixture refusal',receipt.read_text())
|
||||
|
||||
def test_private_file_refuses_symlink_and_group_read(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
path=Path(directory)/'secret'; path.write_text('synthetic'); path.chmod(0o600)
|
||||
delivery.private(path,0o600)
|
||||
link=Path(directory)/'link'; link.symlink_to(path)
|
||||
with self.assertRaises(ValueError): delivery.private(link,0o600)
|
||||
path.chmod(0o640)
|
||||
with self.assertRaises(ValueError): delivery.private(path,0o600)
|
||||
|
||||
def test_credential_redirect_is_refused(self):
|
||||
self.assertIsNone(delivery.NoRedirect().redirect_request(None,None,302,'redirect',{},'https://unrelated.invalid'))
|
||||
|
||||
if __name__=='__main__': unittest.main()
|
||||
|
|
@ -607,3 +607,29 @@ Service/domain-transaction/human and factory runtime/spend admission remain
|
|||
separate; factory attempts and paid model calls remain zero.
|
||||
|
||||
Receipt: [native readback](../docs/evidence/2026-09-11-factory-native-readback.json).
|
||||
|
||||
|
||||
### T06 native reader acceptance — 2026-09-14
|
||||
|
||||
The scoped Warden login lane `secrets-engine-approval-client-login` now routes
|
||||
to the applied OIDC reader and the platform's silent preflight. The installed
|
||||
Warden package still carries an older catalog; use the explicit source catalog
|
||||
`WARDEN_ROUTING_CATALOG=/home/worsch/ops-warden/registry/routing/catalog.yaml`
|
||||
until its next normal installation refresh. This lane authenticates the reader;
|
||||
it is not a raw secret fetch or retained-file delivery interface.
|
||||
|
||||
Live effective-policy and capability checks passed: only exact data/metadata
|
||||
read, no sibling secret, parent listing, write or control-plane authority.
|
||||
A second contained session read existing version 1 into an operator-owned 0600
|
||||
file in a private 0700 runtime tmpfs directory. The native consumer exchanged
|
||||
separate read and consume scopes; Approval Engine verified the read token before
|
||||
returning 404 for a fresh nonexistent approval, and refused the consume-only
|
||||
token's read request with 403. No approval was created, bound or consumed.
|
||||
Both Warden sessions exited 0 after self-revocation/helper cleanup; temporary
|
||||
credential file and directory were removed. Four refusal/path/redirect tests
|
||||
pass. Receipts are in platform `docs/evidence/2026-09-14-ccr0019-{reader-preflight,delivery-check}.json`.
|
||||
|
||||
Remaining: an actual nonmember login refusal, real approval claim/consume,
|
||||
separate narrow requester admission and deployed Informed Decision review with
|
||||
an explicitly admitted human mandate. The reader group alone grants no review
|
||||
mandate. T03 and CCR delivery activation remain open; no OpenRouter key was read.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue