Record native security preparation and owner checkpoints (2/7)
This commit is contained in:
parent
275e034883
commit
a6eee04d42
18 changed files with 5770 additions and 0 deletions
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"schema": "custodian.native-identity-refinement.v1",
|
||||
"revision": 2,
|
||||
"status": "source_task_refinement_ready_not_published",
|
||||
"task": "NK-WP-0049-T38",
|
||||
"previous_task_count": 37,
|
||||
"result_task_count": 38,
|
||||
"old_task_blocks_preserved": true,
|
||||
"uuid_assignment": "normal owner allocator; no UUID supplied",
|
||||
"root_source_review": "accepted narrow guard and two-hash unexecuted successor scope in root instruction; no privileged/native approval inferred",
|
||||
"knowledge_orientation": {
|
||||
"package_version": "0.2.6",
|
||||
"package_digest": "sha256:8d1d6a9d4d07fec7b619618de7dfe2be2254c1790f85f4198c7fe19db9751c02",
|
||||
"retrieval_status": "withheld",
|
||||
"reason": "source changed",
|
||||
"source_review": "current AGENTS, environment orientation, Security Companion and identity/start card source reviewed directly; knowledge is source-only orientation and grants no authority"
|
||||
},
|
||||
"frozen_r1_manifest_sha256": "sha256:6821e650a4ca07087697b5091a3db26b722456170c1c4816ca8c49bdf527fce4",
|
||||
"files": {
|
||||
"NK-WP-0049.postimage.md": "sha256:e0cd01320b366ab8961a0a52a908edc1524f98b3cfab7382a14fa915da2f60a2",
|
||||
"NK-WP-0049.preimage.md": "sha256:5830c429f58a0317b28c7b4bcf22a1b46e6d01b41378cdae95f947c6d9317e44",
|
||||
"task-refinement.patch": "sha256:a2e17aa51eb0313f1370ff366afb1198ce93624bb7451445dd62be9b663e70f0",
|
||||
"updated-owner-source.patch": "sha256:552484c86a7ac8b443faea6222aeb6d660eb0148f5d596c90f94ac9c60c2a6b0"
|
||||
},
|
||||
"canonical_workplan_matches_postimage": true,
|
||||
"diff_whitespace_check": "passed"
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
--- a/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md
|
||||
+++ b/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md
|
||||
@@ -1130,23 +1130,15 @@
|
||||
`recovery-owner-handoffs-r1` source review; independent ID/UUID/status/remote
|
||||
readback is recorded separately when performed.
|
||||
|
||||
-2026-10-17 exact-selector source preparation: the adapter now requires exactly
|
||||
-one selected client in the already-restored archived configuration before further
|
||||
-runtime environment reads, signer-key parsing or native checker invocation.
|
||||
-Absent, duplicate (identical or conflicting) and empty selectors refuse early;
|
||||
-existing unique registration behavior is retained. This check cannot run before
|
||||
-private archive decryption or its key prompt. Current KeyCape Go configuration
|
||||
-also rejects duplicate IDs; this is an explicit adapter guard, not a claim that
|
||||
-the pinned native issuer admitted duplicates. Tests use public/synthetic config
|
||||
-and mocked native calls only. Changed adapter bytes require a fresh reviewed
|
||||
-source/dependency and admission binding; old actual fixture receipts are retained.
|
||||
-The exact eight-field current consumer selector independently passes its offline
|
||||
-AST-only preflight. TLS public provenance/private custody, archive-time selector
|
||||
-binding, current owner recovery assent and outage-compatible actual consumer
|
||||
-proof remain open under T35/T36 and the existing owner tasks. No actual archive,
|
||||
-key, Secret object, token exchange, OpenBao login, rotation or native action was
|
||||
-performed. Source evidence and proposed owner declaration/consumer plan:
|
||||
-Custodian docs/changes/netkingdom-target-2026-10-17/native-identity-r1/.
|
||||
+2026-10-17 source checkpoint refinement: the completed exact-one original
|
||||
+selector guard and its bounded refusal/unique-selector proof are extracted into
|
||||
+T38. T36 retains exact archive-to-selector binding, current actual service-owner
|
||||
+recovery assent and outage-compatible private admission/consumer preparation.
|
||||
+The current eight-field source-selector correspondence is evidenced separately;
|
||||
+it does not complete those remaining obligations or any T18/T19 native gate.
|
||||
+T33 continues to require the complete reviewed TLS/custody/admission packet.
|
||||
+This extraction records one source outcome rather than counting it again as
|
||||
+original registration validation or consumer continuity.
|
||||
|
||||
## Verify actual SOPS compatibility and sealed-descriptor read/write custody
|
||||
|
||||
@@ -1188,6 +1180,51 @@
|
||||
T35 TLS/trust disposition and T36 original registration/private admission remain
|
||||
open under their existing owner boundaries.
|
||||
|
||||
+## Deliver exact-one original selector guard and bounded source refusal proof
|
||||
+
|
||||
+```task
|
||||
+id: NK-WP-0049-T38
|
||||
+status: done
|
||||
+priority: high
|
||||
+assignee: codex
|
||||
+depends_on: [NK-WP-0049-T34]
|
||||
+```
|
||||
+
|
||||
+Completed 2026-10-17 as source preparation, independently reviewed by the
|
||||
+coordinating Custodian agent. The adapter now requires exactly one selected
|
||||
+registration in the already-restored archive configuration before further runtime
|
||||
+environment reads, signer-key parsing or native checker invocation. Absent,
|
||||
+empty, identical-duplicate and conflicting-duplicate selectors refuse before
|
||||
+those later inputs; the existing unique-selector mocked native path still passes.
|
||||
+Current KeyCape Go configuration also rejects duplicate IDs; this makes the
|
||||
+adapter's own boundary explicit and establishes no native duplicate exploit.
|
||||
+The guard cannot run before archive decryption or the original key prompt.
|
||||
+
|
||||
+The 39 adapter checks passed, including four added early-refusal regressions.
|
||||
+Running those four cases against the retained original adapter failed the new
|
||||
+refusal contract as expected. The broader 77-check source run retained 76 passes
|
||||
+and one stale fixture-proposal source-hash refusal. Only the two affected hashes
|
||||
+and scope of that unexecuted/unapproved successor proposal were then refreshed;
|
||||
+all four affected fixture-plan checks passed. The original manifest preimage and
|
||||
+failure receipt remain retained, and frozen actual R6 runtime receipts were not
|
||||
+changed or claimed as proof of this successor. No broader native rerun occurred.
|
||||
+
|
||||
+Evidence: Custodian
|
||||
+`docs/changes/netkingdom-target-2026-10-17/native-identity-r1/`:
|
||||
+`owner-source.patch`, `verification.json`, `manifest.json`, retained preimages,
|
||||
+`original-behavior-regression.txt` and `focused-regressions.stderr.txt`.
|
||||
+The later task extraction and exact workplan successor bytes are in
|
||||
+`refinement-r2/`; the original source-proof packet remains immutable.
|
||||
+Canonical owner publication, allocator-assigned Hub UUID and projection must be
|
||||
+recorded separately through the normal owner process; none is claimed here.
|
||||
+
|
||||
+This completes only the source guard/refusal deliverable extracted from T36.
|
||||
+T35 original TLS public provenance/private custody or accepted reissue, T36 exact
|
||||
+archive binding/current owner assent/consumer custody preparation, T33 complete
|
||||
+attempt readiness, T18 actual recovery/consumer acceptance and T19 retained-factor
|
||||
+MFA remain open. No actual archive, private key, Secret object, token exchange,
|
||||
+OpenBao login, rotation, production action or owner assent was exercised.
|
||||
+
|
||||
## Accept remaining recovery and caller evidence and close the G08 handoff
|
||||
|
||||
```task
|
||||
@@ -1207,7 +1244,7 @@
|
||||
G08 receiving the final evidence. The completed archive/job milestones remain
|
||||
accepted independently of this final gate.
|
||||
|
||||
-**Done when:** T02 and T15–T37 have their stated completed or explicitly accepted
|
||||
+**Done when:** T02 and T15–T38 have their stated completed or explicitly accepted
|
||||
handoff outcomes; service authentication/token/audit proof and current/legacy
|
||||
caller dispositions are accepted; the source workplan and projected tasks agree;
|
||||
and G08 has an exact evidence/handoff record. Record actionable residuals as live
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
--- a/tools/bootstrap-recovery/isolated-keycape.py
|
||||
+++ b/tools/bootstrap-recovery/isolated-keycape.py
|
||||
@@ -322,6 +322,23 @@
|
||||
|
||||
|
||||
def run_verifier(session, admission, payload):
|
||||
+ # Select from the already-restored config before further private/runtime reads.
|
||||
+ # This is not public preflight before archive decryption or its key prompt.
|
||||
+ import yaml
|
||||
+ cfg = yaml.safe_load(base64.b64decode(payload['files']['/etc/keycape/config.yaml'],validate=True))
|
||||
+ if not isinstance(cfg,dict) or cfg.get('issuer') != admission['issuer']:
|
||||
+ raise Refused()
|
||||
+ consumer = admission['consumer']
|
||||
+ clients = cfg.get('clients')
|
||||
+ if not isinstance(clients,list) or any(not isinstance(client,dict) for client in clients):
|
||||
+ raise Refused()
|
||||
+ matches = [client for client in clients if client.get('clientId') == consumer['client_id']]
|
||||
+ if len(matches) != 1:
|
||||
+ raise Refused()
|
||||
+ client = matches[0]
|
||||
+ if (client.get('secretRef') != 'env:'+consumer['secret_env'] or client.get('clientType') != 'confidential'
|
||||
+ or 'client_credentials' not in client.get('grantTypes',[])):
|
||||
+ raise Refused()
|
||||
issuer = session['issuer']
|
||||
if {v['target'] for v in session.get('volumes',{}).values()}!={'/etc/keycape','/var/lib/keycape-policy','/etc/keycape-factor','/recovery-tls'}:raise Refused()
|
||||
from urllib.parse import urlsplit
|
||||
@@ -352,15 +369,7 @@
|
||||
if durable!={k:v for k,v in files.items() if k.startswith('/var/lib/keycape-policy/')}:
|
||||
raise Refused()
|
||||
equal()
|
||||
- # Reading YAML is data parsing only; no archived executable is evaluated.
|
||||
- import yaml
|
||||
- cfg = yaml.safe_load(files['/etc/keycape/config.yaml'])
|
||||
- if cfg['issuer'] != admission['issuer']:
|
||||
- raise Refused()
|
||||
- consumer = admission['consumer']
|
||||
- client = next(x for x in cfg['clients'] if x['clientId']==consumer['client_id'])
|
||||
- if (client['secretRef']!='env:'+consumer['secret_env'] or client['clientType']!='confidential'
|
||||
- or 'client_credentials' not in client['grantTypes'] or not env.get(consumer['secret_env'])):
|
||||
+ if not env.get(consumer['secret_env']):
|
||||
raise Refused()
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
key=serialization.load_pem_private_key(files['/etc/keycape/key.pem'],password=None)
|
||||
--- a/tests/test_isolated_keycape_recovery.py
|
||||
+++ b/tests/test_isolated_keycape_recovery.py
|
||||
@@ -53,6 +53,34 @@
|
||||
for row in self.manifest['files']:
|
||||
if row['path'].endswith('/deployment/keycape.json'):row.update(bytes=len(raw),sha256=hashlib.sha256(raw).hexdigest())
|
||||
with self.assertRaises(a.Refused):self.payload()
|
||||
+
|
||||
+
|
||||
+class OriginalSelectorTests(unittest.TestCase):
|
||||
+ """Already-restored public fixture config; no archive/key/native action."""
|
||||
+ def assert_refused_before_further_inputs(self,clients):
|
||||
+ import yaml
|
||||
+ cfg={'issuer':'https://issuer.example','clients':clients}
|
||||
+ payload={'files':{'/etc/keycape/config.yaml':base64.b64encode(yaml.safe_dump(cfg).encode()).decode(),
|
||||
+ '/etc/keycape/key.pem':'deliberately-not-base64'}}
|
||||
+ admission={'issuer':'https://issuer.example','consumer':{'client_id':'existing','secret_env':'KEYCAPE_ORIGINAL_SECRET'}}
|
||||
+ # Empty session/no env and an undecodable key also expose early private access.
|
||||
+ from contextlib import ExitStack
|
||||
+ with ExitStack() as stack:
|
||||
+ blocked=[stack.enter_context(patch.object(a,name,side_effect=AssertionError('later input or native call')))
|
||||
+ for name in ('container_file','runtime_file','runtime_files','command','check_jwks','process')]
|
||||
+ with self.assertRaises(a.Refused):a.run_verifier({},admission,payload)
|
||||
+ for call in blocked:call.assert_not_called()
|
||||
+ def client(self):
|
||||
+ return {'clientId':'existing','clientType':'confidential','secretRef':'env:KEYCAPE_ORIGINAL_SECRET',
|
||||
+ 'grantTypes':['client_credentials']}
|
||||
+ def test_absent_original_selector_refused_before_further_inputs(self):
|
||||
+ self.assert_refused_before_further_inputs([dict(self.client(),clientId='unrelated')])
|
||||
+ def test_identical_duplicate_selector_refused_before_further_inputs(self):
|
||||
+ self.assert_refused_before_further_inputs([self.client(),self.client()])
|
||||
+ def test_conflicting_duplicate_selector_refused_before_further_inputs(self):
|
||||
+ self.assert_refused_before_further_inputs([self.client(),dict(self.client(),secretRef='env:OTHER')])
|
||||
+ def test_empty_registry_refused_before_further_inputs(self):
|
||||
+ self.assert_refused_before_further_inputs([])
|
||||
|
||||
class NativeTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
--- a/tests/isolated-keycape-native-fixture-manifest.json
|
||||
+++ b/tests/isolated-keycape-native-fixture-manifest.json
|
||||
@@ -7,7 +7,7 @@
|
||||
"tests/run_isolated_keycape_native_fixture.py": "sha256:ecbadecc475622eaaf20a726110aebef5f4fe7af141110a98aca1640179b4a03",
|
||||
"tests/test_identity_bundle.py": "sha256:be5ce74097594cc7f7e77dbccd6cb53aa72f263cd1bb442ce5464038aed1116c",
|
||||
"tests/test_isolated_keycape_fixture_plan.py": "sha256:5945619f4c5957187763276cc900870a9f08f9475b63c240694688e0c2eca7dd",
|
||||
- "tests/test_isolated_keycape_recovery.py": "sha256:247e9a87f5be2ee9f20f7edbb4a9f612ab7cb0cd940392c3caeca8b046605f55",
|
||||
+ "tests/test_isolated_keycape_recovery.py": "sha256:5f729e077db51dd6b17d00dc3eb71c0e652849f55fe68505a07befa663c91dea",
|
||||
"tests/test_isolated_keycape_session.py": "sha256:cbdf51efde26eff337e9303a2c431f80b333b8846d763eb62853f81eb3f13e2c",
|
||||
"tools/bootstrap-recovery/capture-identity.py": "sha256:47dca7c4dc96fa7eb9fb02c81fca9ca8dc5281aac918979eb7367148168ba705",
|
||||
"tools/bootstrap-recovery/check-privacyidea-database.py": "sha256:90f454c87998d7f5d625e3c6656c3418f8f56275dc1879a9d19ed605431b94a4",
|
||||
@@ -25,7 +25,7 @@
|
||||
"tools/bootstrap-recovery/inventory-scaleway.py": "sha256:a219df205708fa4ed44b763a418585d63c820c25434bc0fd14e805eb5c2f79d3",
|
||||
"tools/bootstrap-recovery/inventory-storage-share.py": "sha256:673f9b17fb2f3fef6fcdb5c50a2bcca69e3df3157a9e5582a2d995c6b87640b5",
|
||||
"tools/bootstrap-recovery/isolated-keycape-session.py": "sha256:8fa38efe28167b59a6307f342b2ac8fcda78ecda60e6228f22017424d2343c22",
|
||||
- "tools/bootstrap-recovery/isolated-keycape.py": "sha256:f67627b7d1647d75187dd899874efe22383bc91de5d97dabb9801076668ab3c2",
|
||||
+ "tools/bootstrap-recovery/isolated-keycape.py": "sha256:86f37add7221e4c73e3f9d878c09a3cc81061627cbf024ed6887d973d929b718",
|
||||
"tools/bootstrap-recovery/isolated-lldap.py": "sha256:35bfa8411186ad936a199bd450c7e18c2ad51059301a6db9650e6bd055ab1b81",
|
||||
"tools/bootstrap-recovery/isolated-privacyidea.py": "sha256:4df7196678aac1ad594f32abf45c68dc21a9d2760d9e8a536a215a4a3c5d277f",
|
||||
"tools/bootstrap-recovery/prepare-identity-coverage.py": "sha256:cd5f3067d28b4c7cc93ed08b8cf3869218bdecf7c54b5dffed22d697de71dbb1",
|
||||
@@ -81,7 +81,7 @@
|
||||
"synthetic_source_root": "private /dev/shm/nk49-keycape-fixture-<suffix>",
|
||||
"safe_result": "private /tmp/nk49-keycape-native-fixture-review-<suffix>/result.json"
|
||||
},
|
||||
- "scope": "candidate itself on complete synthetic format/integrity archive fixture; no native PI/LLDAP/Authelia proof, real custody, real factor or real client credential; successor binds sealed-descriptor custody preparation sources; synthetic fixture itself overrides custody with generated fixture key as before",
|
||||
+ "scope": "candidate itself on complete synthetic format/integrity archive fixture; no native PI/LLDAP/Authelia proof, real custody, real factor or real client credential; successor binds sealed-descriptor custody preparation sources; synthetic fixture itself overrides custody with generated fixture key as before; unexecuted exact-one-selector adapter successor: no new native outcome inferred from earlier fixtures",
|
||||
"mutations": [
|
||||
"conditional creation of exact fresh local containers and local-driver tmpfs volumes",
|
||||
"private synthetic file import to those volumes",
|
||||
--- a/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md
|
||||
+++ b/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md
|
||||
@@ -1130,6 +1130,16 @@
|
||||
`recovery-owner-handoffs-r1` source review; independent ID/UUID/status/remote
|
||||
readback is recorded separately when performed.
|
||||
|
||||
+2026-10-17 source checkpoint refinement: the completed exact-one original
|
||||
+selector guard and its bounded refusal/unique-selector proof are extracted into
|
||||
+T38. T36 retains exact archive-to-selector binding, current actual service-owner
|
||||
+recovery assent and outage-compatible private admission/consumer preparation.
|
||||
+The current eight-field source-selector correspondence is evidenced separately;
|
||||
+it does not complete those remaining obligations or any T18/T19 native gate.
|
||||
+T33 continues to require the complete reviewed TLS/custody/admission packet.
|
||||
+This extraction records one source outcome rather than counting it again as
|
||||
+original registration validation or consumer continuity.
|
||||
+
|
||||
## Verify actual SOPS compatibility and sealed-descriptor read/write custody
|
||||
|
||||
```task
|
||||
@@ -1170,6 +1180,51 @@
|
||||
T35 TLS/trust disposition and T36 original registration/private admission remain
|
||||
open under their existing owner boundaries.
|
||||
|
||||
+## Deliver exact-one original selector guard and bounded source refusal proof
|
||||
+
|
||||
+```task
|
||||
+id: NK-WP-0049-T38
|
||||
+status: done
|
||||
+priority: high
|
||||
+assignee: codex
|
||||
+depends_on: [NK-WP-0049-T34]
|
||||
+```
|
||||
+
|
||||
+Completed 2026-10-17 as source preparation, independently reviewed by the
|
||||
+coordinating Custodian agent. The adapter now requires exactly one selected
|
||||
+registration in the already-restored archive configuration before further runtime
|
||||
+environment reads, signer-key parsing or native checker invocation. Absent,
|
||||
+empty, identical-duplicate and conflicting-duplicate selectors refuse before
|
||||
+those later inputs; the existing unique-selector mocked native path still passes.
|
||||
+Current KeyCape Go configuration also rejects duplicate IDs; this makes the
|
||||
+adapter's own boundary explicit and establishes no native duplicate exploit.
|
||||
+The guard cannot run before archive decryption or the original key prompt.
|
||||
+
|
||||
+The 39 adapter checks passed, including four added early-refusal regressions.
|
||||
+Running those four cases against the retained original adapter failed the new
|
||||
+refusal contract as expected. The broader 77-check source run retained 76 passes
|
||||
+and one stale fixture-proposal source-hash refusal. Only the two affected hashes
|
||||
+and scope of that unexecuted/unapproved successor proposal were then refreshed;
|
||||
+all four affected fixture-plan checks passed. The original manifest preimage and
|
||||
+failure receipt remain retained, and frozen actual R6 runtime receipts were not
|
||||
+changed or claimed as proof of this successor. No broader native rerun occurred.
|
||||
+
|
||||
+Evidence: Custodian
|
||||
+`docs/changes/netkingdom-target-2026-10-17/native-identity-r1/`:
|
||||
+`owner-source.patch`, `verification.json`, `manifest.json`, retained preimages,
|
||||
+`original-behavior-regression.txt` and `focused-regressions.stderr.txt`.
|
||||
+The later task extraction and exact workplan successor bytes are in
|
||||
+`refinement-r2/`; the original source-proof packet remains immutable.
|
||||
+Canonical owner publication, allocator-assigned Hub UUID and projection must be
|
||||
+recorded separately through the normal owner process; none is claimed here.
|
||||
+
|
||||
+This completes only the source guard/refusal deliverable extracted from T36.
|
||||
+T35 original TLS public provenance/private custody or accepted reissue, T36 exact
|
||||
+archive binding/current owner assent/consumer custody preparation, T33 complete
|
||||
+attempt readiness, T18 actual recovery/consumer acceptance and T19 retained-factor
|
||||
+MFA remain open. No actual archive, private key, Secret object, token exchange,
|
||||
+OpenBao login, rotation, production action or owner assent was exercised.
|
||||
+
|
||||
## Accept remaining recovery and caller evidence and close the G08 handoff
|
||||
|
||||
```task
|
||||
@@ -1189,7 +1244,7 @@
|
||||
G08 receiving the final evidence. The completed archive/job milestones remain
|
||||
accepted independently of this final gate.
|
||||
|
||||
-**Done when:** T02 and T15–T37 have their stated completed or explicitly accepted
|
||||
+**Done when:** T02 and T15–T38 have their stated completed or explicitly accepted
|
||||
handoff outcomes; service authentication/token/audit proof and current/legacy
|
||||
caller dispositions are accepted; the source workplan and projected tasks agree;
|
||||
and G08 has an exact evidence/handoff record. Record actionable residuals as live
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
{
|
||||
"credential_request_performed": false,
|
||||
"queries": [
|
||||
{
|
||||
"query": "original KeyCape ingress TLS certificate recovery independent custody",
|
||||
"candidates": [
|
||||
{
|
||||
"id": "keycape-client-secret-generate",
|
||||
"owner_repo": "railiance-platform",
|
||||
"resolvable": false,
|
||||
"warden_executes": false
|
||||
},
|
||||
{
|
||||
"id": "openrouter-llm-connect",
|
||||
"owner_repo": "railiance-platform",
|
||||
"resolvable": true,
|
||||
"warden_executes": false
|
||||
},
|
||||
{
|
||||
"id": "openbao-structure-survey",
|
||||
"owner_repo": "ops-mason",
|
||||
"resolvable": false,
|
||||
"warden_executes": false
|
||||
},
|
||||
{
|
||||
"id": "agent-harness-forgejo-deploy",
|
||||
"owner_repo": "railiance-platform",
|
||||
"resolvable": true,
|
||||
"warden_executes": false
|
||||
},
|
||||
{
|
||||
"id": "key-cape-oidc-login",
|
||||
"owner_repo": "key-cape",
|
||||
"resolvable": false,
|
||||
"warden_executes": false
|
||||
}
|
||||
],
|
||||
"interpretation": "Discovery only; no exact independent original TLS custody route or new credential authority inferred; unrelated generation/rotation lanes not selected."
|
||||
},
|
||||
{
|
||||
"query": "KeyCape secrets-engine-openbao client secret custody",
|
||||
"candidates": [
|
||||
{
|
||||
"id": "keycape-client-secret-generate",
|
||||
"owner_repo": "railiance-platform",
|
||||
"resolvable": false,
|
||||
"warden_executes": false
|
||||
},
|
||||
{
|
||||
"id": "rapp-qonto-keycape-client",
|
||||
"owner_repo": "key-cape",
|
||||
"resolvable": true,
|
||||
"warden_executes": false
|
||||
},
|
||||
{
|
||||
"id": "secrets-engine-approval-client-login",
|
||||
"owner_repo": "railiance-platform",
|
||||
"resolvable": true,
|
||||
"warden_executes": false
|
||||
},
|
||||
{
|
||||
"id": "database-dynamic-credentials",
|
||||
"owner_repo": "rapp-postgres",
|
||||
"resolvable": false,
|
||||
"warden_executes": false
|
||||
},
|
||||
{
|
||||
"id": "openbao-api-key",
|
||||
"owner_repo": "railiance-platform",
|
||||
"resolvable": false,
|
||||
"warden_executes": false
|
||||
}
|
||||
],
|
||||
"interpretation": "Discovery only; no exact independent original TLS custody route or new credential authority inferred; unrelated generation/rotation lanes not selected."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"command": [
|
||||
"python3",
|
||||
"tools/check-keycape-recovery-selector.py",
|
||||
"--selector",
|
||||
"docs/keycape-recovery-selector.json",
|
||||
"--source-sha256",
|
||||
"sha256:c0ade429edf452ad17f05d690b7ebef091db7f1a42b5ac350f1e40955c8586c0"
|
||||
],
|
||||
"exit_code": 0,
|
||||
"result": {
|
||||
"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,80 @@
|
|||
--- a/tools/bootstrap-recovery/isolated-keycape.py
|
||||
+++ b/tools/bootstrap-recovery/isolated-keycape.py
|
||||
@@ -322,6 +322,23 @@
|
||||
|
||||
|
||||
def run_verifier(session, admission, payload):
|
||||
+ # Select from the already-restored config before further private/runtime reads.
|
||||
+ # This is not public preflight before archive decryption or its key prompt.
|
||||
+ import yaml
|
||||
+ cfg = yaml.safe_load(base64.b64decode(payload['files']['/etc/keycape/config.yaml'],validate=True))
|
||||
+ if not isinstance(cfg,dict) or cfg.get('issuer') != admission['issuer']:
|
||||
+ raise Refused()
|
||||
+ consumer = admission['consumer']
|
||||
+ clients = cfg.get('clients')
|
||||
+ if not isinstance(clients,list) or any(not isinstance(client,dict) for client in clients):
|
||||
+ raise Refused()
|
||||
+ matches = [client for client in clients if client.get('clientId') == consumer['client_id']]
|
||||
+ if len(matches) != 1:
|
||||
+ raise Refused()
|
||||
+ client = matches[0]
|
||||
+ if (client.get('secretRef') != 'env:'+consumer['secret_env'] or client.get('clientType') != 'confidential'
|
||||
+ or 'client_credentials' not in client.get('grantTypes',[])):
|
||||
+ raise Refused()
|
||||
issuer = session['issuer']
|
||||
if {v['target'] for v in session.get('volumes',{}).values()}!={'/etc/keycape','/var/lib/keycape-policy','/etc/keycape-factor','/recovery-tls'}:raise Refused()
|
||||
from urllib.parse import urlsplit
|
||||
@@ -352,15 +369,7 @@
|
||||
if durable!={k:v for k,v in files.items() if k.startswith('/var/lib/keycape-policy/')}:
|
||||
raise Refused()
|
||||
equal()
|
||||
- # Reading YAML is data parsing only; no archived executable is evaluated.
|
||||
- import yaml
|
||||
- cfg = yaml.safe_load(files['/etc/keycape/config.yaml'])
|
||||
- if cfg['issuer'] != admission['issuer']:
|
||||
- raise Refused()
|
||||
- consumer = admission['consumer']
|
||||
- client = next(x for x in cfg['clients'] if x['clientId']==consumer['client_id'])
|
||||
- if (client['secretRef']!='env:'+consumer['secret_env'] or client['clientType']!='confidential'
|
||||
- or 'client_credentials' not in client['grantTypes'] or not env.get(consumer['secret_env'])):
|
||||
+ if not env.get(consumer['secret_env']):
|
||||
raise Refused()
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
key=serialization.load_pem_private_key(files['/etc/keycape/key.pem'],password=None)
|
||||
--- a/tests/test_isolated_keycape_recovery.py
|
||||
+++ b/tests/test_isolated_keycape_recovery.py
|
||||
@@ -53,6 +53,34 @@
|
||||
for row in self.manifest['files']:
|
||||
if row['path'].endswith('/deployment/keycape.json'):row.update(bytes=len(raw),sha256=hashlib.sha256(raw).hexdigest())
|
||||
with self.assertRaises(a.Refused):self.payload()
|
||||
+
|
||||
+
|
||||
+class OriginalSelectorTests(unittest.TestCase):
|
||||
+ """Already-restored public fixture config; no archive/key/native action."""
|
||||
+ def assert_refused_before_further_inputs(self,clients):
|
||||
+ import yaml
|
||||
+ cfg={'issuer':'https://issuer.example','clients':clients}
|
||||
+ payload={'files':{'/etc/keycape/config.yaml':base64.b64encode(yaml.safe_dump(cfg).encode()).decode(),
|
||||
+ '/etc/keycape/key.pem':'deliberately-not-base64'}}
|
||||
+ admission={'issuer':'https://issuer.example','consumer':{'client_id':'existing','secret_env':'KEYCAPE_ORIGINAL_SECRET'}}
|
||||
+ # Empty session/no env and an undecodable key also expose early private access.
|
||||
+ from contextlib import ExitStack
|
||||
+ with ExitStack() as stack:
|
||||
+ blocked=[stack.enter_context(patch.object(a,name,side_effect=AssertionError('later input or native call')))
|
||||
+ for name in ('container_file','runtime_file','runtime_files','command','check_jwks','process')]
|
||||
+ with self.assertRaises(a.Refused):a.run_verifier({},admission,payload)
|
||||
+ for call in blocked:call.assert_not_called()
|
||||
+ def client(self):
|
||||
+ return {'clientId':'existing','clientType':'confidential','secretRef':'env:KEYCAPE_ORIGINAL_SECRET',
|
||||
+ 'grantTypes':['client_credentials']}
|
||||
+ def test_absent_original_selector_refused_before_further_inputs(self):
|
||||
+ self.assert_refused_before_further_inputs([dict(self.client(),clientId='unrelated')])
|
||||
+ def test_identical_duplicate_selector_refused_before_further_inputs(self):
|
||||
+ self.assert_refused_before_further_inputs([self.client(),self.client()])
|
||||
+ def test_conflicting_duplicate_selector_refused_before_further_inputs(self):
|
||||
+ self.assert_refused_before_further_inputs([self.client(),dict(self.client(),secretRef='env:OTHER')])
|
||||
+ def test_empty_registry_refused_before_further_inputs(self):
|
||||
+ self.assert_refused_before_further_inputs([])
|
||||
|
||||
class NativeTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
{
|
||||
"status": "pre_edit_reviewed_public_source_snapshot",
|
||||
"references": [
|
||||
{
|
||||
"repo": "net-kingdom",
|
||||
"path": "AGENTS.md",
|
||||
"head_observed": "70f408ca2389bf3722a91a03832fc6e8587355e5",
|
||||
"worktree_sha256": "sha256:95158b1d5c15e6cf8be980f5c0e3b48aeef252654846273887f40516b3fa6a78",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "net-kingdom",
|
||||
"path": "SECURITY-COMPANION.md",
|
||||
"head_observed": "70f408ca2389bf3722a91a03832fc6e8587355e5",
|
||||
"worktree_sha256": "sha256:06374445ca888549f1bf79527d1345d94918d7a7ec363160d8427d0e7a31d643",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "net-kingdom",
|
||||
"path": "sso-mfa/k8s/keycape/ingress.yaml",
|
||||
"head_observed": "70f408ca2389bf3722a91a03832fc6e8587355e5",
|
||||
"worktree_sha256": "sha256:bc5c7524a82de5e8b9755e7d7d408b4a66e034424cb2663c1d21352d292d5a72",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "net-kingdom",
|
||||
"path": "tools/bootstrap-recovery/identity-backup-profile.json",
|
||||
"head_observed": "70f408ca2389bf3722a91a03832fc6e8587355e5",
|
||||
"worktree_sha256": "sha256:40f9e5b5bb957e5b23e03b31701702b850502d16a92a0fa0ebf92618cc3f18a1",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "net-kingdom",
|
||||
"path": "tools/bootstrap-recovery/isolated-keycape.py",
|
||||
"head_observed": "70f408ca2389bf3722a91a03832fc6e8587355e5",
|
||||
"worktree_sha256": "sha256:f67627b7d1647d75187dd899874efe22383bc91de5d97dabb9801076668ab3c2",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "net-kingdom",
|
||||
"path": "tools/bootstrap-recovery/isolated-keycape-session.py",
|
||||
"head_observed": "70f408ca2389bf3722a91a03832fc6e8587355e5",
|
||||
"worktree_sha256": "sha256:8fa38efe28167b59a6307f342b2ac8fcda78ecda60e6228f22017424d2343c22",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "net-kingdom",
|
||||
"path": "tools/bootstrap-recovery/prepare-isolated-keycape.py",
|
||||
"head_observed": "70f408ca2389bf3722a91a03832fc6e8587355e5",
|
||||
"worktree_sha256": "sha256:5098bdfa4e0ad30627c1716e5e355a2c78dca6ccc607bd2148a2e06126632288",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "net-kingdom",
|
||||
"path": "tools/bootstrap-recovery/run-isolated-keycape.sh",
|
||||
"head_observed": "70f408ca2389bf3722a91a03832fc6e8587355e5",
|
||||
"worktree_sha256": "sha256:0d994c9c14ebdffdbf7879bd7562042531083d0e8955424d0ae099898a141668",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "net-kingdom",
|
||||
"path": "workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md",
|
||||
"head_observed": "70f408ca2389bf3722a91a03832fc6e8587355e5",
|
||||
"worktree_sha256": "sha256:678ec04b73b57c026001791706c05c5d4d5a508a32f17210ae8ad03ab15d53b8",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "secrets-engine",
|
||||
"path": "AGENTS.md",
|
||||
"head_observed": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
|
||||
"worktree_sha256": "sha256:1b98e24f9eb35c4c56b96ee7cbac21919bbe3b928144bfa7f29cca1c3249d5d0",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "secrets-engine",
|
||||
"path": "src/secrets_engine/service_auth.py",
|
||||
"head_observed": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
|
||||
"worktree_sha256": "sha256:c0ade429edf452ad17f05d690b7ebef091db7f1a42b5ac350f1e40955c8586c0",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "secrets-engine",
|
||||
"path": "src/secrets_engine/engine_auth.py",
|
||||
"head_observed": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
|
||||
"worktree_sha256": "sha256:e0479cf6d8c13233cf99dc39491143478c021597941ae8b6ba0e37957a42f330",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "secrets-engine",
|
||||
"path": "docs/keycape-recovery-selector.json",
|
||||
"head_observed": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
|
||||
"worktree_sha256": "sha256:02077af3c18b24f5e4a85992a3d4d0df51a8e458de1e48b48f7eb5f482257012",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "secrets-engine",
|
||||
"path": "docs/keycape-isolated-recovery-selector.md",
|
||||
"head_observed": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
|
||||
"worktree_sha256": "sha256:ed23b0df3d4b49e4b76df795455153c805971ccd37886836c960f550709e0739",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "secrets-engine",
|
||||
"path": "tools/check-keycape-recovery-selector.py",
|
||||
"head_observed": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
|
||||
"worktree_sha256": "sha256:e3e5e3ee743a212247701d6cb40fcf5b7f19349126fa9b32cbef9a3cc9459150",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "secrets-engine",
|
||||
"path": "workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md",
|
||||
"head_observed": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
|
||||
"worktree_sha256": "sha256:b3cab4e8d14b3b03179fc72a6e9ce1c0ee840cfa3247c022c1324d60378bde5b",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "railiance-cluster",
|
||||
"path": "AGENTS.md",
|
||||
"head_observed": "6ae3f847c83da3402883453ee7110457bfb2d0d6",
|
||||
"worktree_sha256": "sha256:5cc7808a6d0e5cdebc7b3f13a0d7dce9cee5441ed6de4703b67cf3fe1800d45b",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "railiance-cluster",
|
||||
"path": "docs/keycape-tls-recovery-boundary.md",
|
||||
"head_observed": "6ae3f847c83da3402883453ee7110457bfb2d0d6",
|
||||
"worktree_sha256": "sha256:f4bcb1d1832c566f9c87793ed2a461c8cd8a00859dc4ae66cd3c160d7ceefa70",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "railiance-cluster",
|
||||
"path": "tools/public-tls-metadata.py",
|
||||
"head_observed": "6ae3f847c83da3402883453ee7110457bfb2d0d6",
|
||||
"worktree_sha256": "sha256:87c167e44f0fcf154c9f2afae2187bebd33e5f220c05f579c1233b58bfe4f30b",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "railiance-cluster",
|
||||
"path": "tools/cmd/railiance-backup-s2",
|
||||
"head_observed": "6ae3f847c83da3402883453ee7110457bfb2d0d6",
|
||||
"worktree_sha256": "sha256:35c60b7ccccd7b4d5a1cf2134c1f2ca78c45040a7ffcc55f2c32c385a0a682a3",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "railiance-cluster",
|
||||
"path": "workplans/RCLUSTER-WP-0018-keycape-original-tls-recovery.md",
|
||||
"head_observed": "6ae3f847c83da3402883453ee7110457bfb2d0d6",
|
||||
"worktree_sha256": "sha256:96d52b6dbae056399159632d50b32ccc6662e4f6d3677af154f7c8a3d618334b",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "key-cape",
|
||||
"path": "src/internal/config/validate.go",
|
||||
"head_observed": "834b0d06a13bb2ece9cc98392cb39ba0e2167ecb",
|
||||
"worktree_sha256": "sha256:8189ee82e7df74a2a4a1f53e213b1be0a5c737fd76d8f283f7ec9f8ed38c3a65",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "emergent-security",
|
||||
"path": "knowledge/cards/start.md",
|
||||
"head_observed": "6eead2a922ae2eb81593213f54bf1f35e1c9970f",
|
||||
"worktree_sha256": "sha256:698a18f4a8f97a43da75ed0767aa0425c970e17c04a9cbea75cfab719564cc5d",
|
||||
"worktree_matches_head": true
|
||||
},
|
||||
{
|
||||
"repo": "emergent-security",
|
||||
"path": "knowledge/cards/identity.md",
|
||||
"head_observed": "6eead2a922ae2eb81593213f54bf1f35e1c9970f",
|
||||
"worktree_sha256": "sha256:5137f088da301f2229d15f198e6b9a492f9e141eeb572cca37a44251f954fad0",
|
||||
"worktree_matches_head": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
{
|
||||
"status": "source_regressions_passed_not_native_assent",
|
||||
"canonical_changed_paths": [
|
||||
"tools/bootstrap-recovery/isolated-keycape.py",
|
||||
"tests/test_isolated_keycape_recovery.py",
|
||||
"tests/isolated-keycape-native-fixture-manifest.json",
|
||||
"workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md"
|
||||
],
|
||||
"changes": [
|
||||
{
|
||||
"path": "tools/bootstrap-recovery/isolated-keycape.py",
|
||||
"preimage_sha256": "sha256:f67627b7d1647d75187dd899874efe22383bc91de5d97dabb9801076668ab3c2",
|
||||
"postimage_sha256": "sha256:86f37add7221e4c73e3f9d878c09a3cc81061627cbf024ed6887d973d929b718"
|
||||
},
|
||||
{
|
||||
"path": "tests/test_isolated_keycape_recovery.py",
|
||||
"preimage_sha256": "sha256:247e9a87f5be2ee9f20f7edbb4a9f612ab7cb0cd940392c3caeca8b046605f55",
|
||||
"postimage_sha256": "sha256:5f729e077db51dd6b17d00dc3eb71c0e652849f55fe68505a07befa663c91dea"
|
||||
},
|
||||
{
|
||||
"path": "tests/isolated-keycape-native-fixture-manifest.json",
|
||||
"preimage_sha256": "sha256:1dcefbc7ca7b0c2be33135b1b7977b89ba657223ecbb1310cc691d151b3d916e",
|
||||
"postimage_sha256": "sha256:936ee435be04b27f391391e7dda02def69e153bde3adcce92d569f33f308db2e"
|
||||
},
|
||||
{
|
||||
"path": "workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md",
|
||||
"preimage_sha256": "sha256:678ec04b73b57c026001791706c05c5d4d5a508a32f17210ae8ad03ab15d53b8",
|
||||
"postimage_sha256": "sha256:5830c429f58a0317b28c7b4bcf22a1b46e6d01b41378cdae95f947c6d9317e44"
|
||||
}
|
||||
],
|
||||
"checks": [
|
||||
{
|
||||
"command": "PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -p test_isolated_keycape_recovery.py",
|
||||
"tests": 39,
|
||||
"exit_code": 0,
|
||||
"evidence": "tool result; includes existing full unique-selector mocked flow and four new pre-further-input refusal tests"
|
||||
},
|
||||
{
|
||||
"command": "PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -p test_isolated_keycape*.py",
|
||||
"tests": 77,
|
||||
"pass": 76,
|
||||
"errors": 1,
|
||||
"exit_code": 1,
|
||||
"evidence": "focused-regressions.stderr.txt",
|
||||
"finding": "unexecuted source manifest correctly refused changed adapter/test hashes; retained before two-hash/scope update"
|
||||
},
|
||||
{
|
||||
"command": "PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -p test_isolated_keycape_fixture_plan.py",
|
||||
"tests": 4,
|
||||
"exit_code": 0,
|
||||
"evidence": "tool result; only affected fixture-plan checks repeated after two-hash/scope refresh"
|
||||
},
|
||||
{
|
||||
"command": "git diff --check -- four changed paths",
|
||||
"exit_code": 0
|
||||
},
|
||||
{
|
||||
"command": "new refusal regressions against retained original adapter bytes",
|
||||
"tests": 4,
|
||||
"errors": 4,
|
||||
"expected_original_contract_failure": true,
|
||||
"evidence": "original-behavior-regression.txt"
|
||||
}
|
||||
],
|
||||
"limit": "All fixtures synthetic/mocked. Exact-one check runs on already-restored config, not before decryption or initial key prompt; no runtime action or credential source performed. Current native Go validation also rejects duplicate IDs.",
|
||||
"review_status": "pending root independent review; no owner publication/sync performed",
|
||||
"hub_writes": false,
|
||||
"frozen_runtime_receipts_changed": false,
|
||||
"task_status_changes": false
|
||||
}
|
||||
|
|
@ -0,0 +1,240 @@
|
|||
"""Rebuild source-only registration review; no native calls or source mutation."""
|
||||
from pathlib import Path
|
||||
import ast
|
||||
import dataclasses
|
||||
import datetime
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
sys.dont_write_bytecode = True
|
||||
import yaml
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
CUST = HERE.parents[3]
|
||||
NK = Path('/home/worsch/net-kingdom')
|
||||
WARDEN = Path('/home/worsch/ops-warden')
|
||||
AUDIT = Path('/home/worsch/audit-core')
|
||||
PLATFORM = Path('/home/worsch/railiance-platform')
|
||||
CHECKER = Path('/tmp/nk-checker-environment-r2-rebuild/keycape')
|
||||
CHECKER_DIGEST = 'sha256:be37738fe1c08259fb4f9ca0daf0f9301bfffc237e5bb38435525dfbf11ccff5'
|
||||
REGISTER = NK / 'sso-mfa/k8s/keycape/keycape-registration-adapter.py'
|
||||
refs = {}
|
||||
|
||||
def sha(data):
|
||||
return 'sha256:' + hashlib.sha256(data).hexdigest()
|
||||
|
||||
def source(path, symbols=()):
|
||||
path = Path(path)
|
||||
raw = path.read_bytes()
|
||||
item = {'path': str(path), 'sha256': sha(raw), 'bytes': len(raw)}
|
||||
if path.suffix == '.py':
|
||||
tree = ast.parse(raw)
|
||||
item['symbols'] = {n.name: {'line': n.lineno, 'end_line': n.end_lineno}
|
||||
for n in ast.walk(tree) if isinstance(n, (ast.FunctionDef, ast.ClassDef))
|
||||
and n.name in symbols}
|
||||
refs[str(path)] = item
|
||||
return raw
|
||||
|
||||
|
||||
def emit(name, value):
|
||||
(HERE / name).write_text(json.dumps(value, indent=2, sort_keys=True) + '\n')
|
||||
|
||||
before_paths = [NK / 'security-case-types/oidc-browser-relying-party/type.yaml',
|
||||
NK / 'security-cases/forgejo-netkingdom-oidc.yaml',
|
||||
NK / 'security-case-type-revisions/1.2/oidc-browser-relying-party/type.yaml',
|
||||
NK / 'security-case-type-revisions/1.2/oidc-browser-relying-party/examples/forgejo.yaml',
|
||||
NK / 'security-case-type-revisions/1.2/oidc-browser-relying-party/decision/acknowledgment.json',
|
||||
NK / 'workplans/NK-WP-0048-security-case-types.md']
|
||||
before = {str(p): sha(source(p)) for p in before_paths}
|
||||
for p in [NK / 'AGENTS.md', WARDEN / 'AGENTS.md', NK / 'SECURITY-COMPANION.md',
|
||||
WARDEN / 'INTENT.md', NK / 'canon/standards/security-case-types_v0.1.md',
|
||||
NK / 'docs/security-case-execution-owner-review.md',
|
||||
NK / 'sso-mfa/k8s/keycape/registration-adapter.md',
|
||||
WARDEN / 'docs/security-case-execution-kernel-v1.md',
|
||||
WARDEN / 'workplans/WARDEN-WP-0044-security-case-follow-through.md',
|
||||
AUDIT / 'docs/audit-backend-contract.md',
|
||||
CUST / 'docs/changes/netkingdom-target-2026-10-16/browser-checker-environment-r2/build-receipt.json',
|
||||
CUST / 'docs/changes/netkingdom-target-2026-10-16/browser-checker-artifact-next/coordinator-build-review.json']:
|
||||
source(p)
|
||||
source(REGISTER, ['build', 'source_digest', 'descriptor', 'execute', 'verify', 'checker_snapshot'])
|
||||
source(WARDEN / 'src/warden/case_run.py', ['Journal', 'load', 'save', 'Executor', 'admit', 'run', 'rollback', 'reconcile', '_attempt', '_result'])
|
||||
source(WARDEN / 'src/warden/case_receipt_state.py', ['recover', 'begin_rollback'])
|
||||
source(WARDEN / 'src/warden/case_inputs.py', ['BrowserInputs', 'target'])
|
||||
source(NK / 'tools/security-case-types/security_case_evidence.py', ['read_journal', 'check_steps', 'audit'])
|
||||
source(NK / 'tools/security-case-types/security_case_validator.py', ['load_type', 'validate_execution_descriptors'])
|
||||
source(NK / 'sso-mfa/k8s/keycape/test_keycape_registration_adapter.py', ['test_process_loss_does_not_reconstruct_created_authority', 'test_kernel_lost_readback_retains_uncertain_and_refuses_replay_and_undo'])
|
||||
source(AUDIT / 'audit_core/ingestion.py', ['_read', 'normalize'])
|
||||
source(AUDIT / 'audit_core/senders.py', ['SenderIdentity', 'evidence_declaration'])
|
||||
source(AUDIT / 'audit_core/interface.py', ['AuditEvent', 'AcceptResult'])
|
||||
source(PLATFORM / 'scripts/keycape_client_secret_generate.py', ['check_case', 'run', 'record_state_hub'])
|
||||
|
||||
# Generate the one existing real owner descriptor from current maintained source.
|
||||
# Importing this source installs no adapters and performs no tooling operation.
|
||||
sys.path.insert(0, str(WARDEN / 'src'))
|
||||
spec = importlib.util.spec_from_file_location('registration_review_adapter', REGISTER)
|
||||
adapter = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(adapter)
|
||||
from warden.case_run import Descriptor
|
||||
for name in adapter.SOURCE_FILES:
|
||||
source(REGISTER.parent / name)
|
||||
checker_bytes = CHECKER.read_bytes()
|
||||
if sha(checker_bytes) != CHECKER_DIGEST:
|
||||
raise SystemExit('reviewed existing checker bytes no longer match; stop')
|
||||
source(CHECKER)
|
||||
desc = adapter.descriptor(CHECKER_DIGEST)
|
||||
descriptor_bytes = json.dumps(dataclasses.asdict(desc), sort_keys=True, separators=(',', ':')).encode()
|
||||
if Descriptor.decode(descriptor_bytes) != desc:
|
||||
raise SystemExit('actual owner descriptor decode failed')
|
||||
(HERE / 'register-client.proposed-descriptor.json').write_bytes(descriptor_bytes)
|
||||
|
||||
# Preserve real source versions and list every actual follow-through boundary.
|
||||
types = {}
|
||||
for version, root in [('1.1', NK / 'security-case-types'), ('1.2', NK / 'security-case-type-revisions/1.2')]:
|
||||
typ = yaml.safe_load((root / 'oidc-browser-relying-party/type.yaml').read_text())
|
||||
types[version] = typ
|
||||
if typ['spec'].get('execution_descriptors'):
|
||||
raise SystemExit('owner source gained descriptor admission; review must be refreshed')
|
||||
|
||||
remaining = {
|
||||
'ensure-groups': {'owner': 'net-kingdom', 'existing_seam': 'identity-provisioner governed journal T14 with delivered PostgreSQL T21',
|
||||
'missing': ['native dedicated CNPG consumer, checkpoint holder and backup/lost-store continuity', 'authoritative tenant/case/source/principal callbacks', 'all LDAP writers fenced or provider CAS/ABA exclusion', 'exact owner adapter/source/descriptor and revocation evidence; existing legacy ensure/revoke is not created-only undo'],
|
||||
'rollback': 'Only independently authenticated created groups/memberships; preserve shared/preexisting membership and unresolved intents.'},
|
||||
'mint-secret': {'owner': 'railiance-platform', 'existing_seam': 'scripts/keycape_client_secret_generate.py; RPF-WP-0054 and existing broker lane',
|
||||
'missing': ['fixed kernel Adapter/Descriptor for exact admitted case/type and broker source', 'authoritative case materialization receipt and original CAS0 uncertainty reconciliation', 'independent broker-grant AND parent-session revocation receipts for exact current attempt'],
|
||||
'rollback': 'Never regenerate after uncertain write; read-only metadata reconciliation does not establish creation or retry authority; owner custody delete only if exact created-only entitlement.'},
|
||||
'deliver-secret': {'owner': 'railiance-platform', 'existing_seam': 'existing ESO delivery/role and structural materialization boundary',
|
||||
'missing': ['exact delivery object UID/ownerReference prestate and admitted owner adapter', 'current Ready status/readback without value access', 'independent cleanup/revocation receipt and owner custody identity'],
|
||||
'rollback': 'Delete only authenticated case-created delivery objects, preserve preexisting target and shared resources.'},
|
||||
'bind-env': {'owner': 'net-kingdom', 'existing_seam': 'existing sso/keycape Deployment prerequisite checked by keycape-client.py; T12',
|
||||
'missing': ['reviewed fixed exact Deployment UID/resourceVersion/env binding update adapter', 'created-only prestate/readback and owner evidence/session capabilities', 'separately reviewed quiet-window restart/readiness procedure; registry helper only reports restart_required'],
|
||||
'rollback': 'Restore only exact case-created env binding under current revision; a whole Deployment rollback or deleting preexisting env is not admitted.'},
|
||||
'register-client': {'owner': 'net-kingdom', 'existing_seam': 'keycape-registration-adapter.py build/publish/authenticate/revoke_session injection seam',
|
||||
'missing': ['actual admitted durable owner publisher/authenticator and exact parent-session revoker', 'native executable storage/provenance and exact descriptor/type source admission', 'T15 original-attempt recovery contract; fresh adapter intentionally cannot undo prior-process creation'],
|
||||
'rollback': 'Same-process authenticated successful creation only; exact original entry and unchanged postcreation UID/resourceVersion; post-restart stays refused.'},
|
||||
'deliver-consumer-secret': {'owner': 'railiance-apps for Forgejo', 'existing_seam': 'acknowledged source1.2 dedicated SA/namespace SecretStore/ExternalSecret composition',
|
||||
'missing': ['actual installed ESO TokenRequest/RBAC compatibility and consumer owner admission', 'fixed owner adapter/descriptor for exact identities with created/preexisting readback', 'receiver evidence for Ready status and case-issued token revocation/expiry'],
|
||||
'rollback': 'Revert consumer reference first; delete only authenticated created UID/ownerReference resources; SA/Store deletion alone does not immediately revoke OpenBao tokens.'},
|
||||
'hand-over': {'owner': 'railiance-apps for Forgejo', 'existing_seam': 'consumer owner OIDC configuration and groups enforcement path',
|
||||
'missing': ['owner exact deployment/source adapter/descriptor and accepted issuer/client/delivery binding', 'actual human login/group-denial and public authorization/MFA pin verifications', 'rollback and native receipt/custody acceptance'],
|
||||
'rollback': 'Remove only this case-created OIDC source; preserve shared/preexisting auth sources and consumer state.'},
|
||||
}
|
||||
composition = []
|
||||
for step in types['1.2']['spec']['follow_through']:
|
||||
name = step['id']; item = remaining[name]
|
||||
composition.append({'step': name, 'source_order': len(composition) + 1,
|
||||
'declared_owner': step['owner'], 'resolved_first_consumer_owner': item['owner'],
|
||||
'exists_in_default_1_1': name in [s['id'] for s in types['1.1']['spec']['follow_through']],
|
||||
'source_step': step, 'existing_seam': item['existing_seam'],
|
||||
'candidate_descriptor': json.loads(descriptor_bytes) if name == 'register-client' else None,
|
||||
'candidate_descriptor_digest': sha(descriptor_bytes) if name == 'register-client' else None,
|
||||
'missing_exact_owner_facts': item['missing'], 'rollback_requirement': item['rollback'],
|
||||
'native_owner_assent': False, 'dispatch_permitted': False})
|
||||
if set(remaining) != {s['id'] for s in types['1.2']['spec']['follow_through']}:
|
||||
raise SystemExit('composition is incomplete for actual1.2 step inventory')
|
||||
|
||||
emit('descriptor-composition.json', {
|
||||
'schema': 'custodian.registration-descriptor-review.v1',
|
||||
'purpose': 'Review inventory only; this is not a Warden descriptor bundle or accepted SecurityCaseType.',
|
||||
'source_versions': {v: {'status': t['spec']['status'], 'step_count': len(t['spec']['follow_through']), 'machine_descriptor_map_present': False} for v, t in types.items()},
|
||||
'proposed_version_selection': {'first_consumer': 'Forgejo', 'review_base': 'explicit source-only oidc-browser-relying-party@1.2',
|
||||
'why': 'Its dedicated consumer SA/ESO authentication boundary expresses the reviewed six-object structural design;1.1 does not.',
|
||||
'default_loader': 'Keep canonical1.1 unchanged; select1.2 only through existing explicit version-root option for source review.',
|
||||
'canonical_case': 'Keep1.1 accepted history unchanged and1.2 example proposed without acceptance fields.',
|
||||
'descriptor_revision': 'Do not edit acknowledged source1.1/1.2 in place or inherit old acknowledgment for new descriptor bytes. Allocate the exact successor revision/version through NetKingdom canon section6 after the complete owner-reviewed set exists.',
|
||||
'classification': 'Exact closed execution references and any changed trust/materialization/authentication must be classified by the existing owner; changed trust/authentication requires informed-decision acknowledgment, never self-classified as harmless validation.'},
|
||||
'checker': {'path': str(CHECKER), 'sha256': CHECKER_DIGEST, 'bytes': len(checker_bytes), 'native_custody_admitted': False,
|
||||
'runtime_contract': 'Current owner adapter rehashes source/file, snapshots exact checker into sealed memfd, executes same snapshot for live/proposed checks with empty environment; this does not establish parent-directory/interpreter/kernel custody.'},
|
||||
'register_descriptor': {'path': 'register-client.proposed-descriptor.json', 'sha256': sha(descriptor_bytes), 'owner_source_composition': desc.adapter_source,
|
||||
'decode': 'Actual Warden Descriptor.decode round-trip passed; no Executor admission or tooling invocation performed.'},
|
||||
'composition': composition,
|
||||
'verification_inventory': types['1.2']['spec']['verification'],
|
||||
'rollback_inventory': types['1.2']['spec']['rollback'],
|
||||
'run_order_and_completion': [
|
||||
'Accepted exact case source and independently verified six-object native structural materialization before follow-through; a file status or rendered bundle is insufficient.',
|
||||
'Preserve existing source follow-through order. Delivery Ready and exact Deployment env prerequisite before registry apply. Separate quiet-window restart/readiness after checked registration before real sign-in; registry changed receipt alone is not service activation.',
|
||||
'Warden rechecks actual caller principal/actor/lane before each admitted dispatch. A session revoked at a step cannot be reused for later steps; owner must define fresh-session or admitted run-envelope grouping without weakening parent-session revocation.',
|
||||
'Mint must carry separately authenticated broker-grant and parent-session revocation; every completed step requires independently authenticated owner and session evidence.',
|
||||
'Verification is the complete declared positive/negative inventory plus actual human login/group denial. Reverse only independently confirmed creations, retaining uncertain intents and preserving shared/preexisting objects.'
|
||||
],
|
||||
'complete_executable_descriptor_set': False,
|
||||
'missing_descriptor_steps': [s['step'] for s in composition if s['candidate_descriptor'] is None],
|
||||
'native_complete': False, 'execution_permitted': False,
|
||||
})
|
||||
|
||||
emit('original-attempt-review.json', {
|
||||
'schema': 'custodian.registration-original-attempt-review.v1',
|
||||
'task': 'NK-WP-0048-T15', 'disposition': 'Existing seams inspected; no admitted original-attempt holder/readback matches. Source contract review only; recovery remains refused.',
|
||||
'actual_source_findings': [
|
||||
{'source': str(REGISTER), 'symbol': 'build/execute/verify', 'fact': 'records and creation live only in the build closure; original payload publication is injected. Rebuilding the Adapter loses original creation, even if caller retains OwnerResult. Adapter.reconcile is absent.'},
|
||||
{'source': str(WARDEN / 'src/warden/case_run.py'), 'symbol': 'Journal.save/load', 'fact': 'Durable rows keep attempt_id/operation and exact pins/created history but only digest(evidence identifier), digest(session reference) and digest(grant reference), not original owner payload or recoverable evidence identifier. Journal.load returns StepState and drops persisted attempt context.'},
|
||||
{'source': str(WARDEN / 'src/warden/case_run.py'), 'symbol': 'Executor.run/reconcile/_attempt', 'fact': 'Crash recovery appends recovered state without invocation/evidence; historical intent rows remain but latest may have no original attempt identity. reconcile creates a fresh attempt identity and calls Adapter.reconcile(new_invocation), supplying no original attempt reference.'},
|
||||
{'source': str(NK / 'tools/security-case-types/security_case_evidence.py'), 'symbol': 'read_journal/check_steps', 'fact': 'Read-only compatibility projection takes latest rows and explicitly returns native_authenticated false. It is not a holder authenticator or recovery authority.'},
|
||||
{'source': str(AUDIT / 'audit_core/ingestion.py'), 'symbol': '_read/normalize', 'fact': 'Existing authenticated POST/v1/events and privileged tenant-filtered GET/v1/events/{event_id} can supply custody/readback, but this source review found no registration publisher/class admission or owner authenticator wiring to that surface. Generic custody readiness is not creation attribution.'},
|
||||
{'source': str(AUDIT / 'audit_core/senders.py'), 'symbol': 'SenderIdentity', 'fact': 'Sender credential restricts allowed source/tenant; may_write does not imply may_read. Evidence defaults attributive; rollback-load-bearing source requires explicit owner declaration and emission atomicity/detection contract.'}
|
||||
],
|
||||
'reviewed_existing_holder_candidates': [
|
||||
{'holder': 'Warden private SQLite Journal', 'use': 'Original intent/sequence lookup from existing immutable history rows after source/owner integrity checks.', 'not_sufficient': 'Has only hashed evidence references and reducer state; it cannot authenticate original creation or supply missing owner bytes.'},
|
||||
{'holder': 'Actual registration owner publish/authenticate callbacks', 'use': 'The existing fixed injected owner capability is the intended successful-attempt custody seam.', 'not_sufficient': 'No native implementation, named holder or authenticated readback capability is present. The in-test dict authenticator is synthetic only.'},
|
||||
{'holder': 'Audit Core existing event custody/readback', 'use': 'A concrete existing provider to consider, with source/tenant-scoped sender and separate reader through existing owner admission process.', 'not_sufficient': 'Not selected or admitted for registration; no invented registration sender, token, event authority, runtime verifier or new backend is created.'},
|
||||
{'holder': 'State Hub progress/request, JSON receipt, current matching registry', 'use': 'Diagnostic/source references only.', 'not_sufficient': 'No creation custody/provenance guarantee. A current matching entry cannot distinguish an original successful write from preexisting or same-byte foreign creation.'}
|
||||
],
|
||||
'proposed_recovery_sequence_through_existing_seams': [
|
||||
'Re-admit exact case/type/descriptor/catalog/acceptance and new current caller principal/actor/lane through normal Executor.admit. No old session is resurrected.',
|
||||
'Under existing Journal process lock, owner retrieves original intended run attempt from immutable history: exact step/target/pins and original attempt_id/operation. Fresh reconcile attempt_id is distinct and must never substitute for this original identity.',
|
||||
'The selected admitted owner lookup authenticates exact original netkingdom.keycape-registration.attempt.v1 bytes by original attempt_id and admitted source scope. A case-supplied path, JSON payload or evidence identifier is not a capability. Journal fingerprints only detect correspondence after independent authentication.',
|
||||
'Validate original payload against original full Invocation, current admission pins, reviewed adapter/helper/checker source, created-only SUCCESS (not NO_CHANGE), exact owner/target, before/after UID/resourceVersion and original session-revocation evidence. Tenant/realm provenance must come from the actual admitted owner/session context; Invocation has no independent tenant field, so do not add a caller label as a substitute.',
|
||||
'Independently attest original result/session evidence; inspect current native registry through the maintained contained owner helper and match original exact created entry plus unchanged postcreation UID/resourceVersion. Hash equality alone and same client_id are insufficient.',
|
||||
'Bind lookup result and original provenance to the NEW reconcile attempt and newly revoked parent-session evidence. Preserve original record and current uncertainty. Only after owner-reviewed provenance hydration and normal kernel verification could subsequent independently authorized rollback consider that exact creation.',
|
||||
'If original receipt was never durably published, is missing/ambiguous/stale, shows NO_CHANGE, mismatches tenant/case/source/principal, or native revision drifted, retain UNCERTAIN and refuse add replay and undo. Do not infer FAILED_BEFORE from missing evidence. Lost-write/readback cases require attended owner reconciliation; no automatic creation attribution is introduced.'
|
||||
],
|
||||
'minimal_exact_owner_facts_before_implementation': [
|
||||
{'owner': 'ops-warden; existing WARDEN-WP-0044-T03', 'fact': 'Approve exact original-intent lookup in existing Journal history and how original Invocation/evidence identifier is handed to a fixed reconciler alongside the fresh reconcile Invocation. Current method supplies only fresh attempt. Preserve historical rows and current no-replay behavior.'},
|
||||
{'owner': 'NetKingdom registration evidence owner with Warden admission', 'fact': 'Name the actual existing publish/authenticate holder and its bounded authenticated original-attempt readback; supply public interface/source/tenant/principal provenance references and loss/unavailable/ambiguous dispositions. No secret value or new backend is requested.'},
|
||||
{'owner': 'audit-core only if actual selected holder', 'fact': 'Admit the registration source/event class and load-bearing completeness/intent-to-result custody contract, concrete event-id/original-attempt mapping, normalized-data equality/redaction policy and separate tenant-scoped reader. Generic POST acceptance or counts do not authenticate native creation.'},
|
||||
{'owner': 'Warden caller-session/revocation owner', 'fact': 'Name actual original and current session evidence purposes and verifier/capability source; original revocation does not authorize a new session, and each new reconcile/rollback attempt must revoke its own parent.'}
|
||||
],
|
||||
'targeted_existing_fixture_coverage': {'not_rerun': True, 'source': str(NK / 'sso-mfa/k8s/keycape/test_keycape_registration_adapter.py'),
|
||||
'existing_cases': ['test_process_loss_does_not_reconstruct_created_authority', 'test_missing_or_tampered_evidence_never_verifies_or_authorizes_undo', 'test_kernel_lost_readback_retains_uncertain_and_refuses_replay_and_undo'],
|
||||
'limits': 'Current synthetic Kubernetes/dict trust tests prove refusal; none supply original native custody. No duplicate fixture framework or fake native tests added.'},
|
||||
'implementation_disposition': 'No source guard/adapter change is justified until the listed existing owner contracts identify authority. Existing fail-closed behavior is retained.',
|
||||
'task_done': False, 'native_acceptance': False, 'retry_authorized': False, 'rollback_authorized': False,
|
||||
})
|
||||
|
||||
# Read-only source selection demonstrates the actual default/version boundaries.
|
||||
cli = NK / 'tools/security-case-types/security_case_validator.py'
|
||||
commands = [
|
||||
[sys.executable, '-B', str(cli), 'render', str(before_paths[1]), '--types', str(NK / 'security-case-types'), '--repos-root', '/home/worsch', '--allow-unimplemented'],
|
||||
[sys.executable, '-B', str(cli), 'render', str(before_paths[3]), '--types', str(NK / 'security-case-types'), '--version-root', '1.2=' + str(NK / 'security-case-type-revisions/1.2'), '--repos-root', '/home/worsch', '--allow-unimplemented'],
|
||||
[sys.executable, '-B', str(cli), 'validate-case', str(before_paths[3]), '--types', str(NK / 'security-case-types'), '--version-root', '1.2=' + str(NK / 'security-case-type-revisions/1.2')]
|
||||
]
|
||||
results=[]
|
||||
for command in commands:
|
||||
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=30, env={'PATH': '/usr/bin:/bin', 'PYTHONDONTWRITEBYTECODE': '1'})
|
||||
row = {'argv': command, 'returncode': result.returncode, 'stdout_sha256': sha(result.stdout), 'stderr': result.stderr.decode()}
|
||||
if result.returncode == 0 and command[3] == 'render':
|
||||
data=json.loads(result.stdout); row.update(type=data['type'], render_digest=data['digest'], execution_permitted=data['execution']['permitted'])
|
||||
results.append(row)
|
||||
if [r['returncode'] for r in results] != [0,0,1] or any(r.get('execution_permitted') is not False for r in results[:2]):
|
||||
raise SystemExit('actual source-selection/refusal behavior changed; inspect results')
|
||||
after = {str(p): sha(p.read_bytes()) for p in before_paths}
|
||||
if before != after:
|
||||
raise SystemExit('reviewed canonical bytes changed during source inspection')
|
||||
emit('source-verification.json', {'observed_at': datetime.datetime.now(datetime.timezone.utc).isoformat(),
|
||||
'checks': results, 'canonical_pre_post_hashes_equal': True, 'canonical_hashes': after,
|
||||
'descriptor_round_trip': True, 'checker_rehash_matches_delivered_artifact': True,
|
||||
'closed_descriptor_count': 1, 'complete_review_step_count': len(composition),
|
||||
'native_execution': False, 'tests_added_or_rerun': False,
|
||||
'knowledge': {'package_version': '0.2.6', 'package_digest': '8d1d6a9d4d07fec7b619618de7dfe2254c1790f85f4198c7fe19db9751c02',
|
||||
'cards': ['start','evidence'], 'status': 'withheld source changed; direct owner source reviewed, no offline guidance used as authority'}})
|
||||
audit_path = CUST / 'docs/changes/netkingdom-target-2026-10-17/native-gates-r1/native-gate-audit.json'
|
||||
if sha(audit_path.read_bytes()) != 'sha256:ab803e795af61fd027f5930d127592316133de38b68a8fe61b89a1f9803a9ff2':
|
||||
raise SystemExit('immutable prior audit changed')
|
||||
emit('source-manifest.json', {'sources': list(refs.values()), 'original_audit_immutable': {
|
||||
'path': str(CUST / 'docs/changes/netkingdom-target-2026-10-17/native-gates-r1/native-gate-audit.json'),
|
||||
'expected_sha256': 'sha256:ab803e795af61fd027f5930d127592316133de38b68a8fe61b89a1f9803a9ff2'}})
|
||||
print(json.dumps({'descriptor_sha256': sha(descriptor_bytes), 'descriptor_owner_source': desc.adapter_source,
|
||||
'complete_step_inventory': len(composition), 'source_checks': [r['returncode'] for r in results],
|
||||
'native_authority': False}))
|
||||
|
|
@ -0,0 +1,402 @@
|
|||
{
|
||||
"checker": {
|
||||
"bytes": 13633409,
|
||||
"native_custody_admitted": false,
|
||||
"path": "/tmp/nk-checker-environment-r2-rebuild/keycape",
|
||||
"runtime_contract": "Current owner adapter rehashes source/file, snapshots exact checker into sealed memfd, executes same snapshot for live/proposed checks with empty environment; this does not establish parent-directory/interpreter/kernel custody.",
|
||||
"sha256": "sha256:be37738fe1c08259fb4f9ca0daf0f9301bfffc237e5bb38435525dfbf11ccff5"
|
||||
},
|
||||
"complete_executable_descriptor_set": false,
|
||||
"composition": [
|
||||
{
|
||||
"candidate_descriptor": null,
|
||||
"candidate_descriptor_digest": null,
|
||||
"declared_owner": "net-kingdom",
|
||||
"dispatch_permitted": false,
|
||||
"existing_seam": "identity-provisioner governed journal T14 with delivered PostgreSQL T21",
|
||||
"exists_in_default_1_1": true,
|
||||
"missing_exact_owner_facts": [
|
||||
"native dedicated CNPG consumer, checkpoint holder and backup/lost-store continuity",
|
||||
"authoritative tenant/case/source/principal callbacks",
|
||||
"all LDAP writers fenced or provider CAS/ABA exclusion",
|
||||
"exact owner adapter/source/descriptor and revocation evidence; existing legacy ensure/revoke is not created-only undo"
|
||||
],
|
||||
"native_owner_assent": false,
|
||||
"resolved_first_consumer_owner": "net-kingdom",
|
||||
"rollback_requirement": "Only independently authenticated created groups/memberships; preserve shared/preexisting membership and unresolved intents.",
|
||||
"source_order": 1,
|
||||
"source_step": {
|
||||
"attended": true,
|
||||
"attended_justification": "The provisioner's only HTTP credential is user-engine's runtime token, and its NetworkPolicy admits only user-engine pods. A proxy lane would act as user-engine (ops-warden review R8; canon section 3; ops-warden ADR-0002). Running it in the session register-client already needs adds no attended session. It can become unattended once the provisioner has an operator credential of its own and an admitted path.",
|
||||
"auth": "operator cluster access in the attended register-client session; the in-pod call uses the provisioner's own directory binding, and no provisioner or user-engine token is read or sent",
|
||||
"entry_point": "identity-provisioner ensure_service_groups, run inside the provisioner pod through the session's contained cluster access (groups {access_groups}; members exactly {initial_members} as recorded in the accepted case, nothing else)",
|
||||
"id": "ensure-groups",
|
||||
"lane": "key-cape-oidc-login",
|
||||
"owner": "net-kingdom",
|
||||
"value_handling": "none",
|
||||
"warden_executes": false
|
||||
},
|
||||
"step": "ensure-groups"
|
||||
},
|
||||
{
|
||||
"candidate_descriptor": null,
|
||||
"candidate_descriptor_digest": null,
|
||||
"declared_owner": "railiance-platform",
|
||||
"dispatch_permitted": false,
|
||||
"existing_seam": "scripts/keycape_client_secret_generate.py; RPF-WP-0054 and existing broker lane",
|
||||
"exists_in_default_1_1": true,
|
||||
"missing_exact_owner_facts": [
|
||||
"fixed kernel Adapter/Descriptor for exact admitted case/type and broker source",
|
||||
"authoritative case materialization receipt and original CAS0 uncertainty reconciliation",
|
||||
"independent broker-grant AND parent-session revocation receipts for exact current attempt"
|
||||
],
|
||||
"native_owner_assent": false,
|
||||
"resolved_first_consumer_owner": "railiance-platform",
|
||||
"rollback_requirement": "Never regenerate after uncertain write; read-only metadata reconciliation does not establish creation or retry authority; owner custody delete only if exact created-only entitlement.",
|
||||
"source_order": 2,
|
||||
"source_step": {
|
||||
"attended": false,
|
||||
"auth": "the caller's broker grant for the case's KV path, through its lane; the value is generated in custody and never returned",
|
||||
"entry_point": "railiance-platform credential broker: generate a client secret inside custody at bao:platform/workloads/keycape/{client_id}",
|
||||
"id": "mint-secret",
|
||||
"lane": "keycape-client-secret-generate",
|
||||
"owner": "railiance-platform",
|
||||
"value_handling": "generated_in_custody",
|
||||
"warden_executes": true,
|
||||
"when": "client_type == confidential"
|
||||
},
|
||||
"step": "mint-secret"
|
||||
},
|
||||
{
|
||||
"candidate_descriptor": null,
|
||||
"candidate_descriptor_digest": null,
|
||||
"declared_owner": "railiance-platform",
|
||||
"dispatch_permitted": false,
|
||||
"existing_seam": "existing ESO delivery/role and structural materialization boundary",
|
||||
"exists_in_default_1_1": true,
|
||||
"missing_exact_owner_facts": [
|
||||
"exact delivery object UID/ownerReference prestate and admitted owner adapter",
|
||||
"current Ready status/readback without value access",
|
||||
"independent cleanup/revocation receipt and owner custody identity"
|
||||
],
|
||||
"native_owner_assent": false,
|
||||
"resolved_first_consumer_owner": "railiance-platform",
|
||||
"rollback_requirement": "Delete only authenticated case-created delivery objects, preserve preexisting target and shared resources.",
|
||||
"source_order": 3,
|
||||
"source_step": {
|
||||
"attended": false,
|
||||
"auth": "railiance-platform ESO delivery through role external-secrets-keycape-{client_id}; no value leaves custody",
|
||||
"entry_point": "ExternalSecret sso/keycape-{client_id}-client (key client-secret) from bao:platform/workloads/keycape/{client_id}",
|
||||
"id": "deliver-secret",
|
||||
"owner": "railiance-platform",
|
||||
"ready_check": "the delivery for sso/keycape-{client_id}-client reports Ready=True (status only, no value read)",
|
||||
"value_handling": "none",
|
||||
"warden_executes": false,
|
||||
"when": "client_type == confidential"
|
||||
},
|
||||
"step": "deliver-secret"
|
||||
},
|
||||
{
|
||||
"candidate_descriptor": null,
|
||||
"candidate_descriptor_digest": null,
|
||||
"declared_owner": "net-kingdom",
|
||||
"dispatch_permitted": false,
|
||||
"existing_seam": "existing sso/keycape Deployment prerequisite checked by keycape-client.py; T12",
|
||||
"exists_in_default_1_1": true,
|
||||
"missing_exact_owner_facts": [
|
||||
"reviewed fixed exact Deployment UID/resourceVersion/env binding update adapter",
|
||||
"created-only prestate/readback and owner evidence/session capabilities",
|
||||
"separately reviewed quiet-window restart/readiness procedure; registry helper only reports restart_required"
|
||||
],
|
||||
"native_owner_assent": false,
|
||||
"resolved_first_consumer_owner": "net-kingdom",
|
||||
"rollback_requirement": "Restore only exact case-created env binding under current revision; a whole Deployment rollback or deleting preexisting env is not admitted.",
|
||||
"source_order": 4,
|
||||
"source_step": {
|
||||
"attended": true,
|
||||
"attended_justification": "A change to the live identity provider's Deployment. It runs in the same attended operator session as register-client, before it, because KeyCape resolves a confidential client's secret at start and fails closed if the binding is missing.",
|
||||
"auth": "operator kube credentials for namespace sso",
|
||||
"entry_point": "patch Deployment sso/keycape: env KEYCAPE_{client_id:env}_CLIENT_SECRET from sso/keycape-{client_id}-client",
|
||||
"id": "bind-env",
|
||||
"lane": "key-cape-oidc-login",
|
||||
"owner": "net-kingdom",
|
||||
"value_handling": "none",
|
||||
"warden_executes": false,
|
||||
"when": "client_type == confidential"
|
||||
},
|
||||
"step": "bind-env"
|
||||
},
|
||||
{
|
||||
"candidate_descriptor": {
|
||||
"actor": "human",
|
||||
"adapter": "net-kingdom/keycape-registration@v1",
|
||||
"adapter_source": "sha256:7db1caa4d1e73e8f65b6744af53bcdce628bcd86732f74bdc125f85c531a22d1",
|
||||
"allowed_created": [
|
||||
"keycape-client"
|
||||
],
|
||||
"effect": "change",
|
||||
"lane": "key-cape-oidc-login",
|
||||
"owner": "net-kingdom",
|
||||
"retry_safe": false,
|
||||
"revocation_scopes": [
|
||||
"parent-session"
|
||||
],
|
||||
"step": "register-client",
|
||||
"target_parameter": "client_id",
|
||||
"version": "warden.case.execution.v1"
|
||||
},
|
||||
"candidate_descriptor_digest": "sha256:1b86e9032845ec35a58d88a9f1108dbb7d8cee0c9c9176d4a694b893d9d7a3fa",
|
||||
"declared_owner": "net-kingdom",
|
||||
"dispatch_permitted": false,
|
||||
"existing_seam": "keycape-registration-adapter.py build/publish/authenticate/revoke_session injection seam",
|
||||
"exists_in_default_1_1": true,
|
||||
"missing_exact_owner_facts": [
|
||||
"actual admitted durable owner publisher/authenticator and exact parent-session revoker",
|
||||
"native executable storage/provenance and exact descriptor/type source admission",
|
||||
"T15 original-attempt recovery contract; fresh adapter intentionally cannot undo prior-process creation"
|
||||
],
|
||||
"native_owner_assent": false,
|
||||
"resolved_first_consumer_owner": "net-kingdom",
|
||||
"rollback_requirement": "Same-process authenticated successful creation only; exact original entry and unchanged postcreation UID/resourceVersion; post-restart stays refused.",
|
||||
"source_order": 5,
|
||||
"source_step": {
|
||||
"attended": true,
|
||||
"attended_justification": "The live KeyCape client registry is a Kubernetes Secret, and agents do not read or write Secrets. Until KeyCape loads clients from a non-secret registry with secrets referenced from custody, one attended operator session applies the rendered registration. ops-warden groups all attended steps of a run into that one session. KeyCape loads clients at startup and keeps login, authorization and handoff state in memory, so the restart drops in-flight logins and sessions for every client; runs go in a quiet window (key-cape type review R4). The rendered registry must pass KeyCape's own startup checks (keycape check-config, key-cape c528daa, which keycape-client.py runs before it patches) before the restart: a refused entry stops the single replica and every client loses sign-in (R1).",
|
||||
"auth": "operator write access to the live KeyCape client registry in namespace sso",
|
||||
"entry_point": "sso-mfa/k8s/keycape/keycape-client.py apply --client-file <client-from-case> --case-acceptance <record> --check-config <keycape binary> (net-kingdom.keycape-client-registration)",
|
||||
"id": "register-client",
|
||||
"lane": "key-cape-oidc-login",
|
||||
"owner": "net-kingdom",
|
||||
"value_handling": "none",
|
||||
"warden_executes": false
|
||||
},
|
||||
"step": "register-client"
|
||||
},
|
||||
{
|
||||
"candidate_descriptor": null,
|
||||
"candidate_descriptor_digest": null,
|
||||
"declared_owner": "{consumer_owner_repo}",
|
||||
"dispatch_permitted": false,
|
||||
"existing_seam": "acknowledged source1.2 dedicated SA/namespace SecretStore/ExternalSecret composition",
|
||||
"exists_in_default_1_1": false,
|
||||
"missing_exact_owner_facts": [
|
||||
"actual installed ESO TokenRequest/RBAC compatibility and consumer owner admission",
|
||||
"fixed owner adapter/descriptor for exact identities with created/preexisting readback",
|
||||
"receiver evidence for Ready status and case-issued token revocation/expiry"
|
||||
],
|
||||
"native_owner_assent": false,
|
||||
"resolved_first_consumer_owner": "railiance-apps for Forgejo",
|
||||
"rollback_requirement": "Revert consumer reference first; delete only authenticated created UID/ownerReference resources; SA/Store deletion alone does not immediately revoke OpenBao tokens.",
|
||||
"source_order": 6,
|
||||
"source_step": {
|
||||
"attended": false,
|
||||
"auth": "Consumer owner contained Kubernetes deployment authority; ESO authenticates to OpenBao role external-secrets-keycape-{client_id}-{consuming_service} with a TokenRequest for the dedicated namespaced serviceAccountRef; controller remains trusted",
|
||||
"entry_point": "Owner applies dedicated ServiceAccount {consumer_namespace}/{consuming_service}-keycape-{client_id}-eso (automount=false, no legacy tokens), namespace SecretStore openbao-keycape-{client_id}-consumer with serviceAccountRef and audiences [openbao], and ExternalSecret {consuming_service}-netkingdom-oidc-client with Owner target, Retain remote deletion and only CLIENT_SECRET from workloads/keycape/{client_id}. Admission validates actual installed ESO TokenRequest support and common controller RBAC before any owner-approved apply.",
|
||||
"id": "deliver-consumer-secret",
|
||||
"owner": "{consumer_owner_repo}",
|
||||
"ready_check": "Namespace SecretStore and ExternalSecret both report Ready=True; dedicated SA has no legacy token refs; status and fixed metadata only, never Secret values.",
|
||||
"value_handling": "none",
|
||||
"warden_executes": false,
|
||||
"when": "client_type == confidential"
|
||||
},
|
||||
"step": "deliver-consumer-secret"
|
||||
},
|
||||
{
|
||||
"candidate_descriptor": null,
|
||||
"candidate_descriptor_digest": null,
|
||||
"declared_owner": "{consumer_owner_repo}",
|
||||
"dispatch_permitted": false,
|
||||
"existing_seam": "consumer owner OIDC configuration and groups enforcement path",
|
||||
"exists_in_default_1_1": true,
|
||||
"missing_exact_owner_facts": [
|
||||
"owner exact deployment/source adapter/descriptor and accepted issuer/client/delivery binding",
|
||||
"actual human login/group-denial and public authorization/MFA pin verifications",
|
||||
"rollback and native receipt/custody acceptance"
|
||||
],
|
||||
"native_owner_assent": false,
|
||||
"resolved_first_consumer_owner": "railiance-apps for Forgejo",
|
||||
"rollback_requirement": "Remove only this case-created OIDC source; preserve shared/preexisting auth sources and consumer state.",
|
||||
"source_order": 7,
|
||||
"source_step": {
|
||||
"attended": false,
|
||||
"auth": "the consumer owner's own deployment path",
|
||||
"entry_point": "configure {consuming_service} with issuer {issuer}, client {client_id} and custody bao:platform/workloads/keycape/{client_id}, and make it require one of {access_groups} in the groups claim before sign-in completes",
|
||||
"id": "hand-over",
|
||||
"owner": "{consumer_owner_repo}",
|
||||
"value_handling": "none",
|
||||
"warden_executes": false
|
||||
},
|
||||
"step": "hand-over"
|
||||
}
|
||||
],
|
||||
"execution_permitted": false,
|
||||
"missing_descriptor_steps": [
|
||||
"ensure-groups",
|
||||
"mint-secret",
|
||||
"deliver-secret",
|
||||
"bind-env",
|
||||
"deliver-consumer-secret",
|
||||
"hand-over"
|
||||
],
|
||||
"native_complete": false,
|
||||
"proposed_version_selection": {
|
||||
"canonical_case": "Keep1.1 accepted history unchanged and1.2 example proposed without acceptance fields.",
|
||||
"classification": "Exact closed execution references and any changed trust/materialization/authentication must be classified by the existing owner; changed trust/authentication requires informed-decision acknowledgment, never self-classified as harmless validation.",
|
||||
"default_loader": "Keep canonical1.1 unchanged; select1.2 only through existing explicit version-root option for source review.",
|
||||
"descriptor_revision": "Do not edit acknowledged source1.1/1.2 in place or inherit old acknowledgment for new descriptor bytes. Allocate the exact successor revision/version through NetKingdom canon section6 after the complete owner-reviewed set exists.",
|
||||
"first_consumer": "Forgejo",
|
||||
"review_base": "explicit source-only oidc-browser-relying-party@1.2",
|
||||
"why": "Its dedicated consumer SA/ESO authentication boundary expresses the reviewed six-object structural design;1.1 does not."
|
||||
},
|
||||
"purpose": "Review inventory only; this is not a Warden descriptor bundle or accepted SecurityCaseType.",
|
||||
"register_descriptor": {
|
||||
"decode": "Actual Warden Descriptor.decode round-trip passed; no Executor admission or tooling invocation performed.",
|
||||
"owner_source_composition": "sha256:7db1caa4d1e73e8f65b6744af53bcdce628bcd86732f74bdc125f85c531a22d1",
|
||||
"path": "register-client.proposed-descriptor.json",
|
||||
"sha256": "sha256:1b86e9032845ec35a58d88a9f1108dbb7d8cee0c9c9176d4a694b893d9d7a3fa"
|
||||
},
|
||||
"rollback_inventory": [
|
||||
{
|
||||
"action": "remove the OIDC source for {client_id} from {consuming_service} (owner {consumer_owner_repo})",
|
||||
"reverses": "hand-over"
|
||||
},
|
||||
{
|
||||
"action": "After reverting consumer secret reference, delete only authenticated created ExternalSecret/owned target by UID and ownerReference, then SecretStore and dedicated SA; preserve preexisting-matched resources and never delete a shared target. Retain audit and ownership receipts; removing SecretStore/SA alone is not immediate OpenBao token revocation.",
|
||||
"reverses": "deliver-consumer-secret",
|
||||
"when": "client_type == confidential"
|
||||
},
|
||||
{
|
||||
"action": "keycape-client.py apply --operation remove for {client_id}",
|
||||
"reverses": "register-client"
|
||||
},
|
||||
{
|
||||
"action": "remove env KEYCAPE_{client_id:env}_CLIENT_SECRET from Deployment sso/keycape, after register-client is reversed",
|
||||
"reverses": "bind-env",
|
||||
"when": "client_type == confidential"
|
||||
},
|
||||
{
|
||||
"action": "delete ExternalSecret sso/keycape-{client_id}-client and its target",
|
||||
"reverses": "deliver-secret",
|
||||
"when": "client_type == confidential"
|
||||
},
|
||||
{
|
||||
"action": "covered by client-secret-path: one metadata delete, after deliver-secret is reversed",
|
||||
"reverses": "mint-secret",
|
||||
"when": "client_type == confidential"
|
||||
},
|
||||
{
|
||||
"action": "identity-provisioner revoke_service_groups inside the provisioner pod (attended, as ensure-groups) with the case's memberships; delete_if_empty only if no other case uses {access_groups}",
|
||||
"reverses": "ensure-groups"
|
||||
},
|
||||
{
|
||||
"action": "delete metadata and all versions at platform/workloads/keycape/{client_id}, after the ExternalSecret is gone (this also reverses mint-secret)",
|
||||
"reverses": "client-secret-path",
|
||||
"when": "client_type == confidential"
|
||||
},
|
||||
{
|
||||
"action": "delete Kubernetes-auth role external-secrets-keycape-{client_id}",
|
||||
"reverses": "eso-role",
|
||||
"when": "client_type == confidential"
|
||||
},
|
||||
{
|
||||
"action": "delete policy workload-kv-read-keycape-{client_id}-eso, after eso-role",
|
||||
"reverses": "keycape-reader-policy",
|
||||
"when": "client_type == confidential"
|
||||
},
|
||||
{
|
||||
"action": "Delete only this case-created role external-secrets-keycape-{client_id}-{consuming_service}, before deleting consumer-reader-policy; revoke case-issued OpenBao tokens or prove expiration before declaring deactivation.",
|
||||
"reverses": "consumer-eso-role",
|
||||
"when": "client_type == confidential"
|
||||
},
|
||||
{
|
||||
"action": "delete policy workload-kv-read-keycape-{client_id}-{consuming_service}",
|
||||
"reverses": "consumer-reader-policy",
|
||||
"when": "client_type == confidential"
|
||||
},
|
||||
{
|
||||
"action": "remove catalog entry {consuming_service}-keycape-client",
|
||||
"reverses": "catalog-entry"
|
||||
}
|
||||
],
|
||||
"run_order_and_completion": [
|
||||
"Accepted exact case source and independently verified six-object native structural materialization before follow-through; a file status or rendered bundle is insufficient.",
|
||||
"Preserve existing source follow-through order. Delivery Ready and exact Deployment env prerequisite before registry apply. Separate quiet-window restart/readiness after checked registration before real sign-in; registry changed receipt alone is not service activation.",
|
||||
"Warden rechecks actual caller principal/actor/lane before each admitted dispatch. A session revoked at a step cannot be reused for later steps; owner must define fresh-session or admitted run-envelope grouping without weakening parent-session revocation.",
|
||||
"Mint must carry separately authenticated broker-grant and parent-session revocation; every completed step requires independently authenticated owner and session evidence.",
|
||||
"Verification is the complete declared positive/negative inventory plus actual human login/group denial. Reverse only independently confirmed creations, retaining uncertain intents and preserving shared/preexisting objects."
|
||||
],
|
||||
"schema": "custodian.registration-descriptor-review.v1",
|
||||
"source_versions": {
|
||||
"1.1": {
|
||||
"machine_descriptor_map_present": false,
|
||||
"status": "acknowledged",
|
||||
"step_count": 6
|
||||
},
|
||||
"1.2": {
|
||||
"machine_descriptor_map_present": false,
|
||||
"status": "acknowledged",
|
||||
"step_count": 7
|
||||
}
|
||||
},
|
||||
"verification_inventory": [
|
||||
{
|
||||
"check": "GET {issuer}/authorize with client {client_id} and each of {redirect_uris} returns the login page",
|
||||
"expect": "present",
|
||||
"id": "authorize-accepts-redirects",
|
||||
"reads_secret_value": false
|
||||
},
|
||||
{
|
||||
"check": "GET {issuer}/authorize with client {client_id} and an unregistered redirect returns an OAuth error",
|
||||
"expect": "deny",
|
||||
"id": "authorize-refuses-other-redirect",
|
||||
"reads_secret_value": false
|
||||
},
|
||||
{
|
||||
"check": "a default-only OpenBao identity has no read capability on bao:platform/workloads/keycape/{client_id}",
|
||||
"expect": "deny",
|
||||
"id": "custody-denied-to-default",
|
||||
"reads_secret_value": false,
|
||||
"when": "client_type == confidential"
|
||||
},
|
||||
{
|
||||
"check": "policy workload-kv-read-keycape-{client_id}-{consuming_service} grants read on bao:platform/workloads/keycape/{client_id} (capabilities check only)",
|
||||
"expect": "allow",
|
||||
"id": "custody-allowed-to-consumer",
|
||||
"reads_secret_value": false,
|
||||
"when": "client_type == confidential"
|
||||
},
|
||||
{
|
||||
"check": "LLDAP groups {access_groups} exist, with exactly the memberships of the accepted case added",
|
||||
"expect": "present",
|
||||
"id": "groups-present",
|
||||
"reads_secret_value": false
|
||||
},
|
||||
{
|
||||
"check": "{consuming_service}'s OIDC source for {client_id} (owner {consumer_owner_repo}) requires one of {access_groups} in the groups claim (configuration read, no secret value)",
|
||||
"expect": "present",
|
||||
"id": "consumer-enforces-groups",
|
||||
"reads_secret_value": false
|
||||
},
|
||||
{
|
||||
"check": "the delivery for sso/keycape-{client_id}-client reports Ready=True (status only)",
|
||||
"expect": "present",
|
||||
"id": "secret-delivered",
|
||||
"reads_secret_value": false,
|
||||
"when": "client_type == confidential"
|
||||
},
|
||||
{
|
||||
"check": "keycape-client.py inspect for {client_id} shows the MFA pin on the registered client (non-secret client view)",
|
||||
"expect": "present",
|
||||
"id": "mfa-pinned",
|
||||
"reads_secret_value": false,
|
||||
"when": "mfa_required == true"
|
||||
},
|
||||
{
|
||||
"check": "{consumer_namespace} SecretStore openbao-keycape-{client_id}-consumer and ExternalSecret {consuming_service}-netkingdom-oidc-client Ready=True, exact dedicated SA/audience role binding, fixed CLIENT_SECRET mapping; no Secret value read",
|
||||
"expect": "present",
|
||||
"id": "consumer-secret-delivered",
|
||||
"reads_secret_value": false,
|
||||
"when": "client_type == confidential"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"files": [
|
||||
{
|
||||
"path": "assemble_review.py",
|
||||
"sha256": "554cc213824098e3b3599d9e801330a28aea72f19336b7492adacebbf84d62f4",
|
||||
"bytes": 25834
|
||||
},
|
||||
{
|
||||
"path": "descriptor-composition.json",
|
||||
"sha256": "e097abe5f7b149e5688850cfb0ef7793a1b3206388b52f069b51137f6ca92170",
|
||||
"bytes": 22885
|
||||
},
|
||||
{
|
||||
"path": "original-attempt-review.json",
|
||||
"sha256": "d0df5c45f53f7d61ac54589e55b09f1c9cff098ade63e5853e434ced8f83fe3c",
|
||||
"bytes": 8753
|
||||
},
|
||||
{
|
||||
"path": "register-client.proposed-descriptor.json",
|
||||
"sha256": "1b86e9032845ec35a58d88a9f1108dbb7d8cee0c9c9176d4a694b893d9d7a3fa",
|
||||
"bytes": 413
|
||||
},
|
||||
{
|
||||
"path": "source-manifest.json",
|
||||
"sha256": "33c475045cfe958bab5b7545783dea497427373448c83c1859888550e965c104",
|
||||
"bytes": 10433
|
||||
},
|
||||
{
|
||||
"path": "source-verification.json",
|
||||
"sha256": "2ed179ecdcda85a29b0e86e7e19274fdce408d154e4e79f61bbccc80304c8dfd",
|
||||
"bytes": 4054
|
||||
},
|
||||
{
|
||||
"path": "summary.json",
|
||||
"sha256": "3ede75b2d55190fb41236a92c4d2ed157be04c819ab5226e5d9c404d87d51bdd",
|
||||
"bytes": 1878
|
||||
},
|
||||
{
|
||||
"path": "work-record-proposal.json",
|
||||
"sha256": "0aec5c8a8473232d1800c6c3b70661dd1412271e57effe0d7f19242201897134",
|
||||
"bytes": 3009
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
{
|
||||
"actual_source_findings": [
|
||||
{
|
||||
"fact": "records and creation live only in the build closure; original payload publication is injected. Rebuilding the Adapter loses original creation, even if caller retains OwnerResult. Adapter.reconcile is absent.",
|
||||
"source": "/home/worsch/net-kingdom/sso-mfa/k8s/keycape/keycape-registration-adapter.py",
|
||||
"symbol": "build/execute/verify"
|
||||
},
|
||||
{
|
||||
"fact": "Durable rows keep attempt_id/operation and exact pins/created history but only digest(evidence identifier), digest(session reference) and digest(grant reference), not original owner payload or recoverable evidence identifier. Journal.load returns StepState and drops persisted attempt context.",
|
||||
"source": "/home/worsch/ops-warden/src/warden/case_run.py",
|
||||
"symbol": "Journal.save/load"
|
||||
},
|
||||
{
|
||||
"fact": "Crash recovery appends recovered state without invocation/evidence; historical intent rows remain but latest may have no original attempt identity. reconcile creates a fresh attempt identity and calls Adapter.reconcile(new_invocation), supplying no original attempt reference.",
|
||||
"source": "/home/worsch/ops-warden/src/warden/case_run.py",
|
||||
"symbol": "Executor.run/reconcile/_attempt"
|
||||
},
|
||||
{
|
||||
"fact": "Read-only compatibility projection takes latest rows and explicitly returns native_authenticated false. It is not a holder authenticator or recovery authority.",
|
||||
"source": "/home/worsch/net-kingdom/tools/security-case-types/security_case_evidence.py",
|
||||
"symbol": "read_journal/check_steps"
|
||||
},
|
||||
{
|
||||
"fact": "Existing authenticated POST/v1/events and privileged tenant-filtered GET/v1/events/{event_id} can supply custody/readback, but this source review found no registration publisher/class admission or owner authenticator wiring to that surface. Generic custody readiness is not creation attribution.",
|
||||
"source": "/home/worsch/audit-core/audit_core/ingestion.py",
|
||||
"symbol": "_read/normalize"
|
||||
},
|
||||
{
|
||||
"fact": "Sender credential restricts allowed source/tenant; may_write does not imply may_read. Evidence defaults attributive; rollback-load-bearing source requires explicit owner declaration and emission atomicity/detection contract.",
|
||||
"source": "/home/worsch/audit-core/audit_core/senders.py",
|
||||
"symbol": "SenderIdentity"
|
||||
}
|
||||
],
|
||||
"disposition": "Existing seams inspected; no admitted original-attempt holder/readback matches. Source contract review only; recovery remains refused.",
|
||||
"implementation_disposition": "No source guard/adapter change is justified until the listed existing owner contracts identify authority. Existing fail-closed behavior is retained.",
|
||||
"minimal_exact_owner_facts_before_implementation": [
|
||||
{
|
||||
"fact": "Approve exact original-intent lookup in existing Journal history and how original Invocation/evidence identifier is handed to a fixed reconciler alongside the fresh reconcile Invocation. Current method supplies only fresh attempt. Preserve historical rows and current no-replay behavior.",
|
||||
"owner": "ops-warden; existing WARDEN-WP-0044-T03"
|
||||
},
|
||||
{
|
||||
"fact": "Name the actual existing publish/authenticate holder and its bounded authenticated original-attempt readback; supply public interface/source/tenant/principal provenance references and loss/unavailable/ambiguous dispositions. No secret value or new backend is requested.",
|
||||
"owner": "NetKingdom registration evidence owner with Warden admission"
|
||||
},
|
||||
{
|
||||
"fact": "Admit the registration source/event class and load-bearing completeness/intent-to-result custody contract, concrete event-id/original-attempt mapping, normalized-data equality/redaction policy and separate tenant-scoped reader. Generic POST acceptance or counts do not authenticate native creation.",
|
||||
"owner": "audit-core only if actual selected holder"
|
||||
},
|
||||
{
|
||||
"fact": "Name actual original and current session evidence purposes and verifier/capability source; original revocation does not authorize a new session, and each new reconcile/rollback attempt must revoke its own parent.",
|
||||
"owner": "Warden caller-session/revocation owner"
|
||||
}
|
||||
],
|
||||
"native_acceptance": false,
|
||||
"proposed_recovery_sequence_through_existing_seams": [
|
||||
"Re-admit exact case/type/descriptor/catalog/acceptance and new current caller principal/actor/lane through normal Executor.admit. No old session is resurrected.",
|
||||
"Under existing Journal process lock, owner retrieves original intended run attempt from immutable history: exact step/target/pins and original attempt_id/operation. Fresh reconcile attempt_id is distinct and must never substitute for this original identity.",
|
||||
"The selected admitted owner lookup authenticates exact original netkingdom.keycape-registration.attempt.v1 bytes by original attempt_id and admitted source scope. A case-supplied path, JSON payload or evidence identifier is not a capability. Journal fingerprints only detect correspondence after independent authentication.",
|
||||
"Validate original payload against original full Invocation, current admission pins, reviewed adapter/helper/checker source, created-only SUCCESS (not NO_CHANGE), exact owner/target, before/after UID/resourceVersion and original session-revocation evidence. Tenant/realm provenance must come from the actual admitted owner/session context; Invocation has no independent tenant field, so do not add a caller label as a substitute.",
|
||||
"Independently attest original result/session evidence; inspect current native registry through the maintained contained owner helper and match original exact created entry plus unchanged postcreation UID/resourceVersion. Hash equality alone and same client_id are insufficient.",
|
||||
"Bind lookup result and original provenance to the NEW reconcile attempt and newly revoked parent-session evidence. Preserve original record and current uncertainty. Only after owner-reviewed provenance hydration and normal kernel verification could subsequent independently authorized rollback consider that exact creation.",
|
||||
"If original receipt was never durably published, is missing/ambiguous/stale, shows NO_CHANGE, mismatches tenant/case/source/principal, or native revision drifted, retain UNCERTAIN and refuse add replay and undo. Do not infer FAILED_BEFORE from missing evidence. Lost-write/readback cases require attended owner reconciliation; no automatic creation attribution is introduced."
|
||||
],
|
||||
"retry_authorized": false,
|
||||
"reviewed_existing_holder_candidates": [
|
||||
{
|
||||
"holder": "Warden private SQLite Journal",
|
||||
"not_sufficient": "Has only hashed evidence references and reducer state; it cannot authenticate original creation or supply missing owner bytes.",
|
||||
"use": "Original intent/sequence lookup from existing immutable history rows after source/owner integrity checks."
|
||||
},
|
||||
{
|
||||
"holder": "Actual registration owner publish/authenticate callbacks",
|
||||
"not_sufficient": "No native implementation, named holder or authenticated readback capability is present. The in-test dict authenticator is synthetic only.",
|
||||
"use": "The existing fixed injected owner capability is the intended successful-attempt custody seam."
|
||||
},
|
||||
{
|
||||
"holder": "Audit Core existing event custody/readback",
|
||||
"not_sufficient": "Not selected or admitted for registration; no invented registration sender, token, event authority, runtime verifier or new backend is created.",
|
||||
"use": "A concrete existing provider to consider, with source/tenant-scoped sender and separate reader through existing owner admission process."
|
||||
},
|
||||
{
|
||||
"holder": "State Hub progress/request, JSON receipt, current matching registry",
|
||||
"not_sufficient": "No creation custody/provenance guarantee. A current matching entry cannot distinguish an original successful write from preexisting or same-byte foreign creation.",
|
||||
"use": "Diagnostic/source references only."
|
||||
}
|
||||
],
|
||||
"rollback_authorized": false,
|
||||
"schema": "custodian.registration-original-attempt-review.v1",
|
||||
"targeted_existing_fixture_coverage": {
|
||||
"existing_cases": [
|
||||
"test_process_loss_does_not_reconstruct_created_authority",
|
||||
"test_missing_or_tampered_evidence_never_verifies_or_authorizes_undo",
|
||||
"test_kernel_lost_readback_retains_uncertain_and_refuses_replay_and_undo"
|
||||
],
|
||||
"limits": "Current synthetic Kubernetes/dict trust tests prove refusal; none supply original native custody. No duplicate fixture framework or fake native tests added.",
|
||||
"not_rerun": true,
|
||||
"source": "/home/worsch/net-kingdom/sso-mfa/k8s/keycape/test_keycape_registration_adapter.py"
|
||||
},
|
||||
"task": "NK-WP-0048-T15",
|
||||
"task_done": false
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"actor":"human","adapter":"net-kingdom/keycape-registration@v1","adapter_source":"sha256:7db1caa4d1e73e8f65b6744af53bcdce628bcd86732f74bdc125f85c531a22d1","allowed_created":["keycape-client"],"effect":"change","lane":"key-cape-oidc-login","owner":"net-kingdom","retry_safe":false,"revocation_scopes":["parent-session"],"step":"register-client","target_parameter":"client_id","version":"warden.case.execution.v1"}
|
||||
|
|
@ -0,0 +1,323 @@
|
|||
{
|
||||
"original_audit_immutable": {
|
||||
"expected_sha256": "sha256:ab803e795af61fd027f5930d127592316133de38b68a8fe61b89a1f9803a9ff2",
|
||||
"path": "/home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-17/native-gates-r1/native-gate-audit.json"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"bytes": 16474,
|
||||
"path": "/home/worsch/net-kingdom/security-case-types/oidc-browser-relying-party/type.yaml",
|
||||
"sha256": "sha256:f705c64e4875e9b8e18a912fb51c135e77898926d6a451f5cb74ab3c0cbe4d1c"
|
||||
},
|
||||
{
|
||||
"bytes": 1717,
|
||||
"path": "/home/worsch/net-kingdom/security-cases/forgejo-netkingdom-oidc.yaml",
|
||||
"sha256": "sha256:bcc2c6d5bae0d28242b3cdb71e74d8ca297c2afe04766b55d53597f86893351d"
|
||||
},
|
||||
{
|
||||
"bytes": 19052,
|
||||
"path": "/home/worsch/net-kingdom/security-case-type-revisions/1.2/oidc-browser-relying-party/type.yaml",
|
||||
"sha256": "sha256:9e60ff569fb0d860a2bbde7bbb0991a54d4b0688f62b56df0fa5d161fd624578"
|
||||
},
|
||||
{
|
||||
"bytes": 722,
|
||||
"path": "/home/worsch/net-kingdom/security-case-type-revisions/1.2/oidc-browser-relying-party/examples/forgejo.yaml",
|
||||
"sha256": "sha256:1c868c1da7d9077fae97bc6bc029706ec3dc418cfeaae30dc0f92b5b4ba6f2ab"
|
||||
},
|
||||
{
|
||||
"bytes": 4214,
|
||||
"path": "/home/worsch/net-kingdom/security-case-type-revisions/1.2/oidc-browser-relying-party/decision/acknowledgment.json",
|
||||
"sha256": "sha256:2dcc220febf125a17b3769f7014f18b63979d7121e0f7056a2b0d8b1ae6031b0"
|
||||
},
|
||||
{
|
||||
"bytes": 60503,
|
||||
"path": "/home/worsch/net-kingdom/workplans/NK-WP-0048-security-case-types.md",
|
||||
"sha256": "sha256:b737bfae4802c122b21619695a169d7d082672af96314b1709860dd5aff2a60f"
|
||||
},
|
||||
{
|
||||
"bytes": 11186,
|
||||
"path": "/home/worsch/net-kingdom/AGENTS.md",
|
||||
"sha256": "sha256:95158b1d5c15e6cf8be980f5c0e3b48aeef252654846273887f40516b3fa6a78"
|
||||
},
|
||||
{
|
||||
"bytes": 13132,
|
||||
"path": "/home/worsch/ops-warden/AGENTS.md",
|
||||
"sha256": "sha256:aa03031516b886b254d8c4b1fafa160c063c74aa0115ba51af3dd7326dccfad6"
|
||||
},
|
||||
{
|
||||
"bytes": 12019,
|
||||
"path": "/home/worsch/net-kingdom/SECURITY-COMPANION.md",
|
||||
"sha256": "sha256:06374445ca888549f1bf79527d1345d94918d7a7ec363160d8427d0e7a31d643"
|
||||
},
|
||||
{
|
||||
"bytes": 23003,
|
||||
"path": "/home/worsch/ops-warden/INTENT.md",
|
||||
"sha256": "sha256:3e9382fefa52ee0970dfac133cc799656e5034760b26dccc1bf9bab65fc538d9"
|
||||
},
|
||||
{
|
||||
"bytes": 10233,
|
||||
"path": "/home/worsch/net-kingdom/canon/standards/security-case-types_v0.1.md",
|
||||
"sha256": "sha256:a4fda906d5138d2594a1f8d047c7c28e1cdf96b1eae051f543b9a5e5852bcb5e"
|
||||
},
|
||||
{
|
||||
"bytes": 8821,
|
||||
"path": "/home/worsch/net-kingdom/docs/security-case-execution-owner-review.md",
|
||||
"sha256": "sha256:0f1637bfddbbdf50d336974791b7fbf4646efe7e32ca04beb3bf52effd0a28e6"
|
||||
},
|
||||
{
|
||||
"bytes": 5229,
|
||||
"path": "/home/worsch/net-kingdom/sso-mfa/k8s/keycape/registration-adapter.md",
|
||||
"sha256": "sha256:2fadcbd28e34566173428bcb92e42ac464ef73c03909072d0fc2ee988b175e29"
|
||||
},
|
||||
{
|
||||
"bytes": 8813,
|
||||
"path": "/home/worsch/ops-warden/docs/security-case-execution-kernel-v1.md",
|
||||
"sha256": "sha256:0eb563dbaea739fba928d04708c2c2bdac592783bbe68e1271041b0d1b1994cb"
|
||||
},
|
||||
{
|
||||
"bytes": 13901,
|
||||
"path": "/home/worsch/ops-warden/workplans/WARDEN-WP-0044-security-case-follow-through.md",
|
||||
"sha256": "sha256:1df57687200f6a60a2a6f26a4066ce1e93ae663fc4e43db3884d04dc1d6e874e"
|
||||
},
|
||||
{
|
||||
"bytes": 13867,
|
||||
"path": "/home/worsch/audit-core/docs/audit-backend-contract.md",
|
||||
"sha256": "sha256:a80ebeac99bd88b1ec55a2c0c3a25220749908e237d7d3c048f7e867bb0a9b1a"
|
||||
},
|
||||
{
|
||||
"bytes": 1917,
|
||||
"path": "/home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-16/browser-checker-environment-r2/build-receipt.json",
|
||||
"sha256": "sha256:1a3bb61a958afdbe46664384963a53e275a5a6b53741bda9244e28f58b4453ff"
|
||||
},
|
||||
{
|
||||
"bytes": 1073,
|
||||
"path": "/home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-16/browser-checker-artifact-next/coordinator-build-review.json",
|
||||
"sha256": "sha256:621702e9149d59fa187af2f6e5d140dab3b261bbe25a02bbc1f0ac5f0731b233"
|
||||
},
|
||||
{
|
||||
"bytes": 11813,
|
||||
"path": "/home/worsch/net-kingdom/sso-mfa/k8s/keycape/keycape-registration-adapter.py",
|
||||
"sha256": "sha256:d7e3643cc794223dfaa310775eacbbeb4d353f9382e4481322d704d6b7ab1c51",
|
||||
"symbols": {}
|
||||
},
|
||||
{
|
||||
"bytes": 27272,
|
||||
"path": "/home/worsch/ops-warden/src/warden/case_run.py",
|
||||
"sha256": "sha256:afb5ce9c59b9748f85c9f1d4af04b255087632c58de8dcd8c9426fc1ed4db068",
|
||||
"symbols": {
|
||||
"Executor": {
|
||||
"end_line": 710,
|
||||
"line": 320
|
||||
},
|
||||
"Journal": {
|
||||
"end_line": 317,
|
||||
"line": 183
|
||||
},
|
||||
"_attempt": {
|
||||
"end_line": 575,
|
||||
"line": 566
|
||||
},
|
||||
"_result": {
|
||||
"end_line": 532,
|
||||
"line": 490
|
||||
},
|
||||
"admit": {
|
||||
"end_line": 488,
|
||||
"line": 344
|
||||
},
|
||||
"load": {
|
||||
"end_line": 274,
|
||||
"line": 221
|
||||
},
|
||||
"reconcile": {
|
||||
"end_line": 710,
|
||||
"line": 646
|
||||
},
|
||||
"rollback": {
|
||||
"end_line": 644,
|
||||
"line": 613
|
||||
},
|
||||
"run": {
|
||||
"end_line": 611,
|
||||
"line": 577
|
||||
},
|
||||
"save": {
|
||||
"end_line": 317,
|
||||
"line": 276
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"bytes": 5456,
|
||||
"path": "/home/worsch/ops-warden/src/warden/case_receipt_state.py",
|
||||
"sha256": "sha256:a2cda7f187e77bd76d4d209505638de44a587fae0bc033ec75c23ee9ea9f73bc",
|
||||
"symbols": {
|
||||
"begin_rollback": {
|
||||
"end_line": 138,
|
||||
"line": 134
|
||||
},
|
||||
"recover": {
|
||||
"end_line": 120,
|
||||
"line": 114
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"bytes": 4438,
|
||||
"path": "/home/worsch/ops-warden/src/warden/case_inputs.py",
|
||||
"sha256": "sha256:1334b0cd9897e763cfea2d306e997c659f3f284ecc3f9612140c2104835da7c7",
|
||||
"symbols": {
|
||||
"BrowserInputs": {
|
||||
"end_line": 98,
|
||||
"line": 42
|
||||
},
|
||||
"target": {
|
||||
"end_line": 98,
|
||||
"line": 48
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"bytes": 11783,
|
||||
"path": "/home/worsch/net-kingdom/tools/security-case-types/security_case_evidence.py",
|
||||
"sha256": "sha256:da8efa59c52ad73283397ebe639ae259d0cb9c6348b5cb829135c24230dcdc75",
|
||||
"symbols": {
|
||||
"audit": {
|
||||
"end_line": 205,
|
||||
"line": 193
|
||||
},
|
||||
"check_steps": {
|
||||
"end_line": 190,
|
||||
"line": 131
|
||||
},
|
||||
"read_journal": {
|
||||
"end_line": 128,
|
||||
"line": 103
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"bytes": 36729,
|
||||
"path": "/home/worsch/net-kingdom/tools/security-case-types/security_case_validator.py",
|
||||
"sha256": "sha256:1bcc62e9bc374c711363295549f3cd5bb0b32952671ed4b08fddc7f74742959b",
|
||||
"symbols": {
|
||||
"load_type": {
|
||||
"end_line": 452,
|
||||
"line": 419
|
||||
},
|
||||
"validate_execution_descriptors": {
|
||||
"end_line": 215,
|
||||
"line": 194
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"bytes": 17073,
|
||||
"path": "/home/worsch/net-kingdom/sso-mfa/k8s/keycape/test_keycape_registration_adapter.py",
|
||||
"sha256": "sha256:cc5956d811db031e437ebca60bf70eb41177c87db75cc9478fe84075ad224464",
|
||||
"symbols": {
|
||||
"test_kernel_lost_readback_retains_uncertain_and_refuses_replay_and_undo": {
|
||||
"end_line": 305,
|
||||
"line": 289
|
||||
},
|
||||
"test_process_loss_does_not_reconstruct_created_authority": {
|
||||
"end_line": 215,
|
||||
"line": 209
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"bytes": 38172,
|
||||
"path": "/home/worsch/audit-core/audit_core/ingestion.py",
|
||||
"sha256": "sha256:f5a225a204cf77d0ac5aa49298f2e4acd6f559e47fa4f19407672486537e97c6",
|
||||
"symbols": {
|
||||
"_read": {
|
||||
"end_line": 333,
|
||||
"line": 247
|
||||
},
|
||||
"normalize": {
|
||||
"end_line": 679,
|
||||
"line": 625
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"bytes": 20214,
|
||||
"path": "/home/worsch/audit-core/audit_core/senders.py",
|
||||
"sha256": "sha256:bc091ce63dc2cd0fcdc9f26423b258cb94a6db863daced6706c11dba3bbf67e1",
|
||||
"symbols": {
|
||||
"SenderIdentity": {
|
||||
"end_line": 185,
|
||||
"line": 44
|
||||
},
|
||||
"evidence_declaration": {
|
||||
"end_line": 156,
|
||||
"line": 139
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"bytes": 7438,
|
||||
"path": "/home/worsch/audit-core/audit_core/interface.py",
|
||||
"sha256": "sha256:4ecc5f6bdfe04181cce02ec5547fbfded0101868085909f315ea7d4c9eb9b573",
|
||||
"symbols": {
|
||||
"AcceptResult": {
|
||||
"end_line": 146,
|
||||
"line": 142
|
||||
},
|
||||
"AuditEvent": {
|
||||
"end_line": 117,
|
||||
"line": 82
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"bytes": 9872,
|
||||
"path": "/home/worsch/railiance-platform/scripts/keycape_client_secret_generate.py",
|
||||
"sha256": "sha256:9576cd211cfc06526ec4cc9bd0a5b06f0f59287a68931bb2d6e3592a951ddc7d",
|
||||
"symbols": {
|
||||
"check_case": {
|
||||
"end_line": 123,
|
||||
"line": 98
|
||||
},
|
||||
"record_state_hub": {
|
||||
"end_line": 191,
|
||||
"line": 181
|
||||
},
|
||||
"run": {
|
||||
"end_line": 178,
|
||||
"line": 126
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"bytes": 15565,
|
||||
"path": "/home/worsch/net-kingdom/sso-mfa/k8s/keycape/keycape-client.py",
|
||||
"sha256": "sha256:4b63161cf3365d34dd684a3116e2c935baaf7f6aa4b30983f6883546db3d6591",
|
||||
"symbols": {}
|
||||
},
|
||||
{
|
||||
"bytes": 7017,
|
||||
"path": "/home/worsch/net-kingdom/sso-mfa/k8s/keycape/portal-client-rollout.py",
|
||||
"sha256": "sha256:158e1d36eb881cdd0a2eda91b472adea5e8fde5061e00d26dda368580aeb871f",
|
||||
"symbols": {}
|
||||
},
|
||||
{
|
||||
"bytes": 13089,
|
||||
"path": "/home/worsch/net-kingdom/sso-mfa/k8s/keycape/openbao-client-config.py",
|
||||
"sha256": "sha256:1b908b4c36134212d78f9fbe7a2a201eb3ced06d31bb1dcea4a59d80689d84b1",
|
||||
"symbols": {}
|
||||
},
|
||||
{
|
||||
"bytes": 1691,
|
||||
"path": "/home/worsch/net-kingdom/sso-mfa/k8s/keycape/register-user-engine-portal.py",
|
||||
"sha256": "sha256:67173edc44f5457e7b6a3e0fb2321b398159cfce5dea8ead01eabf835fb38d76",
|
||||
"symbols": {}
|
||||
},
|
||||
{
|
||||
"bytes": 13633409,
|
||||
"path": "/tmp/nk-checker-environment-r2-rebuild/keycape",
|
||||
"sha256": "sha256:be37738fe1c08259fb4f9ca0daf0f9301bfffc237e5bb38435525dfbf11ccff5"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
{
|
||||
"canonical_hashes": {
|
||||
"/home/worsch/net-kingdom/security-case-type-revisions/1.2/oidc-browser-relying-party/decision/acknowledgment.json": "sha256:2dcc220febf125a17b3769f7014f18b63979d7121e0f7056a2b0d8b1ae6031b0",
|
||||
"/home/worsch/net-kingdom/security-case-type-revisions/1.2/oidc-browser-relying-party/examples/forgejo.yaml": "sha256:1c868c1da7d9077fae97bc6bc029706ec3dc418cfeaae30dc0f92b5b4ba6f2ab",
|
||||
"/home/worsch/net-kingdom/security-case-type-revisions/1.2/oidc-browser-relying-party/type.yaml": "sha256:9e60ff569fb0d860a2bbde7bbb0991a54d4b0688f62b56df0fa5d161fd624578",
|
||||
"/home/worsch/net-kingdom/security-case-types/oidc-browser-relying-party/type.yaml": "sha256:f705c64e4875e9b8e18a912fb51c135e77898926d6a451f5cb74ab3c0cbe4d1c",
|
||||
"/home/worsch/net-kingdom/security-cases/forgejo-netkingdom-oidc.yaml": "sha256:bcc2c6d5bae0d28242b3cdb71e74d8ca297c2afe04766b55d53597f86893351d",
|
||||
"/home/worsch/net-kingdom/workplans/NK-WP-0048-security-case-types.md": "sha256:b737bfae4802c122b21619695a169d7d082672af96314b1709860dd5aff2a60f"
|
||||
},
|
||||
"canonical_pre_post_hashes_equal": true,
|
||||
"checker_rehash_matches_delivered_artifact": true,
|
||||
"checks": [
|
||||
{
|
||||
"argv": [
|
||||
"/usr/bin/python3",
|
||||
"-B",
|
||||
"/home/worsch/net-kingdom/tools/security-case-types/security_case_validator.py",
|
||||
"render",
|
||||
"/home/worsch/net-kingdom/security-cases/forgejo-netkingdom-oidc.yaml",
|
||||
"--types",
|
||||
"/home/worsch/net-kingdom/security-case-types",
|
||||
"--repos-root",
|
||||
"/home/worsch",
|
||||
"--allow-unimplemented"
|
||||
],
|
||||
"execution_permitted": false,
|
||||
"render_digest": "sha256:e64b56e4590b57b858303fcda1a474693e3dd821bc83df26646fe78fc345498a",
|
||||
"returncode": 0,
|
||||
"stderr": "",
|
||||
"stdout_sha256": "sha256:186461a1dc2d587ccc0cc9ea6e51f05214d6cfe94f4aa0764e3150ab197ad3cf",
|
||||
"type": "oidc-browser-relying-party@1.1"
|
||||
},
|
||||
{
|
||||
"argv": [
|
||||
"/usr/bin/python3",
|
||||
"-B",
|
||||
"/home/worsch/net-kingdom/tools/security-case-types/security_case_validator.py",
|
||||
"render",
|
||||
"/home/worsch/net-kingdom/security-case-type-revisions/1.2/oidc-browser-relying-party/examples/forgejo.yaml",
|
||||
"--types",
|
||||
"/home/worsch/net-kingdom/security-case-types",
|
||||
"--version-root",
|
||||
"1.2=/home/worsch/net-kingdom/security-case-type-revisions/1.2",
|
||||
"--repos-root",
|
||||
"/home/worsch",
|
||||
"--allow-unimplemented"
|
||||
],
|
||||
"execution_permitted": false,
|
||||
"render_digest": "sha256:c0afd5576cdae0cbc807eccb2b9fa87ac668f15e32ec7cf79d295bdb23c75b35",
|
||||
"returncode": 0,
|
||||
"stderr": "",
|
||||
"stdout_sha256": "sha256:96b25108335e2cf5f96af481fe8a7735831c8320d81b50f7c6e6d4e53d0c0f02",
|
||||
"type": "oidc-browser-relying-party@1.2"
|
||||
},
|
||||
{
|
||||
"argv": [
|
||||
"/usr/bin/python3",
|
||||
"-B",
|
||||
"/home/worsch/net-kingdom/tools/security-case-types/security_case_validator.py",
|
||||
"validate-case",
|
||||
"/home/worsch/net-kingdom/security-case-type-revisions/1.2/oidc-browser-relying-party/examples/forgejo.yaml",
|
||||
"--types",
|
||||
"/home/worsch/net-kingdom/security-case-types",
|
||||
"--version-root",
|
||||
"1.2=/home/worsch/net-kingdom/security-case-type-revisions/1.2"
|
||||
],
|
||||
"returncode": 1,
|
||||
"stderr": "ERROR case.spec.type: type 'oidc-browser-relying-party' is 'acknowledged'; only implemented types accept cases\n",
|
||||
"stdout_sha256": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
}
|
||||
],
|
||||
"closed_descriptor_count": 1,
|
||||
"complete_review_step_count": 7,
|
||||
"descriptor_round_trip": true,
|
||||
"knowledge": {
|
||||
"cards": [
|
||||
"start",
|
||||
"evidence"
|
||||
],
|
||||
"package_digest": "8d1d6a9d4d07fec7b619618de7dfe2254c1790f85f4198c7fe19db9751c02",
|
||||
"package_version": "0.2.6",
|
||||
"status": "withheld source changed; direct owner source reviewed, no offline guidance used as authority"
|
||||
},
|
||||
"native_execution": false,
|
||||
"observed_at": "2026-10-17T02:10:28.924934+00:00",
|
||||
"tests_added_or_rerun": false
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue