Record native security preparation and owner checkpoints (5/7)
This commit is contained in:
parent
43f88d5f73
commit
ae055669d0
18 changed files with 1278 additions and 0 deletions
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"scope": "two-path canonical source follow-through; root publication pending",
|
||||
"files": [
|
||||
{
|
||||
"path": "integration-manifest.json",
|
||||
"sha256": "sha256:97c9d28bb094e6089b2b24ce4e1ae4ba90d319f1042cd83871429953e9eda97d"
|
||||
},
|
||||
{
|
||||
"path": "integration-result.json",
|
||||
"sha256": "sha256:cb081438de0b8ffc2c8e47464699b4d0ba9f88af61c25c852b8078dc867d86ce"
|
||||
},
|
||||
{
|
||||
"path": "owner-plan.post.md",
|
||||
"sha256": "sha256:b984425e043e08e5bd1e53dbef90839af5258b8fdeee057d2293a93b78bb492d"
|
||||
},
|
||||
{
|
||||
"path": "source.patch",
|
||||
"sha256": "sha256:682dd10dcd39e148e84dacd91e29c5b6016d30029e0d7c2c82f3cd3f82739261"
|
||||
},
|
||||
{
|
||||
"path": "verification.json",
|
||||
"sha256": "sha256:8cc33b5f431b4b4d206a17da4e96ecba8e5a12cb3e88092bc82710a12bd8374d"
|
||||
},
|
||||
{
|
||||
"path": "workplan.post.md",
|
||||
"sha256": "sha256:c35019a8609e52fc4a7f5cc14e7b12cdc17dffbc8cd0b564a48a6b9fb6b5035d"
|
||||
},
|
||||
{
|
||||
"path": "workplan.pre.md",
|
||||
"sha256": "sha256:b3cab4e8d14b3b03179fc72a6e9ce1c0ee840cfa3247c022c1324d60378bde5b"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"scope": "exact two-path canonical source integration only; no Git/Hub/native actions",
|
||||
"paths": [
|
||||
{
|
||||
"path": "workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md",
|
||||
"pre_sha256": "sha256:b3cab4e8d14b3b03179fc72a6e9ce1c0ee840cfa3247c022c1324d60378bde5b",
|
||||
"post_sha256": "sha256:c35019a8609e52fc4a7f5cc14e7b12cdc17dffbc8cd0b564a48a6b9fb6b5035d",
|
||||
"postimage": "workplan.post.md"
|
||||
},
|
||||
{
|
||||
"path": "docs/keycape-isolated-consumer-continuity-plan.md",
|
||||
"pre_sha256": null,
|
||||
"post_sha256": "sha256:b984425e043e08e5bd1e53dbef90839af5258b8fdeee057d2293a93b78bb492d",
|
||||
"postimage": "owner-plan.post.md"
|
||||
}
|
||||
],
|
||||
"unrelated_worktree_hashes": {
|
||||
".custodian-brief.md": "sha256:4b3536c5d30aa558f9ba455b5f8984e54fe451a1792388be7006f2dc0a361193",
|
||||
"WORK-RECORDS.md": "sha256:ec39fefa21b5a2dde0bab42af82c9354c475f3ae64d13d45f9405796a04cc790"
|
||||
},
|
||||
"frozen_packet_manifest_sha256": "sha256:e557347945780f2ae81782a64af0cb976e43aca9c25b0f7444167473adccb0a2"
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"status": "exact_two_source_paths_applied",
|
||||
"git_hub_and_native_actions": false,
|
||||
"paths": [
|
||||
{
|
||||
"path": "workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md",
|
||||
"pre_sha256": "sha256:b3cab4e8d14b3b03179fc72a6e9ce1c0ee840cfa3247c022c1324d60378bde5b",
|
||||
"post_sha256": "sha256:c35019a8609e52fc4a7f5cc14e7b12cdc17dffbc8cd0b564a48a6b9fb6b5035d"
|
||||
},
|
||||
{
|
||||
"path": "docs/keycape-isolated-consumer-continuity-plan.md",
|
||||
"pre_sha256": null,
|
||||
"post_sha256": "sha256:b984425e043e08e5bd1e53dbef90839af5258b8fdeee057d2293a93b78bb492d"
|
||||
}
|
||||
],
|
||||
"unrelated_worktree_hashes_preserved": true
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
# Original KeyCape isolated consumer continuity plan
|
||||
|
||||
Owner: secrets-engine. Source outcome: SECRETS-WP-0015-T03, 2026-10-17.
|
||||
This is a reviewed source plan, not native assent, a custody grant or an
|
||||
executed recovery. T04 remains a human wait on the complete NK49T33 attempt.
|
||||
|
||||
The [frozen owner packet](../../the-custodian/docs/changes/netkingdom-target-2026-10-17/consumer-outage-r1/OWNER-PLAN.md)
|
||||
contains the exact custody/command/negative/equality/timeout/abort plan and source
|
||||
references. Its owner-plan SHA-256 is
|
||||
`sha256:d358aaeedc18c42c591d3301ec34f493e63bf579bf5a17b6ccc7e32ec88ea8ed`.
|
||||
The packet remains immutable; this source note does not revise its authority.
|
||||
|
||||
## Exact original selector and source
|
||||
|
||||
Use the existing [public selector](keycape-recovery-selector.json): issuer
|
||||
`https://kc.coulomb.social`, client/audience `secrets-engine-openbao`, env name
|
||||
`KEYCAPE_SECRETS_ENGINE_OPENBAO_CLIENT_SECRET`, subject
|
||||
`service:secrets-engine`, tenant `tenant:platform`, exactly role
|
||||
`secrets-engine`, scope `openbao:login`, denied scope `openbao:admin`.
|
||||
The current consumer `service_auth.py` source SHA-256 is
|
||||
`sha256:c0ade429edf452ad17f05d690b7ebef091db7f1a42b5ac350f1e40955c8586c0`.
|
||||
Its existing AST-only selector preflight passes at that exact hash. Historical
|
||||
issuer/consumer successes predate the archive and retain their historical scope.
|
||||
|
||||
The packet's [one-shot observer candidate](../../the-custodian/docs/changes/netkingdom-target-2026-10-17/consumer-outage-r1/consumer_contract_observer.py)
|
||||
is `sha256:23467730be61625d53b34c09e62f737a35e3def10d22a3a64664835961d3f4bd`.
|
||||
Its frozen four-file consumer-source manifest is
|
||||
`sha256:5b0409d7141514295e7d0f636ff6fa5dbe9d1f0d4d23b2f9ebce84a174d69499`.
|
||||
The observer remains a source candidate: it was tested with synthetic unsigned
|
||||
tokens only and is not installed, invoked on real material, or wired into either
|
||||
NK49 recovery or ordinary consumer authentication. Five synthetic tests pass;
|
||||
seven parser-negative variants and source/input refusal checks are within those
|
||||
tests, not extra native successes.
|
||||
|
||||
## Claims and custody boundaries
|
||||
|
||||
1. **Original issuer:** the existing frozen NK49 native checker binds the
|
||||
original archived registration/env, original TLS/trust/JWKS, wrong-secret and
|
||||
excess-scope refusal, and exact original config/registry/policy/receipt
|
||||
equality. Its receipt keeps downstream consumer reconnect false.
|
||||
2. **Consumer claim compatibility:** after a newly reviewed NK49 source/admission
|
||||
closure, the existing issuer `service-token` command may mint a short-lived
|
||||
original-identity token in the issuer's private tmpfs. A reviewed same-session
|
||||
wrapper would hand only that bounded token object over private stdin to the
|
||||
exact Secrets claim observer, then prove transient-token/resource cleanup.
|
||||
The original client secret stays in the restored issuer environment. Native
|
||||
issuer/JWKS verification precedes consumer parsing; the observer verifies no
|
||||
signature or native provenance. This proposed callback is not implemented.
|
||||
3. **Full original OpenBao consumer continuity:** requires Platform/rapp-openbao's
|
||||
independently recovered original backend/custody, original KV registration,
|
||||
narrow OIDC source role and actual operator authentication/MFA dependencies,
|
||||
plus exact isolated routing/trust. NK49's identity archive does not supply
|
||||
OpenBao Raft recovery. A fresh backend, production login or injected secret
|
||||
cannot substitute for this return. Then use the unchanged ordinary attended
|
||||
OpenBao in-memory secret source, KeyCape exchange, actual OpenBao JWT login
|
||||
and definite operator/engine session revocation.
|
||||
|
||||
The current no-file/no-fallback direction remains. Do not inject the recovered
|
||||
issuer secret into ordinary `login_service_jwt`, create a persistent consumer
|
||||
copy, use ambient/bootstrap credentials, or redirect production. An exceptional
|
||||
source would need a separate explicit owner/founder custody decision; none is
|
||||
proposed or implemented here. Service identity/login-only policy is not protected
|
||||
backend execution authority. SECRETS-WP-0008-T06/0013 retain those scopes;
|
||||
finished SECRETS-WP-0012 remains finished.
|
||||
|
||||
## Actual acceptance and next owner action
|
||||
|
||||
The next action is to assemble NK49T33's exact owner-held original TLS/archive/
|
||||
private-admission packet and surviving offline founder authorization before any
|
||||
key prompt. Matching hashes, possession of an archive key, this workplan and
|
||||
historical CCRs are not that authorization. Bind exact source/image/executor,
|
||||
original issuer/case/target, deadline and permitted isolated effects in the
|
||||
existing supervised recovery process. No new auth or approval service is needed.
|
||||
|
||||
Keep original ciphertext/transfer/source/binary/trust and manifest-binding-mode
|
||||
interfaces. Private manifests and equality hashes stay inside custody. Freeze any
|
||||
new observer callback/dependency closure, native command count and phase-specific
|
||||
negative parsing; its source/synthetic lifecycle review must precede real input.
|
||||
Use the existing bounded NK49 execution, exact pidfd/session quiescence and
|
||||
registered tmpfs/container cleanup. Abort on unknown provenance, changed original
|
||||
bytes, ambiguous daemon action or incomplete cleanup; preserve failed receipts
|
||||
and uncertainty rather than retrying or reinitializing state.
|
||||
|
||||
Require an actual positive original-issuer token and exact consumer claims,
|
||||
including no extra roles. Native wrong-expected-audience/required-role refusals
|
||||
are verifier checks, not OpenBao authorization. The observer's seven deliberately
|
||||
modified payloads prove parser refusal only; unsigned mutations prove no signed
|
||||
claim denial. Full backend acceptance separately requires real resource-server
|
||||
wrong-audience/scope/role refusal, restored policy/role/KV equality and session
|
||||
revocation through the existing owner path. Missing original signed negative
|
||||
cases stay missing; do not create grants or claim signature failure isolates a
|
||||
particular claim. A fresh attempt token is not a preserved pre-outage token.
|
||||
|
||||
T04 remains wait/needs_human, depends on T03 and NK-WP-0049-T33, and retains
|
||||
actual native acceptance. T18 owns actual selected-consumer recovery; T19 owns
|
||||
retained-factor MFA. Return separate closed issuer/consumer-contract/backend
|
||||
receipts tied to one attempt. Export source/public signing/TLS hashes, allowed
|
||||
identifiers, booleans and cleanup facts only; never secret/token/private manifest
|
||||
or raw provider output. A human wait is not an automatic worker wakeup.
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
"""Publish only independently reviewed offline owner handoffs, preserving other work."""
|
||||
from pathlib import Path
|
||||
import argparse,hashlib,json,subprocess,sys
|
||||
base=Path(__file__).resolve().parent
|
||||
sys.path.insert(0,'/home/worsch/repo-manager/src')
|
||||
from repo_manager.identifiers import ensure_missing_work_record_identifiers
|
||||
p=argparse.ArgumentParser();p.add_argument('lane',choices=['cluster','secrets']);p.add_argument('action',choices=['commit','sync']);a=p.parse_args()
|
||||
manifest=json.loads((base/(a.lane+'-integration.json')).read_text());owner=manifest['owner'];root=Path('/home/worsch')/owner
|
||||
paths=list(manifest['files']);backup=base/(owner+'-publication-backup')
|
||||
def git(*argv):return subprocess.check_output(['git','-C',str(root),*argv],stderr=subprocess.PIPE)
|
||||
def sha(path):return 'sha256:'+hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
if a.action=='commit':
|
||||
assert git('rev-parse','HEAD').decode().strip()==manifest['base_revision']
|
||||
for rel,pin in manifest['files'].items():assert sha(root/rel)==pin
|
||||
assert not backup.exists();backup.mkdir()
|
||||
originals={}
|
||||
for name in ['.custodian-brief.md','WORK-RECORDS.md']:
|
||||
if (root/name).exists():
|
||||
(backup/(name+'.worktree')).write_bytes((root/name).read_bytes());originals[name]=git('ls-files','--stage','--',name).decode()
|
||||
(backup/'originals.json').write_text(json.dumps(originals))
|
||||
planned=ensure_missing_work_record_identifiers(root,execute=False)
|
||||
assert set(planned['files_changed'])<=set(paths),'unrelated identifier writeback'
|
||||
assigned=ensure_missing_work_record_identifiers(root)
|
||||
inputs={rel:sha(root/rel) for rel in paths}
|
||||
git('add','--',*paths)
|
||||
r=subprocess.run(['git','-C',str(root),'commit','--only','-m','docs(recovery): deliver isolated original consumer custody plan','--',*paths],capture_output=True,text=True,timeout=180)
|
||||
receipt={'owner':owner,'exit_code':r.returncode,'stdout':r.stdout,'stderr':r.stderr,'head':git('rev-parse','HEAD').decode().strip(),'files':inputs,'managed_identifier_assignments':assigned}
|
||||
(base/(owner+'-commit.json')).write_text(json.dumps(receipt,indent=2)+'\n')
|
||||
for name,index in originals.items():
|
||||
assert (root/name).read_bytes()==(backup/(name+'.worktree')).read_bytes()
|
||||
assert git('ls-files','--stage','--',name).decode()==index
|
||||
print(json.dumps({'owner':owner,'commit_exit':r.returncode,'head':receipt['head']}));raise SystemExit(r.returncode)
|
||||
else:
|
||||
try:
|
||||
r=subprocess.run(['statehub','fix-consistency','--repo',owner,'--json'],cwd=root,capture_output=True,text=True,timeout=300)
|
||||
(base/(owner+'-consistency.json')).write_text(r.stdout)
|
||||
(base/(owner+'-consistency.stderr.txt')).write_text(r.stderr)
|
||||
assert r.returncode==0,'consistency failed; retained receipt'
|
||||
# Legacy sync omits record_id for some tasks; use the existing canonical
|
||||
# forge projection rather than declaring matching statuses sufficient.
|
||||
r=subprocess.run(['/home/worsch/repo-manager/.venv/bin/rmgr','sync','--path',str(root),'--push'],cwd=root,capture_output=True,text=True,timeout=180)
|
||||
(base/(owner+'-projection.json')).write_text(r.stdout)
|
||||
(base/(owner+'-projection.stderr.txt')).write_text(r.stderr)
|
||||
finally:
|
||||
for name,index in json.loads((backup/'originals.json').read_text()).items():
|
||||
(root/name).write_bytes((backup/(name+'.worktree')).read_bytes())
|
||||
if index:
|
||||
mode,oid,stage,path=index.split();assert stage=='0';git('update-index','--cacheinfo',mode,oid,path)
|
||||
assert git('ls-files','--stage','--',name).decode()==index
|
||||
print(json.dumps({'owner':owner,'projection_exit':r.returncode,'preexisting_other_work_preserved':True}));raise SystemExit(r.returncode)
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"owner": "secrets-engine",
|
||||
"exit_code": 0,
|
||||
"stdout": "[main 691dc74] docs(recovery): deliver isolated original consumer custody plan\n 2 files changed, 130 insertions(+), 15 deletions(-)\n create mode 100644 docs/keycape-isolated-consumer-continuity-plan.md\n",
|
||||
"stderr": "{\"blocked_blob_ids\": [], \"scanned_blobs\": 2, \"scanner_sha256\": \"88f91962aa2f93ac6ab281d553b9e125f5197bbbce38f9f2437f7299c32e5509\", \"scanner_version\": \"8.30.1\", \"scope\": \"changed-staged-blobs\", \"status\": \"clean\"}\n",
|
||||
"head": "691dc742362eeec45d5bd32d2b468f31a959748e",
|
||||
"files": {
|
||||
"docs/keycape-isolated-consumer-continuity-plan.md": "sha256:b984425e043e08e5bd1e53dbef90839af5258b8fdeee057d2293a93b78bb492d",
|
||||
"workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md": "sha256:c35019a8609e52fc4a7f5cc14e7b12cdc17dffbc8cd0b564a48a6b9fb6b5035d"
|
||||
},
|
||||
"managed_identifier_assignments": {
|
||||
"schema": "repo-manager.identifier-assignment.v1",
|
||||
"ok": true,
|
||||
"executed": true,
|
||||
"repo": "secrets-engine",
|
||||
"namespace": "helixforge",
|
||||
"assignments": [],
|
||||
"historical_invalid_identifiers": [],
|
||||
"historical_identity_collisions": [],
|
||||
"files_changed": []
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
{
|
||||
"repo_slug": "secrets-engine",
|
||||
"repo_path": "/home/worsch/secrets-engine",
|
||||
"source_revision": "691dc742362eeec45d5bd32d2b468f31a959748e",
|
||||
"source_revision_reason": null,
|
||||
"issues": [
|
||||
{
|
||||
"severity": "WARN",
|
||||
"check_id": "C-33",
|
||||
"message": "WORK-RECORDS.md is missing or stale \u2014 regenerate via fix-consistency (CUST-WP-0061-T04 generated work-record index)",
|
||||
"file_path": "WORK-RECORDS.md",
|
||||
"db_id": "",
|
||||
"file_value": "",
|
||||
"db_value": "",
|
||||
"fixable": true
|
||||
},
|
||||
{
|
||||
"severity": "WARN",
|
||||
"check_id": "C-05",
|
||||
"message": "Title drift in 'secrets-wp-0001': file='Bootstrap secrets-engine MVP' db='Bootstrap State Hub integration' (file wins)",
|
||||
"file_path": "workplans/SECRETS-WP-0002-bootstrap.md",
|
||||
"db_id": "6c9a8c0d-18b5-41ac-8cd5-a8e84fb286b4",
|
||||
"file_value": "Bootstrap secrets-engine MVP",
|
||||
"db_value": "Bootstrap State Hub integration",
|
||||
"fixable": true
|
||||
},
|
||||
{
|
||||
"severity": "WARN",
|
||||
"check_id": "C-23",
|
||||
"message": "Lifecycle drift in 'secrets-wp-0013': workplan status 'proposed' has an active task \u2014 report only (ADR-007: do not auto-promote proposed)",
|
||||
"file_path": "workplans/SECRETS-WP-0013-task-scoped-openbao-execution.md",
|
||||
"db_id": "5e38aecc-85ca-5f55-94c6-9fbb08604819",
|
||||
"file_value": "proposed",
|
||||
"db_value": "proposed",
|
||||
"fixable": false
|
||||
},
|
||||
{
|
||||
"severity": "WARN",
|
||||
"check_id": "C-04",
|
||||
"message": "Status drift in 'secrets-wp-0015': file='active' db='ready' (file wins)",
|
||||
"file_path": "workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md",
|
||||
"db_id": "68a0642e-4908-5260-89c9-3adce60e6a4d",
|
||||
"file_value": "active",
|
||||
"db_value": "ready",
|
||||
"fixable": true
|
||||
},
|
||||
{
|
||||
"severity": "WARN",
|
||||
"check_id": "C-10",
|
||||
"message": "Task status drift 'SECRETS-WP-0015-T03': file='done' db='todo' (file wins)",
|
||||
"file_path": "workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md#SECRETS-WP-0015-T03",
|
||||
"db_id": "6262a915-7655-50be-b9f7-481f816d7335",
|
||||
"file_value": "done",
|
||||
"db_value": "todo",
|
||||
"fixable": true
|
||||
},
|
||||
{
|
||||
"severity": "WARN",
|
||||
"check_id": "C-22",
|
||||
"message": "Task description drift 'SECRETS-WP-0015-T03': file content differs from DB (file wins)",
|
||||
"file_path": "workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md#SECRETS-WP-0015-T03",
|
||||
"db_id": "6262a915-7655-50be-b9f7-481f816d7335",
|
||||
"file_value": "Completed 2026-10-17 as source-plan preparation only. The reviewed owner plan\nis [keycape-isolated-consumer-continuity-p",
|
||||
"db_value": "Next: map the exact original archive-delivered registration and producer-native\nchecker result to the intended consumer,",
|
||||
"fixable": true
|
||||
},
|
||||
{
|
||||
"severity": "WARN",
|
||||
"check_id": "C-39",
|
||||
"message": "Human wait task 'SECRETS-WP-0015-T04' in workplan 'SECRETS-WP-0015' has needs_human: true without decision_id \u2014 unrouted human gate",
|
||||
"file_path": "workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md#SECRETS-WP-0015-T04",
|
||||
"db_id": "",
|
||||
"file_value": "needs_human: true",
|
||||
"db_value": "",
|
||||
"fixable": false
|
||||
},
|
||||
{
|
||||
"severity": "WARN",
|
||||
"check_id": "C-41",
|
||||
"message": "Task wait-qualifier drift 'SECRETS-WP-0015-T04': file={'needs_human': True, 'blocking_reason': 'Source plan delivered in T03. Await NK-WP-0049-T33 original TLS/archive/private admission, exact native owner authority, and original OpenBao/custody recovery for actual consumer continuity.', 'decision_id': None, 'blocked_on': None, 'wait_until': None} db={'needs_human': True, 'blocking_reason': 'Await exact consumer proof/custody plan plus original TLS/private admission readiness; actual attended owner path/authority remains required.', 'decision_id': None, 'blocked_on': None, 'wait_until': None} (file wins)",
|
||||
"file_path": "workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md#SECRETS-WP-0015-T04",
|
||||
"db_id": "aeec6eb0-39e2-5f7c-8f5d-778133edfc73",
|
||||
"file_value": "{\"blocked_on\": null, \"blocking_reason\": \"Source plan delivered in T03. Await NK-WP-0049-T33 original TLS/archive/private admission, exact native owner authority, and original OpenBao/custody recovery for actual consumer continuity.\", \"decision_id\": null, \"needs_human\": true, \"wait_until\": null}",
|
||||
"db_value": "{\"blocked_on\": null, \"blocking_reason\": \"Await exact consumer proof/custody plan plus original TLS/private admission readiness; actual attended owner path/authority remains required.\", \"decision_id\": null, \"needs_human\": true, \"wait_until\": null}",
|
||||
"fixable": true
|
||||
},
|
||||
{
|
||||
"severity": "INFO",
|
||||
"check_id": "C-08",
|
||||
"message": "Closed DB workstream 'secrets-wp-0002' (id=7929a2d1\u2026, status=finished) has no backing workplan file",
|
||||
"file_path": "",
|
||||
"db_id": "7929a2d1-3006-5d4b-85e4-c62da055ee9b",
|
||||
"file_value": "",
|
||||
"db_value": "",
|
||||
"fixable": false
|
||||
},
|
||||
{
|
||||
"severity": "WARN",
|
||||
"check_id": "C-28",
|
||||
"message": "3 unread inbox message(s) older than 3 day(s): railiance-platform:0490edcb, the-custodian:23172cb2, the-custodian:51e9eace",
|
||||
"file_path": "",
|
||||
"db_id": "",
|
||||
"file_value": "",
|
||||
"db_value": "",
|
||||
"fixable": false
|
||||
},
|
||||
{
|
||||
"severity": "WARN",
|
||||
"check_id": "C-28",
|
||||
"message": "2 unread message(s) lack thread_id for supersession tracking: the-custodian:23172cb2, the-custodian:51e9eace",
|
||||
"file_path": "",
|
||||
"db_id": "",
|
||||
"file_value": "",
|
||||
"db_value": "",
|
||||
"fixable": false
|
||||
}
|
||||
],
|
||||
"fixes_applied": [
|
||||
"bindings: synced 17/17",
|
||||
"C-17 cleared: pushed 1 backlogged commit(s)",
|
||||
"C-33 fixed: regenerated WORK-RECORDS.md",
|
||||
"C-05 fixed: workstream 6c9a8c0d\u2026 title \u2192 'Bootstrap secrets-engine MVP'",
|
||||
"C-04 fixed: workstream 68a0642e\u2026 status \u2192 'active'",
|
||||
"C-10 fixed: task 6262a915\u2026 status \u2192 'done'",
|
||||
"C-22 fixed: task 6262a915\u2026 description updated",
|
||||
"C-41 fixed: task aeec6eb0\u2026 wait qualifiers synced",
|
||||
"brief: .custodian-brief.md updated",
|
||||
"push: pushed"
|
||||
],
|
||||
"summary": {
|
||||
"fail": 0,
|
||||
"automation_error": 0,
|
||||
"warn": 10,
|
||||
"info": 1
|
||||
},
|
||||
"result": "warn"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
WARN: git commit failed for writeback: Generated-only commits rejected: staged
|
||||
|
|
@ -0,0 +1,285 @@
|
|||
# Original KeyCape consumer outage proof: SECRETS-WP-0015-T03 review candidate
|
||||
|
||||
Prepared 2026-10-17. Scope is the exact owner proof/custody plan and a bounded
|
||||
source observer. No value, private archive, token or TLS material was retrieved;
|
||||
no namespace/container, issuer/OpenBao endpoint or native approval was used.
|
||||
NK-WP-0049 remains read-only here. Existing T04/native/human gates remain open.
|
||||
|
||||
## Actual gap and selected deliverable
|
||||
|
||||
The current source owner selector is established, and its AST-only preflight
|
||||
passes the already-reviewed service_auth.py digest. Historical 7 October issuer
|
||||
issuance and 10 October OpenBao consumer login predate the 16 October archive.
|
||||
They prove their historical operations, not that the current archive contains
|
||||
an unmodified registration, that the original TLS trust is recoverable, or that
|
||||
a consumer works with ordinary OpenBao/KeyCape unavailable.
|
||||
|
||||
The current NK49 adapter proves the restored issuer's native registration checks
|
||||
and keeps `downstream_consumer_reconnect_proven=false`. It never executes Secrets
|
||||
Engine's consumer validator. Its native Go verifier requires the requested roles
|
||||
to be present; Secrets Engine requires roles to equal exactly `[secrets-engine]`,
|
||||
including no extra role. Native Go verification and Python claim preflight are
|
||||
therefore distinct useful acceptance oracles. The latter explicitly does not
|
||||
verify signatures. No security defect or privilege grant is inferred from this
|
||||
split; OpenBao remains the actual resource-server signature verifier.
|
||||
|
||||
The ordinary Secrets consumer reads its client secret only from OpenBao through
|
||||
an attended OIDC memory source, self-revokes that operator session, exchanges at
|
||||
KeyCape, then obtains a login-only OpenBao JWT session and self-revokes it. Files,
|
||||
ambient secrets and bootstrap fallback are refused. If ordinary OpenBao is down,
|
||||
that first custody read cannot happen. If only isolated KeyCape is restored,
|
||||
the human OIDC/backend graph is also not established. Calling probe-openbao on a
|
||||
reachable production backend would establish current liveness, not the outage
|
||||
claim. Do not add a recovery client-secret fallback to make that call succeed.
|
||||
|
||||
**Smallest deliverable now:** run the exact consumer claim validator against a
|
||||
fresh token from the restored original issuer, with native issuer/JWKS verification
|
||||
before that validator and no client-secret transfer out of the issuer. Report
|
||||
consumer-contract compatibility only. Full backend continuity remains a separate
|
||||
owner-admitted original-OpenBao recovery proof, not a second invented broker.
|
||||
|
||||
## Exact public selector and owner coordinates
|
||||
|
||||
| Field | Required value |
|
||||
|---|---|
|
||||
| Issuer / token URL | https://kc.coulomb.social / https://kc.coulomb.social/token |
|
||||
| Client / audience | secrets-engine-openbao / secrets-engine-openbao |
|
||||
| Original secret env | KEYCAPE_SECRETS_ENGINE_OPENBAO_CLIENT_SECRET |
|
||||
| Subject / principal type | service:secrets-engine / service |
|
||||
| Tenant / roles | tenant:platform / exactly [secrets-engine] |
|
||||
| Scope / denied scope | openbao:login / openbao:admin |
|
||||
| Claim profile | RS256, groups [], aal1/client_secret, mfa false, source key-cape; <=900s lifetime |
|
||||
| Ordinary consumer custody | platform/data/workloads/keycape/secrets-engine-openbao, field CLIENT_SECRET |
|
||||
| Ordinary operator source | auth/netkingdom role keycape-secrets-engine-openbao-operator-workload-kv-read; memory only; 5m/4 uses |
|
||||
| Actual resource-server contract | JWT mount keycape-services, role secrets-engine-openbao, bound issuer above |
|
||||
| Login-only policy | secrets-engine-login-self; self endpoints only, explicit client-secret data/metadata deny |
|
||||
|
||||
The native role and ordinary custody coordinates are Platform/Mason-owned, not
|
||||
new grants by Secrets Engine. CCR-2026-0038 login identity does not authorize
|
||||
protected backend effects. SECRETS-WP-0008-T06/0013 retain those obligations.
|
||||
The current `require_backend_execution_ready` continues to refuse service-jwt
|
||||
protected execution before approval consumption or any backend call.
|
||||
|
||||
## Frozen interfaces and admission
|
||||
|
||||
Retain the exact original ciphertext identity and independently verified transfer
|
||||
receipt already identified by NK49, the existing `explicit-digest-v1` or explicit
|
||||
`ciphertext-derived-v1` private-manifest binding mode, source closure and target.
|
||||
Private manifest/config/key/client-secret hashes stay inside custody; only allowed
|
||||
public signing/certificate/source hashes and boolean equality results leave it.
|
||||
Do not reconstruct a private digest from guessed public metadata.
|
||||
|
||||
The fixed restored issuer image is
|
||||
`forgejo.coulomb.social/coulomb/key-cape@sha256:cdec9dd7c515f7e0a6169fc3fa560ee2cc47bf40d899755dec808c362f5ce010`.
|
||||
Current launcher remains exactly six args:
|
||||
|
||||
```text
|
||||
run-isolated-keycape.sh VERIFIED_TRANSFER_RECEIPT ADMISSION ADMISSION_SHA256 TLS_CERT TLS_KEY TRUST
|
||||
```
|
||||
|
||||
Current session: fixed local Docker Unix socket, two nonroot read-only containers,
|
||||
network-none/shared loopback namespace, no host ports or restart/log driver,
|
||||
512Mi/1CPU/64PIDs per container, owner-only tmpfs, exact source/binary/trust pins
|
||||
and pre-import cleanup/reaper obligations. The helper and original issuer share
|
||||
only their reviewed private tmpfs roots. Public source files and helper code for
|
||||
this consumer observer need a newly reviewed closure before any real attempt.
|
||||
No new image, Docker socket mount, external network, daemon or auth service is
|
||||
needed by the observer design.
|
||||
|
||||
`source-references.json` records exact observed public source. Root integrated the reviewed NK49 adapter source as
|
||||
`c52ca7f405416d437951844c0640b86e677c3523`; the adapter
|
||||
`sha256:86f37add7221e4c73e3f9d878c09a3cc81061627cbf024ed6887d973d929b718`
|
||||
matches that committed checkpoint. Remote publication/projection is separate
|
||||
root follow-through. Final source/admission pins must use that actual integrated
|
||||
closure, with any subsequent changes separately reviewed. The existing frozen actual R6 recovery proof retains its own bytes,
|
||||
failures and scope; adding this observer cannot inherit its proof digest.
|
||||
|
||||
The reviewed source observer imports exactly the existing four-file Secrets
|
||||
claim-validation closure, from a protected read-only staged copy. It verifies
|
||||
those source hashes against `consumer-source-manifest.json`, then accepts at most
|
||||
64KiB of strict duplicate-free token JSON over private stdin. It never calls a
|
||||
secret source, exchange, subprocess, OpenBao or network. Output contains booleans
|
||||
only, including explicit false signature/native-provenance/backend claims.
|
||||
The manifest hash must be pinned in the new admission; it is not authorization.
|
||||
|
||||
## Narrow original-token consumer check after native owner approval
|
||||
|
||||
1. Complete NK49T35 original TLS/trust disposition, NK49T36 original registration
|
||||
and private admission, and T33 exact command/revision/authority review. Original
|
||||
registration must be unique, confidential, client_credentials-enabled and
|
||||
bound to exactly the original env selector after authenticated decryption.
|
||||
The exact-one guard runs **after** decryption, not before its key prompt.
|
||||
2. Inside the existing protected restore/session path, execute the unchanged
|
||||
native verify-client against the restored original issuer with original
|
||||
environment and TLS/JWKS. Require every positive/native wrong-secret and
|
||||
openbao:admin refusal already required by NK49. Establish before/after exact
|
||||
original config, complete registry/policy/receipt tree and environment equality.
|
||||
3. Use the pinned issuer's **existing** `service-token` entry point, in that same
|
||||
isolated issuer, with `-issuer https://kc.coulomb.social -client-id
|
||||
secrets-engine-openbao -audience secrets-engine-openbao -scope openbao:login
|
||||
-secret-env KEYCAPE_SECRETS_ENGINE_OPENBAO_CLIENT_SECRET -out
|
||||
/tmp/secrets-engine-consumer-contract.json`. The command takes an env name,
|
||||
never a secret value. It independently verifies the issued token against the
|
||||
restored original JWKS. Output is an exclusive-create mode-0600 bearer-token
|
||||
file on the issuer's existing 16Mi tmpfs, never a workstation client-secret
|
||||
copy. Existing file/symlink or unknown containment stops before issuance.
|
||||
4. The reviewed wrapper reads that bounded new token object only into its private
|
||||
process memory, removes the tmpfs bearer file, then delivers the bytes over
|
||||
sealed stdin to the one-shot observer in the existing network-none helper.
|
||||
The original client secret never leaves the restored issuer env. No token
|
||||
value, auth header, private claim body or raw error reaches tool stdout,
|
||||
logs, Git, State Hub or a safe receipt. A failed transfer/cleanup is failure,
|
||||
not authority to mint another token or use a host file fallback.
|
||||
5. Run `python3 -I -B consumer_contract_observer.py --source-root
|
||||
<exact-readonly-staged-owner-source> --source-manifest
|
||||
<exact-public-source-manifest> --source-manifest-sha256
|
||||
sha256:5b0409d7141514295e7d0f636ff6fa5dbe9d1f0d4d23b2f9ebce84a174d69499`.
|
||||
The final admitted wrapper supplies stdin privately; do not paste a token
|
||||
into a shell command or run this manually with real values. Require exact
|
||||
actual positive claim preflight and every labelled local claim-parser negative.
|
||||
6. Separately, reuse native verify-client with a deliberately wrong expected
|
||||
audience and a deliberately absent required role against the same existing
|
||||
original registration. Each expected mismatch must fail for its intended
|
||||
verification phase with original TLS/signature positively established first;
|
||||
a generic transport/TLS failure is not a negative pass. This changes no
|
||||
registration or grant. Its wrong-audience verifier result is not an OpenBao
|
||||
role denial. Keep the already-required actual excessive-scope/wrong-secret
|
||||
issuer denials. Source/review tests must bind phase-specific negative parsing
|
||||
before this can be an executable native callback.
|
||||
7. Repeat full original config/env/registry/policy/receipt/JWKS equality, then
|
||||
record a separate consumer-contract observer receipt bound to the same run,
|
||||
original ciphertext/admission, native verifier/source and observer closure.
|
||||
Preserve the existing NK49 receipt's downstream-consumer flag false. Do not
|
||||
broaden its closed allowlist or change its native status to a backend result.
|
||||
8. Reuse NK49's exact pidfd/deadline quiescence and owned resource cleanup.
|
||||
Explicitly prove the token tmpfs path absent before final teardown and all
|
||||
owning tmpfs/container/plaintext resources absent afterward. All original
|
||||
signing material and generated JWTs stay confined to this boundary. A JWT
|
||||
is not individually revoked by deleting its file; it remains time-bound up
|
||||
to 900 seconds. No original provider grant is changed to simulate revocation.
|
||||
|
||||
This observer is **source preparation**, not yet wired into NK49. The old six-arg
|
||||
runner cannot call it. A minimal separately reviewed owner integration adds the
|
||||
frozen observer/source manifest to existing preflight/dependency closure, invokes
|
||||
it while the original isolated session still exists and records the separate
|
||||
closed receipt before existing cleanup. Do not import the consumer after its
|
||||
cleanup or add a background process outside the existing reaper session.
|
||||
Private token handling and extra native executions require a fresh exact NK49
|
||||
admission and synthetic lifecycle/phase-failure tests first. No real execution is
|
||||
proposed until root has that complete revision and the actual owner/human assent.
|
||||
|
||||
## Negative/equality oracles and what they establish
|
||||
|
||||
| Oracle | Required result / scope |
|
||||
|---|---|
|
||||
| Public source selector | all eight fields and fixed consumer source hash match; no archive/native claim |
|
||||
| Original archived binding | exactly one original registration and exact delivered env binding after verified archive restore |
|
||||
| TLS/signing continuity | original accepted cert/trust/issuer and original signing SPKI in live isolated JWKS; no self-signed substitute |
|
||||
| Native positive | original valid secret yields correctly signed scoped token at restored issuer |
|
||||
| Wrong unrelated secret | explicit native HTTP/authentication refusal; not predecessor-rotation continuity |
|
||||
| Excess requested scope | original issuer explicitly refuses openbao:admin |
|
||||
| Actual consumer positive | exact frozen Python validator accepts that privately delivered original-issuer token, including exact roles/no extras |
|
||||
| Wrong audience/required role | native verifier expected-binding mismatch on correctly reached original issuer; not an OpenBao authorization case |
|
||||
| Parser negatives | seven in-memory deliberately modified payloads refused: aud, scope, wrong role, extra role, tenant, subject, expiry; **noncryptographic** checks only |
|
||||
| Source/manifest/input failure | source drift, wrong source-manifest pin, duplicate/oversize/malformed JSON and forbidden extra token refuse without private diagnostics |
|
||||
| Restored equality | exact original config/environment and complete registry/policy/receipt bytes equal before/after; original public signing identity equal |
|
||||
| Token freshness | newly issued token is within <=900s; this is attempt freshness, not recovery of a pre-outage token |
|
||||
| Cleanup | no transient token file, owning tmpfs/container/private plaintext, process/session or daemon uncertainty hidden |
|
||||
|
||||
The observer's synthetic tokens deliberately have no real signature and may pass
|
||||
its positive shape check. That is expected and is explicitly reported as
|
||||
`signature_verified_here=false`; it must never be treated as token authentication.
|
||||
Original-token provenance comes from the exact owner wrapper/native checker,
|
||||
not a caller-supplied `verified: true` field or self-attesting JSON.
|
||||
|
||||
## Full original OpenBao consumer continuity: separate required owner return
|
||||
|
||||
To run the ordinary `login_service_jwt`/probe-openbao during a genuine ordinary-
|
||||
service outage, Platform/rapp-openbao must first supply its existing independently
|
||||
recoverable **original** OpenBao snapshot, unseal/recovery custody, exact version,
|
||||
audit/lease policy and isolated restore receipt. The NK49 identity archive does
|
||||
not contain that OpenBao Raft state. A fresh empty backend with a hand-authored
|
||||
matching role, a dev root token, or a fabricated KV copy is not recovery of the
|
||||
original consumer. No snapshot/key/unseal retrieval is requested here.
|
||||
|
||||
The isolated backend must have the restored original CLIENT_SECRET KV version,
|
||||
original narrow operator OIDC source role, original keycape-services JWT mount,
|
||||
role, policy and trust/discovery configuration. Bind private byte equality to
|
||||
owner-held original snapshots inside custody and export booleans/public metadata
|
||||
only. Restored ordinary OIDC source operation also needs the selected operator's
|
||||
actual original authentication/MFA dependency graph, callback/local routing and
|
||||
original TLS; this may depend on NK49T19 and cannot be inferred from service-token
|
||||
issuance. An isolated DNS route must not redirect production consumers or contact
|
||||
ordinary production issuer/OpenBao. Supply exact owner-controlled isolated
|
||||
endpoint/callback mapping, trust and egress before changing source config.
|
||||
|
||||
Then use the **unchanged** current attended OpenBao in-memory source to read and
|
||||
self-revoke, current client exchange, actual restored OpenBao JWT login, exact
|
||||
self-only policy/capability checks and definite engine session self-revocation.
|
||||
Prove wrong-audience, wrong-scope and wrong-role **resource-server** denials with
|
||||
an owner-admitted method that changes neither original registration nor roles.
|
||||
If no appropriately signed negative can be produced under existing original
|
||||
registrations, retain the missing negative; unsigned or payload-tampered tokens
|
||||
prove only signature refusal, not which claim binding caused denial. Historical
|
||||
CCR negative test clients are not invented archive contents or new grants.
|
||||
Protected catalog execution remains separately refused/not exercised.
|
||||
|
||||
If the owner instead chooses an exceptional isolated source for CLIENT_SECRET,
|
||||
that is a new explicit scoped custody/governance decision against the current
|
||||
only-OpenBao direction, not an implementation detail or a callback injection
|
||||
shortcut. This packet recommends no exception and implements none. T04 remains
|
||||
waiting until the actually chosen complete path is admitted and succeeds.
|
||||
|
||||
## Offline authority, timeout, abort and receipts
|
||||
|
||||
The recovery launcher validates metadata/source/containment, not a live approval
|
||||
token. Possession of a backup age key, a matching hash, a historical CCR, current
|
||||
owner files or source task status is not authority. Under ordinary issuer/approval
|
||||
outage, use the existing founder-controlled supervised recovery process to retain
|
||||
an exact offline action decision **before** custody prompts: named owner/executor,
|
||||
proposal/revision/digest, original archive/transfer/admission/source/image/target,
|
||||
permitted isolated token issuance/consumer check, no production/backend contact,
|
||||
expiry and abort/recovery. Native approval-object consumption is only claimed
|
||||
where the existing surviving approval path actually supplies it. No synthetic
|
||||
approval, bootstrapped signing trust or new approval/auth service is proposed.
|
||||
Existing root-approved work elsewhere does not authorize this action.
|
||||
|
||||
Use the existing 1800-second execution deadline and exact parent/session pidfd
|
||||
quiescence contract; native verifier timeout is currently 150 seconds. Bound the
|
||||
added service-token invocation (CLI's own max five minutes), observer (30 seconds)
|
||||
and negative checks within the same remaining deadline, with no retry. Exact
|
||||
numbers and maximum additional issuances need source-owner final review before
|
||||
native admission. Declared maximum additional service-client exchanges for this
|
||||
observer design is three (one successful service-token, one wrong-expected-aud,
|
||||
one wrong-required-role); each native verifier also performs its declared
|
||||
scope/secret cases if configured, so final argv/oracle count must be frozen.
|
||||
No payment/provider spend is invoked, but workstation resource use, recovery
|
||||
burden and EUR loss bound remain unknown and supervised, never priced as free.
|
||||
|
||||
Any source/private-admission/equality/provenance/negative-phase mismatch stops
|
||||
without another key request or token issuance. Preserve the failing phase and
|
||||
original recovery receipts; quiesce only exact owned processes and remove only
|
||||
registered owned token/tmpfs/container objects. Parent death or in-flight Docker
|
||||
uncertainty remains uncertain even after absence is observed. Preserve both the
|
||||
failed return and cleanup return. Do not clear uncertainty by reinitializing
|
||||
archives, rotating/replacing keys, editing the registry, redirecting production,
|
||||
creating clients, reissuing TLS silently or restarting ordinary services.
|
||||
|
||||
Safe combined evidence contains the same attempt ID, source/observer/manifest
|
||||
hashes, original ciphertext/admission references, public certificate/SPKI hashes,
|
||||
positive/negative phase booleans, original equality, issuer-only versus consumer-
|
||||
contract versus backend claim scope, timeouts and exact cleanup obligations.
|
||||
No token, client secret, seed, private manifest, config body, private key, user
|
||||
record or raw upstream response belongs in it.
|
||||
|
||||
## Review disposition and live records
|
||||
|
||||
The packet makes SECRETS-WP-0015-T03's plan/custody dependencies concrete and adds
|
||||
a reviewable one-shot source observer with five synthetic tests. It changes no
|
||||
canonical source/workplan, owner decision or authority. Root may integrate the
|
||||
owner-reviewed plan/observer into the existing owner source task after review;
|
||||
source delivery is distinct from T04 native acceptance. T04 keeps its dependency
|
||||
on NK49T33; NK49T36/T18/T19 and Platform original OpenBao/TLS/private custody/
|
||||
resource-server negative gates remain. No driver, intake, message or worker was
|
||||
created. Existing finished0012 stays finished; steady-state adoption0008 and
|
||||
protected effects0013 retain their scopes.
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"proposal_id": "SECRETS-WP-0015-T03-outage-consumer-source-r1",
|
||||
"revision": 1,
|
||||
"status": "source-review-candidate",
|
||||
"native_authorized": false,
|
||||
"files": [
|
||||
{
|
||||
"path": "OWNER-PLAN.md",
|
||||
"sha256": "sha256:d358aaeedc18c42c591d3301ec34f493e63bf579bf5a17b6ccc7e32ec88ea8ed"
|
||||
},
|
||||
{
|
||||
"path": "consumer-proof-interface.json",
|
||||
"sha256": "sha256:50ea7080133f27a690e2fb559ea6e4686b1990ce725809419a0768081832406f"
|
||||
},
|
||||
{
|
||||
"path": "consumer-source-manifest.json",
|
||||
"sha256": "sha256:5b0409d7141514295e7d0f636ff6fa5dbe9d1f0d4d23b2f9ebce84a174d69499"
|
||||
},
|
||||
{
|
||||
"path": "consumer_contract_observer.py",
|
||||
"sha256": "sha256:23467730be61625d53b34c09e62f737a35e3def10d22a3a64664835961d3f4bd"
|
||||
},
|
||||
{
|
||||
"path": "existing-selector-preflight.json",
|
||||
"sha256": "sha256:831e631bbb45bfe7e8cf196e0044601668a5e6800b8e4b56ae417045e9869d18"
|
||||
},
|
||||
{
|
||||
"path": "source-checks.json",
|
||||
"sha256": "sha256:83604266a79a9fbc41790fb0ffdb5ab90b7d991971aaa5df16acac22a87e8c48"
|
||||
},
|
||||
{
|
||||
"path": "source-references.json",
|
||||
"sha256": "sha256:f488eeab35504656c6f3b3c2721ca1c46b19eb529b9b0f05e9424cddf6913335"
|
||||
},
|
||||
{
|
||||
"path": "test_consumer_contract_observer.py",
|
||||
"sha256": "sha256:34984176c281a3aa123b0ce6138e18e7dda5fae631e277e5b1726b223458f5a2"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"schema": "secrets-engine.outage-consumer-proof-plan.v1",
|
||||
"status": "source-review-candidate-not-native-admission",
|
||||
"workplan_task": "SECRETS-WP-0015-T03",
|
||||
"original_selector": {
|
||||
"client_id": "secrets-engine-openbao",
|
||||
"secret_env": "KEYCAPE_SECRETS_ENGINE_OPENBAO_CLIENT_SECRET",
|
||||
"audience": "secrets-engine-openbao",
|
||||
"scope": "openbao:login",
|
||||
"subject": "service:secrets-engine",
|
||||
"tenant": "tenant:platform",
|
||||
"roles": "secrets-engine",
|
||||
"deny_scope": "openbao:admin"
|
||||
},
|
||||
"observer_source_manifest_sha256": "sha256:5b0409d7141514295e7d0f636ff6fa5dbe9d1f0d4d23b2f9ebce84a174d69499",
|
||||
"future_private_input": {
|
||||
"transport": "sealed stdin from reviewed same-session native service-token handoff",
|
||||
"max_bytes": 65536,
|
||||
"strict_keys": [
|
||||
"access_token",
|
||||
"token_type",
|
||||
"expires_in"
|
||||
],
|
||||
"client_secret_permitted": false,
|
||||
"input_logged_or_retained": false,
|
||||
"signature_verification": "prior native original issuer/JWKS checker, not this observer"
|
||||
},
|
||||
"native_issuer_receipt_preserved": {
|
||||
"schema": "netkingdom.isolated-keycape-recovery.v1",
|
||||
"status": "isolated_keycape_native_registration_checked",
|
||||
"downstream_consumer_reconnect_proven": false
|
||||
},
|
||||
"observer_receipt": {
|
||||
"schema": "secrets-engine.isolated-consumer-claim-observer.v1",
|
||||
"status": "consumer_claim_preflight_matches_not_backend_acceptance",
|
||||
"required_positive": "consumer_claim_preflight_matches",
|
||||
"required_false": [
|
||||
"signature_verified_here",
|
||||
"native_input_provenance_verified_here",
|
||||
"client_secret_source_exercised",
|
||||
"openbao_login_performed",
|
||||
"protected_backend_operation_performed",
|
||||
"downstream_consumer_reconnect_proven",
|
||||
"network_contacted"
|
||||
],
|
||||
"negative_scope": "local claim-parser checks only; altered payloads are not signed native token proofs"
|
||||
},
|
||||
"wrapper_required_binding": [
|
||||
"same_attempt_id",
|
||||
"ciphertext_sha256",
|
||||
"admission_sha256",
|
||||
"native_verifier_sha256",
|
||||
"original_public_signing_spki_sha256",
|
||||
"original_tls_trust_disposition",
|
||||
"observer_sha256",
|
||||
"consumer_source_manifest_sha256",
|
||||
"native_source_closure",
|
||||
"before_after_original_equality",
|
||||
"private_token_absence_and_resource_cleanup"
|
||||
],
|
||||
"implemented_native_callback": false,
|
||||
"full_original_openbao_consumer_acceptance": "pending independent original OpenBao/custody/SSO graph restore, unchanged attended source, real resource-server denial/revocation and owner admission"
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"src/secrets_engine/__init__.py": "sha256:6536fc21988755467f71a91e79c90bf984f1ee16e696566a03cc4c1240920573",
|
||||
"src/secrets_engine/errors.py": "sha256:4cd0bfdc009556b35d4359a37d797a6bacf644ca4969d46e33f60435b4bafac8",
|
||||
"src/secrets_engine/safe_paths.py": "sha256:90e31769f66f34910b562d64bebcaa3e8cea23e79678eff4d625efcefc0d4f73",
|
||||
"src/secrets_engine/service_auth.py": "sha256:c0ade429edf452ad17f05d690b7ebef091db7f1a42b5ac350f1e40955c8586c0"
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Review candidate: frozen consumer claim preflight, never authentication.
|
||||
|
||||
Only the reviewed recovery wrapper may deliver a short-lived token via private
|
||||
stdin after its independent original-issuer/JWKS verification. This program
|
||||
performs no network/secret acquisition/OpenBao login and cannot prove that origin.
|
||||
It emits no bearer token, claims, secret, parser diagnostic or provider output.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import argparse
|
||||
import base64
|
||||
from datetime import datetime, timezone
|
||||
import hashlib
|
||||
import importlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import stat
|
||||
import sys
|
||||
|
||||
SOURCE_FILES = (
|
||||
'src/secrets_engine/__init__.py', 'src/secrets_engine/errors.py',
|
||||
'src/secrets_engine/safe_paths.py', 'src/secrets_engine/service_auth.py',
|
||||
)
|
||||
LIMIT = 65536
|
||||
|
||||
|
||||
def unique(pairs):
|
||||
result = {}
|
||||
for key, value in pairs:
|
||||
if key in result:
|
||||
raise ValueError()
|
||||
result[key] = value
|
||||
return result
|
||||
|
||||
|
||||
def source_module(root, manifest_path, expected):
|
||||
if not expected.startswith('sha256:') or len(expected) != 71:
|
||||
raise ValueError()
|
||||
raw = manifest_path.read_bytes()
|
||||
if len(raw) > LIMIT or 'sha256:' + hashlib.sha256(raw).hexdigest() != expected:
|
||||
raise ValueError()
|
||||
entries = json.loads(raw, object_pairs_hook=unique)
|
||||
if set(entries) != set(SOURCE_FILES):
|
||||
raise ValueError()
|
||||
root = root.absolute()
|
||||
for name in SOURCE_FILES:
|
||||
path = root / name
|
||||
if any(p.is_symlink() for p in (path, *path.parents)):
|
||||
raise ValueError()
|
||||
st = path.stat()
|
||||
if not stat.S_ISREG(st.st_mode) or st.st_size > 1024 * 1024:
|
||||
raise ValueError()
|
||||
if 'sha256:' + hashlib.sha256(path.read_bytes()).hexdigest() != entries[name]:
|
||||
raise ValueError()
|
||||
if any(n == 'secrets_engine' or n.startswith('secrets_engine.') for n in sys.modules):
|
||||
raise ValueError()
|
||||
sys.path.insert(0, str(root / 'src'))
|
||||
return importlib.import_module('secrets_engine.service_auth')
|
||||
|
||||
|
||||
def observe(module, raw):
|
||||
if not 0 < len(raw) <= LIMIT:
|
||||
raise ValueError()
|
||||
value = json.loads(raw, object_pairs_hook=unique)
|
||||
if not isinstance(value, dict) or set(value) != {'access_token', 'token_type', 'expires_in'}:
|
||||
raise ValueError()
|
||||
token = value['access_token']
|
||||
if (not isinstance(token, str) or not token or value['token_type'].lower() != 'bearer'
|
||||
or type(value['expires_in']) is not int or not 0 < value['expires_in'] <= 900):
|
||||
raise ValueError()
|
||||
cfg = module.KeyCapeServiceAuthConfig(
|
||||
token_url='https://kc.coulomb.social/token', issuer='https://kc.coulomb.social')
|
||||
now = datetime.now(timezone.utc)
|
||||
checked = module.preflight_service_jwt(token, cfg, now=now)
|
||||
# These are intentionally noncryptographic parser negatives. A body edit
|
||||
# invalidates the old signature; this is not a signed foreign-claim oracle.
|
||||
replacements = {
|
||||
'wrong_audience': {'aud': 'isolated-denied-audience'},
|
||||
'excess_scope': {'scope': 'openbao:login openbao:admin'},
|
||||
'wrong_role': {'roles': ['isolated-denied-role']},
|
||||
'extra_role': {'roles': ['secrets-engine', 'isolated-denied-role']},
|
||||
'wrong_tenant': {'tenant': 'tenant:isolated-denied'},
|
||||
'wrong_subject': {'sub': 'service:isolated-denied'},
|
||||
'expired': {'exp': int(now.timestamp()) - 1},
|
||||
}
|
||||
parts = token.split('.')
|
||||
negatives = {}
|
||||
for name, replacement in replacements.items():
|
||||
body = {**checked.claims, **replacement}
|
||||
encoded = base64.urlsafe_b64encode(json.dumps(body, separators=(',', ':')).encode()).decode().rstrip('=')
|
||||
candidate = '.'.join((parts[0], encoded, parts[2]))
|
||||
try:
|
||||
module.preflight_service_jwt(candidate, cfg, now=now)
|
||||
except module.BackendError:
|
||||
negatives[name] = True
|
||||
else:
|
||||
negatives[name] = False
|
||||
if not all(negatives.values()):
|
||||
raise ValueError()
|
||||
return {
|
||||
'schema': 'secrets-engine.isolated-consumer-claim-observer.v1',
|
||||
'status': 'consumer_claim_preflight_matches_not_backend_acceptance',
|
||||
'consumer_claim_preflight_matches': True,
|
||||
'claim_parser_refusals': negatives,
|
||||
'signature_verified_here': False,
|
||||
'native_input_provenance_verified_here': False,
|
||||
'client_secret_source_exercised': False,
|
||||
'openbao_login_performed': False,
|
||||
'protected_backend_operation_performed': False,
|
||||
'downstream_consumer_reconnect_proven': False,
|
||||
'network_contacted': False,
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--source-root', type=Path, required=True)
|
||||
parser.add_argument('--source-manifest', type=Path, required=True)
|
||||
parser.add_argument('--source-manifest-sha256', required=True)
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
module = source_module(args.source_root, args.source_manifest, args.source_manifest_sha256)
|
||||
result = observe(module, sys.stdin.buffer.read(LIMIT + 1))
|
||||
except Exception:
|
||||
result = {'schema': 'secrets-engine.isolated-consumer-claim-observer.v1',
|
||||
'status': 'consumer_claim_preflight_refused',
|
||||
'private_diagnostics_suppressed': True}
|
||||
print(json.dumps(result, sort_keys=True))
|
||||
return 0 if result['status'] == 'consumer_claim_preflight_matches_not_backend_acceptance' else 1
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main())
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"schema": "secrets-engine.recovery-selector-preflight.v1",
|
||||
"status": "source_selector_matches_not_native_assent",
|
||||
"source_sha256": "sha256:c0ade429edf452ad17f05d690b7ebef091db7f1a42b5ac350f1e40955c8586c0",
|
||||
"consumer": {
|
||||
"client_id": "secrets-engine-openbao",
|
||||
"secret_env": "KEYCAPE_SECRETS_ENGINE_OPENBAO_CLIENT_SECRET",
|
||||
"audience": "secrets-engine-openbao",
|
||||
"scope": "openbao:login",
|
||||
"subject": "service:secrets-engine",
|
||||
"tenant": "tenant:platform",
|
||||
"roles": "secrets-engine",
|
||||
"deny_scope": "openbao:admin"
|
||||
},
|
||||
"credential_source_exercised": false,
|
||||
"network_contacted": false
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"scope": "source-only observer; all tokens synthetic and intentionally not cryptographically valid",
|
||||
"command": "python3 -B -m unittest discover -s docs/changes/netkingdom-target-2026-10-17/consumer-outage-r1 -p test_consumer_contract_observer.py",
|
||||
"tests_passed": 5,
|
||||
"claim_parser_negative_variants": 7,
|
||||
"existing_public_selector_preflight": "passed at exact previously reviewed c0ade429 source digest",
|
||||
"native_calls": 0,
|
||||
"credentials_read": false,
|
||||
"ordinary_or_recovered_issuer_contacted": false,
|
||||
"openbao_contacted": false,
|
||||
"all_source_reference_files_match_head": true
|
||||
}
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
{
|
||||
"scope": "public source and historical evidence; no native source assent",
|
||||
"references": [
|
||||
{
|
||||
"repo": "secrets-engine",
|
||||
"path": "src/secrets_engine/__init__.py",
|
||||
"revision": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
|
||||
"sha256": "sha256:6536fc21988755467f71a91e79c90bf984f1ee16e696566a03cc4c1240920573",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "secrets-engine",
|
||||
"path": "src/secrets_engine/errors.py",
|
||||
"revision": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
|
||||
"sha256": "sha256:4cd0bfdc009556b35d4359a37d797a6bacf644ca4969d46e33f60435b4bafac8",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "secrets-engine",
|
||||
"path": "src/secrets_engine/safe_paths.py",
|
||||
"revision": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
|
||||
"sha256": "sha256:90e31769f66f34910b562d64bebcaa3e8cea23e79678eff4d625efcefc0d4f73",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "secrets-engine",
|
||||
"path": "src/secrets_engine/service_auth.py",
|
||||
"revision": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
|
||||
"sha256": "sha256:c0ade429edf452ad17f05d690b7ebef091db7f1a42b5ac350f1e40955c8586c0",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "secrets-engine",
|
||||
"path": "src/secrets_engine/engine_auth.py",
|
||||
"revision": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
|
||||
"sha256": "sha256:e0479cf6d8c13233cf99dc39491143478c021597941ae8b6ba0e37957a42f330",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "secrets-engine",
|
||||
"path": "docs/keycape-recovery-selector.json",
|
||||
"revision": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
|
||||
"sha256": "sha256:02077af3c18b24f5e4a85992a3d4d0df51a8e458de1e48b48f7eb5f482257012",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "secrets-engine",
|
||||
"path": "docs/keycape-isolated-recovery-selector.md",
|
||||
"revision": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
|
||||
"sha256": "sha256:ed23b0df3d4b49e4b76df795455153c805971ccd37886836c960f550709e0739",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "secrets-engine",
|
||||
"path": "docs/keycape-openbao-consumer-custody.md",
|
||||
"revision": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
|
||||
"sha256": "sha256:73efdd549f3feaccc53eefd6f1b95c8b9eb7091648f94ad80978ba5381be9124",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "secrets-engine",
|
||||
"path": "docs/evidence/2026-10-10-keycape-openbao-probe.json",
|
||||
"revision": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
|
||||
"sha256": "sha256:bf0b5df9f030499d96770f1d9fb2091a8d37da71422a6d456be7200d3a1a1782",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "secrets-engine",
|
||||
"path": "workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md",
|
||||
"revision": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
|
||||
"sha256": "sha256:b3cab4e8d14b3b03179fc72a6e9ce1c0ee840cfa3247c022c1324d60378bde5b",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "secrets-engine",
|
||||
"path": "tools/check-keycape-recovery-selector.py",
|
||||
"revision": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
|
||||
"sha256": "sha256:e3e5e3ee743a212247701d6cb40fcf5b7f19349126fa9b32cbef9a3cc9459150",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "net-kingdom",
|
||||
"path": "tools/bootstrap-recovery/isolated-keycape.py",
|
||||
"revision": "c52ca7f405416d437951844c0640b86e677c3523",
|
||||
"sha256": "sha256:86f37add7221e4c73e3f9d878c09a3cc81061627cbf024ed6887d973d929b718",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "net-kingdom",
|
||||
"path": "tools/bootstrap-recovery/isolated-keycape-session.py",
|
||||
"revision": "c52ca7f405416d437951844c0640b86e677c3523",
|
||||
"sha256": "sha256:8fa38efe28167b59a6307f342b2ac8fcda78ecda60e6228f22017424d2343c22",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "net-kingdom",
|
||||
"path": "tools/bootstrap-recovery/run-isolated-keycape.sh",
|
||||
"revision": "c52ca7f405416d437951844c0640b86e677c3523",
|
||||
"sha256": "sha256:0d994c9c14ebdffdbf7879bd7562042531083d0e8955424d0ae099898a141668",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "net-kingdom",
|
||||
"path": "tools/bootstrap-recovery/prepare-isolated-keycape.py",
|
||||
"revision": "c52ca7f405416d437951844c0640b86e677c3523",
|
||||
"sha256": "sha256:5098bdfa4e0ad30627c1716e5e355a2c78dca6ccc607bd2148a2e06126632288",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "net-kingdom",
|
||||
"path": "tools/bootstrap-recovery/identity-backup-profile.json",
|
||||
"revision": "c52ca7f405416d437951844c0640b86e677c3523",
|
||||
"sha256": "sha256:40f9e5b5bb957e5b23e03b31701702b850502d16a92a0fa0ebf92618cc3f18a1",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "key-cape",
|
||||
"path": "src/internal/authclient/verify.go",
|
||||
"revision": "258d899a78fd4673b92004d1b10717b4de03d26f",
|
||||
"sha256": "sha256:804735be927ba7d0228ac378056730040d3ccf2ed020b4da0714085bae972f25",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "key-cape",
|
||||
"path": "src/internal/authclient/cli.go",
|
||||
"revision": "258d899a78fd4673b92004d1b10717b4de03d26f",
|
||||
"sha256": "sha256:376a8e0d1d60825a8b3ef21d371e3fc353c0a34e461712a6899e264278edbe7f",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "key-cape",
|
||||
"path": "src/internal/authclient/client.go",
|
||||
"revision": "258d899a78fd4673b92004d1b10717b4de03d26f",
|
||||
"sha256": "sha256:61fb150349c5d3714450a90834c59af9a579a8a649c4149297a402cfcf6e39c5",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "railiance-platform",
|
||||
"path": "docs/contracts/secrets-engine-openbao-jwt-login.yaml",
|
||||
"revision": "08c1f036f2750097750f435efd76e8f6ee6df393",
|
||||
"sha256": "sha256:a98663c316611c4b2773f197c734befb8446e8efe20f563da018c358c3b11d77",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "railiance-platform",
|
||||
"path": "credential-change-requests/CCR-2026-0038-secrets-engine-service-jwt-login.yaml",
|
||||
"revision": "08c1f036f2750097750f435efd76e8f6ee6df393",
|
||||
"sha256": "sha256:65b2cfb772623da59c351033ab4eb2ec7adfbd109778e787c7fe1b0e185a3bc0",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "railiance-platform",
|
||||
"path": "openbao/auth/secrets-engine-jwt-role.json",
|
||||
"revision": "08c1f036f2750097750f435efd76e8f6ee6df393",
|
||||
"sha256": "sha256:529dc23193be42cbe0d4440f902a64ca7c9158da158c9da13396aa0030480f40",
|
||||
"matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "railiance-platform",
|
||||
"path": "openbao/policies/secrets-engine-login-self.hcl",
|
||||
"revision": "08c1f036f2750097750f435efd76e8f6ee6df393",
|
||||
"sha256": "sha256:d1a2969dd2949c822972e9b32243650567ac123a669f3fc609e9bfea977bb4eb",
|
||||
"matches_head": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
"""Synthetic observer checks: no cryptographic/native/authentication claim."""
|
||||
import base64
|
||||
from datetime import datetime, timezone
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
OWNER = Path('/home/worsch/secrets-engine')
|
||||
MANIFEST = HERE / 'consumer-source-manifest.json'
|
||||
|
||||
|
||||
def segment(value):
|
||||
return base64.urlsafe_b64encode(json.dumps(value).encode()).decode().rstrip('=')
|
||||
|
||||
|
||||
def envelope(**overrides):
|
||||
now = int(datetime.now(timezone.utc).timestamp())
|
||||
claims = {'iss': 'https://kc.coulomb.social', 'sub': 'service:secrets-engine',
|
||||
'aud': 'secrets-engine-openbao', 'principal_type': 'service',
|
||||
'tenant': 'tenant:platform', 'groups': [], 'roles': ['secrets-engine'],
|
||||
'scope': 'openbao:login', 'iat': now, 'exp': now + 900,
|
||||
'assurance': {'level': 'aal1', 'methods': ['client_secret'],
|
||||
'mfa': False, 'source': 'key-cape'}}
|
||||
claims.update(overrides)
|
||||
token = segment({'alg': 'RS256', 'typ': 'JWT'}) + '.' + segment(claims) + '.synthetic_no_signature'
|
||||
return {'access_token': token, 'token_type': 'Bearer', 'expires_in': 900}
|
||||
|
||||
|
||||
def run(raw, *, owner=OWNER, digest=None):
|
||||
expected = digest or 'sha256:' + hashlib.sha256(MANIFEST.read_bytes()).hexdigest()
|
||||
result = subprocess.run(['python3', '-I', '-B', str(HERE/'consumer_contract_observer.py'),
|
||||
'--source-root', str(owner), '--source-manifest', str(MANIFEST),
|
||||
'--source-manifest-sha256', expected], input=raw,
|
||||
capture_output=True, timeout=10)
|
||||
return result, json.loads(result.stdout)
|
||||
|
||||
|
||||
class ObserverTests(unittest.TestCase):
|
||||
def test_synthetic_contract_is_explicitly_noncryptographic(self):
|
||||
value = envelope()
|
||||
result, report = run(json.dumps(value).encode())
|
||||
self.assertEqual(result.returncode, 0)
|
||||
self.assertTrue(all(report['claim_parser_refusals'].values()))
|
||||
for field in ('signature_verified_here', 'native_input_provenance_verified_here',
|
||||
'client_secret_source_exercised', 'openbao_login_performed',
|
||||
'protected_backend_operation_performed',
|
||||
'downstream_consumer_reconnect_proven', 'network_contacted'):
|
||||
self.assertIs(report[field], False)
|
||||
self.assertNotIn(value['access_token'].encode(), result.stdout + result.stderr)
|
||||
self.assertEqual(result.stderr, b'')
|
||||
|
||||
def test_wrong_actual_input_claims_refuse_without_private_diagnostics(self):
|
||||
for change in ({'aud': 'wrong'}, {'roles': ['admin']}, {'scope': 'openbao:admin'}):
|
||||
with self.subTest(change=change):
|
||||
value = envelope(**change)
|
||||
result, report = run(json.dumps(value).encode())
|
||||
self.assertEqual(result.returncode, 1)
|
||||
self.assertEqual(report['status'], 'consumer_claim_preflight_refused')
|
||||
self.assertNotIn(value['access_token'].encode(), result.stdout + result.stderr)
|
||||
self.assertEqual(result.stderr, b'')
|
||||
|
||||
def test_forbidden_extra_token_and_duplicate_json_refuse(self):
|
||||
value = envelope(); value['refresh_token'] = 'synthetic-forbidden'
|
||||
for raw in (json.dumps(value).encode(), b'{"access_token":"a","access_token":"b"}'):
|
||||
result, report = run(raw)
|
||||
self.assertEqual(result.returncode, 1)
|
||||
self.assertTrue(report['private_diagnostics_suppressed'])
|
||||
self.assertEqual(result.stderr, b'')
|
||||
|
||||
def test_oversize_and_malformed_refuse(self):
|
||||
for raw in (b'x' * 65537, b'not json'):
|
||||
result, report = run(raw)
|
||||
self.assertEqual(result.returncode, 1)
|
||||
self.assertTrue(report['private_diagnostics_suppressed'])
|
||||
|
||||
def test_source_manifest_and_source_body_drift_refuse(self):
|
||||
result, _ = run(json.dumps(envelope()).encode(), digest='sha256:' + '0'*64)
|
||||
self.assertEqual(result.returncode, 1)
|
||||
with tempfile.TemporaryDirectory(prefix='se-consumer-source-drift-') as directory:
|
||||
target = Path(directory)
|
||||
for name in json.loads(MANIFEST.read_text()):
|
||||
p = target/name; p.parent.mkdir(parents=True, exist_ok=True)
|
||||
p.write_bytes((OWNER/name).read_bytes())
|
||||
p = target/'src/secrets_engine/service_auth.py'; p.write_bytes(p.read_bytes()+b'\n# drift\n')
|
||||
result, report = run(json.dumps(envelope()).encode(), owner=target)
|
||||
self.assertEqual(result.returncode, 1)
|
||||
self.assertEqual(report['status'], 'consumer_claim_preflight_refused')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
{
|
||||
"status": "public_source_and_sanitized_prior_evidence_only",
|
||||
"observed_at": "2026-10-17T02:13:49.246721+00:00",
|
||||
"references": [
|
||||
{
|
||||
"repo": "repo-manager",
|
||||
"path": "AGENTS.md",
|
||||
"head": "3bcb1e1cf3e58b263f690534f7f28024d75cdbf6",
|
||||
"sha256": "sha256:b461f40a102fa25593807f9cd4213a411f3201e458df43dbcfde41b8251e1477"
|
||||
},
|
||||
{
|
||||
"repo": "repo-manager",
|
||||
"path": "INTENT.md",
|
||||
"head": "3bcb1e1cf3e58b263f690534f7f28024d75cdbf6",
|
||||
"sha256": "sha256:62afa83ecb1fd733abce07489d48d0d7c7e14ccf9def9f561c118cf8ec5409b2"
|
||||
},
|
||||
{
|
||||
"repo": "repo-manager",
|
||||
"path": "SCOPE.md",
|
||||
"head": "3bcb1e1cf3e58b263f690534f7f28024d75cdbf6",
|
||||
"sha256": "sha256:bca5806e11f04e4550ce5c147d4d98e6c0014fed1f17fa3f134e5b193adec43c"
|
||||
},
|
||||
{
|
||||
"repo": "repo-manager",
|
||||
"path": "history/2026-08-09-genesis.md",
|
||||
"head": "3bcb1e1cf3e58b263f690534f7f28024d75cdbf6",
|
||||
"sha256": "sha256:dbd4111a25d42fc3e1b1bcf921416fb9506c7f3d8f54e8f0dc82f5bbaeb4217d"
|
||||
},
|
||||
{
|
||||
"repo": "repo-manager",
|
||||
"path": "docs/secret-detection.md",
|
||||
"head": "3bcb1e1cf3e58b263f690534f7f28024d75cdbf6",
|
||||
"sha256": "sha256:1158dd4180b8c08717112dcbe6fa8f09ac0e2a44dd4d7d9bac2edf629d1766dc"
|
||||
},
|
||||
{
|
||||
"repo": "repo-manager",
|
||||
"path": "src/repo_manager/secret_scan.py",
|
||||
"head": "3bcb1e1cf3e58b263f690534f7f28024d75cdbf6",
|
||||
"sha256": "sha256:e709c658f779534fcab093207b0a78e49d54fc584c515fdf7ac535ce75f6c400"
|
||||
},
|
||||
{
|
||||
"repo": "repo-manager",
|
||||
"path": "src/repo_manager/cli.py",
|
||||
"head": "3bcb1e1cf3e58b263f690534f7f28024d75cdbf6",
|
||||
"sha256": "sha256:1120e8cc50341a2b02fd7d940a79f75a26ec6230c00dd1da76acaf0c6e494014"
|
||||
},
|
||||
{
|
||||
"repo": "repo-manager",
|
||||
"path": "tests/test_secret_scan.py",
|
||||
"head": "3bcb1e1cf3e58b263f690534f7f28024d75cdbf6",
|
||||
"sha256": "sha256:827ab6382bb63fed8d2e82ebb45ac7a28789abeb397a831f340e5f19d7cc7876"
|
||||
},
|
||||
{
|
||||
"repo": "repo-manager",
|
||||
"path": "workplans/RMGR-WP-0021-secret-detection-controls.md",
|
||||
"head": "3bcb1e1cf3e58b263f690534f7f28024d75cdbf6",
|
||||
"sha256": "sha256:966d15ccdabc8edf98bc58f9422ea190566d05fe4208f4749f59a9731f4e108d"
|
||||
},
|
||||
{
|
||||
"repo": "the-custodian",
|
||||
"path": "docs/changes/netkingdom-target-2026-10-17/scanner-unavailable-r1/namespace-hook-results.json",
|
||||
"sha256": "sha256:5aaef79c0be4ae3cf721482784b255dde795559363bfb671e64ba6252fec59bc"
|
||||
},
|
||||
{
|
||||
"repo": "the-custodian",
|
||||
"path": "docs/changes/netkingdom-target-2026-10-17/scanner-unavailable-r1/manifest.json",
|
||||
"sha256": "sha256:fb678cd82c41dd76ad0f056e1c3513e5339bc2ae82daf3cd17c9c85a43679665"
|
||||
},
|
||||
{
|
||||
"repo": "the-custodian",
|
||||
"path": "docs/changes/netkingdom-target-2026-10-17/native-gates-r1/native-gate-audit.json",
|
||||
"sha256": "sha256:ab803e795af61fd027f5930d127592316133de38b68a8fe61b89a1f9803a9ff2"
|
||||
},
|
||||
{
|
||||
"repo": "the-custodian",
|
||||
"path": "workplans/CUST-WP-0073-agent-credential-separation.md",
|
||||
"sha256": "sha256:8cbf27819b4d8c689c6afadf0dd3eabe8a8cd4b399d20f05a5e7fe8749b9b43a"
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue