Record founder source acknowledgment for isolated Forgejo type 1.2
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
This commit is contained in:
tegwick 2026-10-11 08:56:45 +02:00
parent 584a964684
commit f6856cdb53
13 changed files with 859 additions and 2 deletions

View file

@ -0,0 +1 @@
{"memo_id": "infd-20261011-forgejo-type12-source-r1", "version": 1, "register_event_id": "66d85468-6cd9-4a40-8c35-febc152758c0", "revision_event_id": null, "publication_event_id": "cbe4a05f-c7ab-4770-8e6e-8b537b165f7e", "review_event_id": "5be59cf9-a207-43aa-9fe2-131dc1e53538", "review_memo_id": "review-126c6c90-11ba-4609-b8d1-75e054c246cd", "queue_status": "pending", "queue_detail": "queued", "workspace_url": "https://decisions.coulomb.social/decisions/infd-20261011-forgejo-type12-source-r1?version=1", "outcome_review": {"intake_state": "not_submitted", "memo_id": "review-126c6c90-11ba-4609-b8d1-75e054c246cd", "stale": false}, "human_dispositions": 0}

View file

@ -0,0 +1 @@
{"memo_id": "infd-20261011-forgejo-type12-source-r1", "review": {"intake_state": "ready", "memo_id": "review-126c6c90-11ba-4609-b8d1-75e054c246cd", "path": "/review?memo_id=review-126c6c90-11ba-4609-b8d1-75e054c246cd", "stale": false}, "disposition_count": 1, "dispositions": [{"id": null, "approval_id": null, "submission_state": "confirmed", "disposition": {"actor": {"kind": "person", "sub": "uid=platform-root,ou=people,dc=netkingdom,dc=local"}, "approval_id": "8e9332c8-754a-420c-b8b7-445cb4fe6765", "at": "2026-10-11T06:47:39Z", "id": "disp-315d54ad-20f1-40e6-862c-6c7d2e8f0ea8", "memo_id": "review-126c6c90-11ba-4609-b8d1-75e054c246cd", "memo_version": 1, "note": null, "presentation_id": "pres-5a52f932-8c65-46cc-8054-0264f47f934a", "reasons": [], "verb": "accept"}, "approved_at": "2026-10-11T06:47:39+00:00", "decided_at": null}]}

View file

@ -0,0 +1,18 @@
{
"acknowledged_type_sha256": "9e60ff569fb0d860a2bbde7bbb0991a54d4b0688f62b56df0fa5d161fd624578",
"only_type_status_semantic_delta": true,
"full_package_validator_pass": true,
"independent_acknowledged_package_tests_passed": 22,
"closed_schema_checks_pass": true,
"explicit_version_root_loads_exact12": true,
"default11_type_and_case_byte_unchanged": true,
"canonical_case12_proposed_no_acceptance": true,
"ordinary_admission_refused": true,
"full_render_regeneration_identical": true,
"full_render_digest": "sha256:c0afd5576cdae0cbc807eccb2b9fa87ac668f15e32ec7cf79d295bdb23c75b35",
"execution_permitted": false,
"packet_bound_files_mutated": false,
"genuine_native_human_source_accept_confirmed": true,
"human_approval_id": "8e9332c8-754a-420c-b8b7-445cb4fe6765",
"new_native_action_by_worker": false
}

View file

@ -0,0 +1,39 @@
# Forgejo type1.2 source acknowledgment and existing implementation gates
Confirmed human source ACCEPT at2026-10-11T06:47:39Z is recorded separately from
implementation. Exact type package lives at
security-case-type-revisions/1.2/oidc-browser-relying-party/; its external
decision/acknowledgment.json binds actual memo, human actor/disposition, packet,
proposed/acknowledged source hashes and post-anchor review. Type.yaml changes
only semantic status proposed→acknowledged; README history and one test expectation
adapt to the recorded source state. The frozen proposed human packet stays
immutable. Independent acknowledged-package validator and22 tests pass; closed
schema/version load and identical c0afd preparation render are proved.
Current canonical1.1 package and accepted1.1 case remain unchanged, without
inherited1.2 authority. Current load_type reads one type.yaml per id and requires
exact version, so selecting1.2 as default would break that1.1 case. The explicit
version root loads1.2 through existing --types/--types-root input, only for source
validation/preparation. This record changes no resolver/default, native broker
pin, canonicalcase or adapter. The1.2 reference remains proposed without
acceptance fields; normal admission still refuses acknowledged/unimplemented type.
Separate Apps receipt records only actual human reference-design scope.
## Actual next source/proof gates in existing work
| Owner work | Remaining contract and evidence |
| --- | --- |
| NK-WP-0048-T06 / existing ORGREF driver | Deliberately integrate explicit version selection and first-reference source receipts under the accepted lifecycle. Ordinary case acceptance requires implemented type; preparation flags and design receipt are no waiver. Define source bootstrap integration without inventing canonical admission. Type becomes implemented only after materialization/follow-through capability and actual live verified reference proof, with distinct owner acceptance. |
| WARDEN-WP-0044-T03, then T04 | Current case_run.py is a closed local kernel with no installed owner adapters/live CLI dispatch; case_receipt_state.py is a pure/proposed reducer. Need exact owner-acknowledged descriptors/adapters, independently authenticated global provenance verifier, durable attempt/recovery receipts, bounded caller grant/session/source pins and confirmed revocation. No shell/type prose execution, privilege manufacture, native success from local prototype or pending-owner receipt. |
| MASON-WP-0010-T03, then T04 | Current case_structure.py prepares typed evidence requests, not native materialization. Rebuild reviewed source deliberately with exact version/type/case/render and corrected CCR targets; obtain independent authenticated layout/policy/role/catalog observations and created-versus-preexisting ownership/change receipts for all six objects. No mint prerequisite for structural proof and no trusted self-authored JSON acceptance. Preserve old wrong-target bundle refusal. |
| Platform existing CCR-2026-0042 and broker owner path | Reconcile historical/current/proposed body and actual exact SA/namespace/audience/read-only policy; bound claims are still false. Any source broker/case pin adaptation needs exact owner review and source tests, not blanket version bypass. Native apply/capabilities/created-object/issued-token revocation or verified-expiry receipts require separately approved authority. A source role deletion does not revoke issued tokens. |
| NetKingdom/KeyCape registration/group/env owners | Supply exact attended registration/config/group/verify/undo adapters or owner receipt-only steps through existing lanes. Bind registry/environment/groups to reviewed case; do not substitute user-engine runtime identity or give Warden new broad Kubernetes authority. Native unknown outcomes remain unresolved pending owner reconciliation. |
| RAPPS-WP-0016-T02, with its existing T01 prerequisite | Refresh exact ESO/CRD/RBAC/dedicatedSA/no legacy refs and target ownership metadata. Prepare reviewed Helm OIDC secret consumption and group enforcement adapters or receipt-only consumer step; native Store/ExternalSecret Ready is not browser/MFA/group refusal, break-glass/account-link or first-case completion. Shared ESO trust/default workloadSA remain explicit. |
All created-only undo retains immutable UIDs/ownership and exact source references;
preserve matched/shared resources, revert consumer references first, revoke issued
reader tokens or independently prove expiry before role removal, then policy.
No new login/remint or speculative delete authority follows from this record.
Existing native acceptance and human gates remain in their current owner/project
records. This document adds no broad plan, promoted residual or implementation
permission and marks no existing implementation task done.

View file

@ -0,0 +1,32 @@
{
"reviewer": "net-kingdom-owner (agent net-kingdom, codex)",
"decision": "approved",
"work_item": "NK-WP-ADHOC-2026-10-11-T06",
"comment": "Same NetKingdom source role/trial after actual completedT06 anchor. INTENT Taxonomy and Meta-Orchestration support truthful exact human source acknowledgment recording in explicit version root without default1.1 repoint, package authority inflation or canonicalcase acceptance. Root requesting agent transcribes actual human8e9332c8 disposition; this technical review supplies no founder decision or other owner role.",
"acknowledged_type_sha256": "9e60ff569fb0d860a2bbde7bbb0991a54d4b0688f62b56df0fa5d161fd624578",
"independent_recording_checks": {
"acknowledged_type_sha256": "9e60ff569fb0d860a2bbde7bbb0991a54d4b0688f62b56df0fa5d161fd624578",
"only_type_status_semantic_delta": true,
"full_package_validator_pass": true,
"independent_acknowledged_package_tests_passed": 22,
"closed_schema_checks_pass": true,
"explicit_version_root_loads_exact12": true,
"default11_type_and_case_byte_unchanged": true,
"canonical_case12_proposed_no_acceptance": true,
"ordinary_admission_refused": true,
"full_render_regeneration_identical": true,
"full_render_digest": "sha256:c0afd5576cdae0cbc807eccb2b9fa87ac668f15e32ec7cf79d295bdb23c75b35",
"execution_permitted": false,
"packet_bound_files_mutated": false,
"genuine_native_human_source_accept_confirmed": true,
"human_approval_id": "8e9332c8-754a-420c-b8b7-445cb4fe6765",
"new_native_action_by_worker": false
},
"completed_actual_anchor_sha256": "b33f203ff9e6318442b04374a5c6c97518097c2c9cad2bc38f65e3e9050f7820",
"canonical_package_type_path": "security-case-type-revisions/1.2/oidc-browser-relying-party/type.yaml",
"only_type_semantic_delta": "status proposed to acknowledged",
"packet_bound_type_sources_changed": false,
"default11_type_and_case_changed": false,
"next_owner_gates": "docs/forgejo-type12-source-acknowledgment-followthrough.md",
"new_native_operation": false
}

View file

@ -0,0 +1,54 @@
# Acknowledged OIDC browser relying-party 1.2 source package
This package supplements the exact proposed 1.2 type and Forgejo reference design. It is source-only and unimplemented. Its examples are proposed, including Forgejo; normal admission must refuse them until the separate implemented-type and canonical-case acceptance requirements are discharged. Completing this package or acknowledging its type does not accept a canonical case or authorize native work. Immutable acknowledged 1.1 history remains unchanged.
## Purpose
Register exact-redirect browser OIDC relying parties through KeyCape, with groups enforced by the consumer. Confidential clients add a custody path, two reader policies, the existing KeyCape ESO role and a sixth dedicated consumer ESO reader role. consumer_namespace is explicit and independently constrained; a consuming service name does not establish its namespace or workload identity. Public clients require no secret materialization.
## Threat model
Exact HTTPS redirects prohibit wildcard, query, fragment and plaintext HTTP. Requested scopes always include groups, but KeyCape issues identity tokens without a per-client group gate: each consumer must enforce its required claims. MFA pinning is client configuration, not proof of a human MFA session. Secret custody parameters and reader identities cannot be overridden by case authors.
The namespace SecretStore references a dedicated automount-disabled service account rather than forgejo/default. ESO's broadly privileged common controller remains trusted; this is routing and identity attribution, not cryptographic controller isolation. The supported v0.16.1 TokenRequest path requests a 600-second token; its legacy fallback must not acquire static tokens. The proposed OpenBao role has a 900-second maximum token TTL and no default policy. Neither rendered claims nor source tests prove native bindings, token audience, capabilities, delivery readiness or revocation.
## Alternatives considered
Retain 1.1 with the observed Forgejo/runner workload ServiceAccount forgejo/default: preserves existing history but does not express the dedicated reader boundary. This describes observed workload identity only; the historical 1.1 consumer OpenBao policy was unbound and no historical default-SA OpenBao reader binding is claimed. Reuse the KeyCape reader role: combines provider and consumer identities unnecessarily. Adopt a separate controller: potentially reduces shared trust but adds infrastructure outside this bounded proposal. Proposed 1.2 retains shared-controller trust explicitly while adding the sixth dedicated role; no new grant follows from this source design.
## Known limits
All native bound claims remain unconfirmed and execution remains false. HTTP OpenBao transport, shared ESO controller trust, legacy fallback, retained target Secrets and later dependency handling require owner verification before any separately approved session. A SecretStore/SA deletion alone does not revoke issued tokens. Recovery may remove only authenticated case-created resources with unchanged UID/ownership, must preserve preexisting exact matches, revert consumer references first and revoke issued tokens or verify expiry before declaring deactivation. Owner adapter and global verifier observations remain required. No human login, MFA, credentials, native materialization or first-case completion is claimed.
## Verification
Run the existing owner full-package validator against this directory, then run its tests. Tests use the existing owner validator/composer and actual declarations; they prove source schema, examples, deterministic rendering, six-object confidential versus public boundaries, refused mutation/parameters, normal admission refusal and bounded rollback ordering. They do not contact native services.
```sh
python3 tools/security-case-types/security_case_validator.py validate-type docs/proposals/2026-10-11-forgejo-consumer-eso/package-1.2
NET_KINGDOM_ROOT=/home/worsch/net-kingdom python3 -m pytest docs/proposals/2026-10-11-forgejo-consumer-eso/package-1.2/tests
```
## Governance and recording
SecurityCaseTypes section 3 requires the complete package and a separate NetKingdom source-owner review before type acknowledgment recording. Sections 4/5 require an implemented type for canonical case acceptance; section 6 requires a genuine new acknowledgment for the sixth role/authentication path. The old 1.1 acknowledgment is not inherited. Reference-migration source approval is a separate owner receipt; canonical 1.2 stays proposed without acceptance fields or phase acceptance.
## Recorded source acknowledgment — 2026-10-11
Confirmed native human ACCEPT of infd-20261011-forgejo-type12-source-r1@1
at2026-10-11T06:47:39Z, approval8e9332c8-754a-420c-b8b7-445cb4fe6765,
acknowledges source architecture only. Exact reviewed proposed typeSHA
017885bdd139cd66a5bf6d9839b1b8ec9bc08fb051d9577adc3928b76a7be6db is preserved
in the immutable proposal package. This copy changes type status to acknowledged
and documents that source record; it remains unimplemented. See
decision/acknowledgment.json for exact native disposition, packet, owner returns,
post-anchor review and source digests. Tests adapt only the expected type status;
examples remain proposed without acceptance fields. Current canonical1.1 type,
package and acceptedcase remain unchanged and selected by the default loader.
This explicit version root is security-case-type-revisions/1.2; choose it only
for separate source validation/preparation using the existing --types/--types-root
option. No default loader/repoint or canonicalcase1.2 admission is introduced.
The full proposed package test/validator proof is retained; run this acknowledged
copy's package validator/tests before recording its acknowledgment. The separate
reference-migration owner design receipt is not canonical case acceptance.

View file

@ -0,0 +1,79 @@
{
"kind": "security-case-type-source-acknowledgment",
"type": "oidc-browser-relying-party@1.2",
"stable_proposal": "NK-FORGEJO-TYPE12-SOURCE-20261011-R1",
"work_item": "NK-WP-ADHOC-2026-10-11-T06",
"source_implementation_task": "NK-WP-0048-T06",
"memo_id": "infd-20261011-forgejo-type12-source-r1",
"memo_version": 1,
"review_id": "review-126c6c90-11ba-4609-b8d1-75e054c246cd",
"approval_id": "8e9332c8-754a-420c-b8b7-445cb4fe6765",
"disposition_id": "disp-315d54ad-20f1-40e6-862c-6c7d2e8f0ea8",
"presentation_id": "pres-5a52f932-8c65-46cc-8054-0264f47f934a",
"actual_human_actor": {
"kind": "person",
"sub": "uid=platform-root,ou=people,dc=netkingdom,dc=local"
},
"actual_disposition_at": "2026-10-11T06:47:39Z",
"verb": "accept",
"confirmed_nonstale": true,
"exact_human_packet_manifest_sha256": "0b377d647ca748cd03c92f9792396412048055d4bde9f7bb06ff6d413f7acd68",
"submission_digest": "sha256:585cee731de30d2b37883a57abfd9eb32f023ee694e8d911989109d5caf80569",
"proposed_type_sha256": "017885bdd139cd66a5bf6d9839b1b8ec9bc08fb051d9577adc3928b76a7be6db",
"acknowledged_type_sha256": "9e60ff569fb0d860a2bbde7bbb0991a54d4b0688f62b56df0fa5d161fd624578",
"canonical_case12_source_sha256": "1c868c1da7d9077fae97bc6bc029706ec3dc418cfeaae30dc0f92b5b4ba6f2ab",
"full_render_digest": "sha256:c0afd5576cdae0cbc807eccb2b9fa87ac668f15e32ec7cf79d295bdb23c75b35",
"version_types_root": "security-case-type-revisions/1.2",
"package_type_path": "security-case-type-revisions/1.2/oidc-browser-relying-party/type.yaml",
"packet_bound_sources_edited": false,
"default_type_loader_or_11_case_repointed": false,
"current11_preserved": {
"type_path": "security-case-types/oidc-browser-relying-party/type.yaml",
"type_sha256": "f705c64e4875e9b8e18a912fb51c135e77898926d6a451f5cb74ab3c0cbe4d1c",
"case_path": "security-cases/forgejo-netkingdom-oidc.yaml",
"case_sha256": "bcc2c6d5bae0d28242b3cdb71e74d8ca297c2afe04766b55d53597f86893351d"
},
"review_receipts": [
{
"path": "docs/reviews/2026-10-11-forgejo-type12-human-packet-net-owner-final-review.md",
"sha256": "9e9b8dda889203c064b35e1bbcd4d0c62d76d4ba1935c9a10f4b2dbf1c6e8497"
},
{
"path": "docs/reviews/2026-10-11-forgejo-type12-human-packet-final-hash-ack.json",
"sha256": "7f2264668ad205d127bb216bc726f62a6ee447759f9899fcccc6c439b9bbefe5"
},
{
"path": "docs/reviews/2026-10-11-forgejo-type12-post-anchor-owner-review.json",
"sha256": "0893b8fe936c72394147bc511c6a21af8e75866c96549ceec8af5d2abd1ee100"
}
],
"native_source_provenance": [
{
"path": "docs/evidence/2026-10-11-forgejo-type12-source-acknowledgment/native-outcome.json",
"sha256": "042fcc80dbd450ad6901d91624b544e2128d4bb3045ae201d570ec0bf96f5f2d"
},
{
"path": "docs/evidence/2026-10-11-forgejo-type12-source-acknowledgment/native-authoring-receipt.json",
"sha256": "67b581d2f825d0ba10bcbf0296e7f9e63f5d78e5d6d723150b0983f067635172",
"initial_authoring_was_queued_not_disposed": true
}
],
"scope": "Confirmed human source architecture acknowledgment only; reference-migration design approval recorded separately. No agent decision. Root requesting agent records exact actual founder disposition after verifying these staged files.",
"type_implemented": false,
"canonical_case12_status": "proposed",
"canonical_case12_acceptance_fields_present": false,
"claims_confirmed": false,
"execution_permitted": false,
"native_operation_authorized": false,
"recording_act": "Transcribe confirmed human source acknowledgment; requesting coordinator applies this exact record after independent verification. This is not an agent approval.",
"recorded_status": "source-acknowledged",
"recorded_package_validation": {
"actual_full_package_validator": "PASS acknowledged1.2",
"independent_runnable_tests": 22,
"closed_type_case_schemas": "PASS",
"ordinary_case_admission": "REFUSED unimplemented acknowledged type",
"explicit_types_root_load": "PASS",
"full_render_regenerated_digest": "sha256:c0afd5576cdae0cbc807eccb2b9fa87ac668f15e32ec7cf79d295bdb23c75b35",
"execution_permitted": false
}
}

View file

@ -0,0 +1,20 @@
apiVersion: netkingdom.io/security-case/v0.1
kind: SecurityCase
spec:
id: example-public-portal
type: oidc-browser-relying-party@1.2
status: proposed
owner:
repo: net-kingdom
person: example-owner
parameters:
client_id: example-portal
display_name: Example portal
redirect_uris: https://portal.example.invalid/auth/callback
allowed_scopes: openid,profile,email,groups
client_type: public
mfa_required: 'false'
access_groups: example-portal-users
consuming_service: example-portal
consumer_owner_repo: net-kingdom
consumer_namespace: example-portal

View file

@ -0,0 +1,21 @@
apiVersion: netkingdom.io/security-case/v0.1
kind: SecurityCase
spec:
id: forgejo-netkingdom-oidc
type: oidc-browser-relying-party@1.2
status: proposed
owner:
repo: railiance-apps
person: founder
parameters:
client_id: forgejo
display_name: Forgejo source forge
redirect_uris: https://forgejo.coulomb.social/user/oauth2/netkingdom/callback
allowed_scopes: openid,profile,email,groups
client_type: confidential
mfa_required: 'true'
access_groups: forge-admins,forge-coulomb-owners,forge-coulomb-readers
initial_members: forge-admins=tegwick;forge-coulomb-owners=tegwick
consuming_service: forgejo
consumer_owner_repo: railiance-apps
consumer_namespace: forgejo

View file

@ -0,0 +1,88 @@
"""Source-only contract checks against the actual owner validator and declarations."""
import copy, importlib.util, os, sys
from pathlib import Path
import pytest, yaml
PACKAGE=Path(__file__).resolve().parents[1]
OWNER=Path(os.environ.get("NET_KINGDOM_ROOT", "/home/worsch/net-kingdom"))
VP=OWNER/"tools/security-case-types/security_case_validator.py"
sys.path.insert(0,str(VP.parent))
spec=importlib.util.spec_from_file_location("security_case_validator",VP)
v=importlib.util.module_from_spec(spec);sys.modules[spec.name]=v;spec.loader.exec_module(v)
TYPE=yaml.safe_load((PACKAGE/"type.yaml").read_text())
FORGEJO=yaml.safe_load((PACKAGE/"examples/forgejo.yaml").read_text())
paths,discovery=v.discover_declarations(TYPE,OWNER.parent)
DECLS,loading=v.composer.load_declarations(paths)
def render(case):
issues,result=v.render_case(case,TYPE,DECLS,require_implemented=False)
assert not v.has_errors(discovery+loading+issues)
return result
def test_full_package_and_proposed_boundary():
assert not v.has_errors(v.validate_type(TYPE,PACKAGE))
assert TYPE["spec"]["status"]=="acknowledged"
assert FORGEJO["spec"]["status"]=="proposed"
assert "acceptance" not in FORGEJO["spec"]
assert v.has_errors(v.validate_case(FORGEJO,TYPE))
def test_acknowledged_is_still_not_implemented_admission():
acknowledged=copy.deepcopy(TYPE);acknowledged["spec"]["status"]="acknowledged"
assert v.has_errors(v.validate_case(FORGEJO,acknowledged))
@pytest.mark.parametrize("example",sorted((PACKAGE/"examples").glob("*.yaml")))
def test_examples_valid_deterministic_and_nonexecuting(example):
case=yaml.safe_load(example.read_text())
assert not v.has_errors(v.validate_case(case,TYPE,require_implemented=False))
first=render(case);assert first==render(case)
assert first["execution"]["permitted"] is False
assert first["composition"]["execution"]["permitted"] is False
def test_sixth_role_is_exact_consumer_identity_and_namespace():
case=copy.deepcopy(FORGEJO);case["spec"]["parameters"]["consumer_namespace"]="forgejo-preview"
r=render(case);objects={x["id"]:x for x in r["materialization"]}
assert len(objects)==6
consumer=yaml.safe_load(objects["consumer-eso-role"]["body"])
assert consumer["bound_service_account_names"]==["forgejo-keycape-forgejo-eso"]
assert consumer["bound_service_account_namespaces"]==["forgejo-preview"]
assert consumer["audience"]=="openbao"
assert consumer["token_policies"]==["workload-kv-read-keycape-forgejo-forgejo"]
assert consumer["token_no_default_policy"] is True
provider=yaml.safe_load(objects["eso-role"]["body"])
assert provider["bound_service_account_names"]!=consumer["bound_service_account_names"]
def test_original_five_structural_bodies_unchanged():
old=yaml.safe_load((OWNER/"security-case-types/oidc-browser-relying-party/type.yaml").read_text())
case=yaml.safe_load((OWNER/"security-cases/forgejo-netkingdom-oidc.yaml").read_text())
issues,before=v.render_case(case,old,DECLS,require_implemented=False)
assert not v.has_errors(issues)
after={x["id"]:x["body"] for x in render(FORGEJO)["materialization"]}
for item in before["materialization"]:assert item["body"]==after[item["id"]]
def test_public_has_no_secret_or_delivery_hooks():
r=render(yaml.safe_load((PACKAGE/"examples/example-public-portal.yaml").read_text()))
assert [x["id"] for x in r["materialization"]]==["catalog-entry"]
assert not {"mint-secret","deliver-secret","deliver-consumer-secret","bind-env"}&{x["id"] for x in r["follow_through"]}
@pytest.mark.parametrize("key,value",[("consumer_namespace",None),("consumer_namespace","default/other"),("consumer_namespace","x"*64),("consuming_service","x"*64),("redirect_uris","http://portal.invalid/callback"),("redirect_uris","https://portal.invalid/*"),("redirect_uris","https://portal.invalid/callback?x=y"),("redirect_uris","https://portal.invalid/callback#x"),("allowed_scopes","openid,email"),("consumer_reader_service_account","default"),("secret_path","other/path")])
def test_invalid_or_unsettable_parameter_refused(key,value):
case=copy.deepcopy(FORGEJO)
if value is None:case["spec"]["parameters"].pop(key)
else:case["spec"]["parameters"][key]=value
assert v.has_errors(v.validate_case(case,TYPE,require_implemented=False))
def test_created_only_role_recovery_precedes_policy_and_needs_revocation():
rollback=render(FORGEJO)["rollback"];ids=[x["reverses"] for x in rollback]
assert ids.index("consumer-eso-role")<ids.index("consumer-reader-policy")
action=next(x["action"] for x in rollback if x["reverses"]=="consumer-eso-role")
assert "case-created" in action and "revoke" in action and "expiration" in action
delivery=next(x["action"] for x in rollback if x["reverses"]=="deliver-consumer-secret")
assert "UID" in delivery and "preexisting" in delivery and "consumer secret reference" in delivery
@pytest.mark.parametrize("omitted",["README.md","tests/test_source_contract.py","examples"])
def test_full_package_validator_rejects_incomplete_supplement(tmp_path,omitted):
import shutil
trial=tmp_path/"package";shutil.copytree(PACKAGE,trial,ignore=shutil.ignore_patterns("__pycache__",".pytest_cache"))
target=trial/omitted
if target.is_dir():
for example in target.glob("*.yaml"):example.unlink()
else:target.unlink()
assert v.has_errors(v.validate_type(TYPE,trial))

View file

@ -0,0 +1,442 @@
apiVersion: netkingdom.io/security-case-type/v0.1
kind: SecurityCaseType
spec:
id: oidc-browser-relying-party
version: '1.2'
status: acknowledged
title: Browser OIDC relying party for an internal service
purpose: 'Let an internal web service sign its human users in through NetKingdom
(KeyCape): an exact-redirect OIDC client, optional MFA pin, the LLDAP groups the
service maps to its own roles, and, for confidential clients, a client secret
minted straight into OpenBao custody. Replaces the per-client rollout scripts
in sso-mfa/k8s/keycape. First case: Forgejo (KEY-WP-0038).'
parameters:
- name: client_id
type: string
case_settable: true
constraints:
pattern: ^[a-z0-9][a-z0-9-]{1,62}$
sensitivity: operational
description: OAuth2 client_id, unique in KeyCape.
- name: display_name
type: string
case_settable: true
constraints:
pattern: ^[^\n\r]{1,80}$
sensitivity: public
description: Name shown on the sign-in page.
- name: redirect_uris
type: string
case_settable: true
constraints:
pattern: ^https://[^*?#\s,]+(,https://[^*?#\s,]+)*$
sensitivity: security_sensitive
description: 'Comma-separated exact https redirect URIs. No wildcards, no plain
http, no query and no fragment: KeyCape refuses ''*'' and ''?'' at startup,
and OAuth 2.0 forbids fragments (key-cape type review R1).'
- name: allowed_scopes
type: string
case_settable: true
constraints:
enum:
- openid,profile,email,groups
- openid,email,groups
- openid,profile,groups
- openid,groups
sensitivity: security_sensitive
description: Scopes the client may request, openid first. Always includes groups,
because access_groups is required and KeyCape's UserInfo returns groups only
for that scope (key-cape type review R2).
- name: client_type
type: string
case_settable: true
constraints:
enum:
- confidential
- public
sensitivity: security_sensitive
description: confidential for server-side services that can hold a secret; public
for SPAs and native apps (PKCE only).
- name: mfa_required
type: string
case_settable: true
constraints:
enum:
- 'true'
- 'false'
sensitivity: security_sensitive
description: '"true" pins MFA on this client; required when the service grants
administrative or owner rights. "false" is not "no MFA": the client then carries
no mfaRequired field and KeyCape applies the per-user privacyIDEA policy. A
renderer must never emit an explicit mfaRequired false, which would skip that
policy (key-cape type review R3).'
- name: access_groups
type: string
case_settable: true
constraints:
pattern: ^[a-z][a-z0-9-]{1,62}(,[a-z][a-z0-9-]{1,62})*$
sensitivity: operational
description: 'Comma-separated LLDAP groups that the service maps to its roles.
Created if absent. KeyCape has no per-client group gate: it issues tokens to
any authenticated user and only carries the groups claim, so the consuming service
enforces the gate itself (for Forgejo, its required-claim setting; key-cape
type review R2).'
- name: initial_members
type: string
required: false
case_settable: true
constraints:
pattern: ^[a-z][a-z0-9-]*=[a-z][a-z0-9._-]*(\+[a-z][a-z0-9._-]*)*(;[a-z][a-z0-9-]*=[a-z][a-z0-9._-]*(\+[a-z][a-z0-9._-]*)*)*$
sensitivity: operational
description: Initial memberships as group=user+user;group=user. Usernames are
directory usernames, never secrets.
- name: consuming_service
type: string
case_settable: true
constraints:
pattern: ^[a-z0-9][a-z0-9-]{0,62}$
sensitivity: operational
description: The service that signs users in with this client.
- name: consumer_owner_repo
type: string
case_settable: true
constraints:
pattern: ^[a-z0-9][a-z0-9-]*$
sensitivity: operational
description: The repository that owns the consuming service's configuration.
- name: consumer_namespace
type: string
case_settable: true
constraints:
pattern: ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$
sensitivity: security_sensitive
description: Consumer namespace for namespaced ESO TokenRequest reader; actual
workload owner must confirm; never infer from service name.
- name: issuer
type: string
case_settable: false
default: https://kc.coulomb.social
sensitivity: security_sensitive
description: The NetKingdom issuer; fixed by the type.
composition:
authority: netkingdom
initial_trust:
- runtime_secret_trust
- runtime_identity_trust
capabilities:
- c1.lightweight-sso
providers:
c1.lightweight-sso: net-kingdom.keycape-client-registration
parameter_bindings:
net-kingdom.keycape-client-registration.client_id: client_id
net-kingdom.keycape-client-registration.display_name: display_name
net-kingdom.keycape-client-registration.redirect_uris: redirect_uris
net-kingdom.keycape-client-registration.allowed_scopes: allowed_scopes
net-kingdom.keycape-client-registration.client_type: client_type
net-kingdom.keycape-client-registration.mfa_required: mfa_required
materialization:
- id: client-secret-path
kind: kv_path
when: client_type == confidential
template: platform/workloads/keycape/{client_id}
body: field CLIENT_SECRET; minted by the credential broker, never written by hand
- id: keycape-reader-policy
kind: openbao_policy
when: client_type == confidential
template: workload-kv-read-keycape-{client_id}-eso
body: "path \"platform/data/workloads/keycape/{client_id}\" {{\n capabilities\
\ = [\"read\"]\n}}\n"
description: KeyCape reads its client secret only through ESO. No metadata, list,
parent or sibling access.
- id: consumer-reader-policy
kind: openbao_policy
when: client_type == confidential
template: workload-kv-read-keycape-{client_id}-{consuming_service}
body: "path \"platform/data/workloads/keycape/{client_id}\" {{\n capabilities\
\ = [\"read\"]\n}}\n"
description: The consuming service reads the same secret. No metadata, list, parent
or sibling access.
- id: eso-role
kind: openbao_role
when: client_type == confidential
template: external-secrets-keycape-{client_id}
body: 'auth: kubernetes
bound_service_account_names: [external-secrets]
bound_service_account_namespaces: [external-secrets]
token_policies: [workload-kv-read-keycape-{client_id}-eso]
token_no_default_policy: true
token_ttl: 15m
token_max_ttl: 15m
'
description: The Kubernetes-auth role deliver-secret uses; bound to the ESO service
account only.
- id: consumer-eso-role
kind: openbao_role
when: client_type == confidential
template: external-secrets-keycape-{client_id}-{consuming_service}
body: 'auth: kubernetes
bound_service_account_names: [{consuming_service}-keycape-{client_id}-eso]
bound_service_account_namespaces: [{consumer_namespace}]
audience: openbao
token_policies: [workload-kv-read-keycape-{client_id}-{consuming_service}]
token_no_default_policy: true
token_ttl: 15m
token_max_ttl: 15m
'
description: Consumer ESO requests a token for this separate reference identity.
Common ESO controller remains trusted and can request tokens; no cryptographic
controller isolation is claimed.
- id: catalog-entry
kind: catalog_entry
template: '{consuming_service}-keycape-client'
body: 'id: {consuming_service}-keycape-client
owner_repo: key-cape
warden_executes: false
risk: high
status: active once verification passes
workload_ref: applicable, name {consuming_service}, declaration_ref of the consumer''s
published declaration or the explicit unknown form, never inferred
path_template: platform/workloads/keycape/{client_id}
field: CLIENT_SECRET
delegation: native, intended_owner key-cape
rotation: mint-secret then verification; automatable false until a run has been
proven
'
description: One entry per case (ops-mason item 5, ops-warden R4'). It carries
the consumer's workload reference, which ADR-0009 needs for zone selection.
follow_through:
- id: ensure-groups
owner: net-kingdom
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)
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
lane: key-cape-oidc-login
warden_executes: false
attended: true
value_handling: none
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.
- id: mint-secret
owner: railiance-platform
when: client_type == confidential
entry_point: 'railiance-platform credential broker: generate a client secret inside
custody at bao:platform/workloads/keycape/{client_id}'
auth: the caller's broker grant for the case's KV path, through its lane; the
value is generated in custody and never returned
lane: keycape-client-secret-generate
warden_executes: true
attended: false
value_handling: generated_in_custody
- id: deliver-secret
owner: railiance-platform
when: client_type == confidential
entry_point: ExternalSecret sso/keycape-{client_id}-client (key client-secret)
from bao:platform/workloads/keycape/{client_id}
auth: railiance-platform ESO delivery through role external-secrets-keycape-{client_id};
no value leaves custody
warden_executes: false
attended: false
value_handling: none
ready_check: the delivery for sso/keycape-{client_id}-client reports Ready=True
(status only, no value read)
- id: bind-env
owner: net-kingdom
when: client_type == confidential
entry_point: 'patch Deployment sso/keycape: env KEYCAPE_{client_id:env}_CLIENT_SECRET
from sso/keycape-{client_id}-client'
auth: operator kube credentials for namespace sso
lane: key-cape-oidc-login
warden_executes: false
attended: true
value_handling: none
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.
- id: register-client
owner: net-kingdom
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)
auth: operator write access to the live KeyCape client registry in namespace sso
lane: key-cape-oidc-login
warden_executes: false
attended: true
value_handling: none
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).'
- id: deliver-consumer-secret
owner: '{consumer_owner_repo}'
when: client_type == confidential
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.
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
warden_executes: false
attended: false
value_handling: none
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.
- id: hand-over
owner: '{consumer_owner_repo}'
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
auth: the consumer owner's own deployment path
warden_executes: false
attended: false
value_handling: none
verification:
- id: authorize-accepts-redirects
check: GET {issuer}/authorize with client {client_id} and each of {redirect_uris}
returns the login page
expect: present
reads_secret_value: false
- id: authorize-refuses-other-redirect
check: GET {issuer}/authorize with client {client_id} and an unregistered redirect
returns an OAuth error
expect: deny
reads_secret_value: false
- id: custody-denied-to-default
when: client_type == confidential
check: a default-only OpenBao identity has no read capability on bao:platform/workloads/keycape/{client_id}
expect: deny
reads_secret_value: false
- id: custody-allowed-to-consumer
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
reads_secret_value: false
- id: groups-present
check: LLDAP groups {access_groups} exist, with exactly the memberships of the
accepted case added
expect: present
reads_secret_value: false
- id: consumer-enforces-groups
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
reads_secret_value: false
- id: secret-delivered
when: client_type == confidential
check: the delivery for sso/keycape-{client_id}-client reports Ready=True (status
only)
expect: present
reads_secret_value: false
- id: mfa-pinned
when: mfa_required == true
check: keycape-client.py inspect for {client_id} shows the MFA pin on the registered
client (non-secret client view)
expect: present
reads_secret_value: false
- id: consumer-secret-delivered
when: client_type == confidential
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
reads_secret_value: false
rollback:
- reverses: hand-over
action: remove the OIDC source for {client_id} from {consuming_service} (owner
{consumer_owner_repo})
- reverses: deliver-consumer-secret
when: client_type == confidential
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: register-client
action: keycape-client.py apply --operation remove for {client_id}
- reverses: bind-env
when: client_type == confidential
action: remove env KEYCAPE_{client_id:env}_CLIENT_SECRET from Deployment sso/keycape,
after register-client is reversed
- reverses: deliver-secret
when: client_type == confidential
action: delete ExternalSecret sso/keycape-{client_id}-client and its target
- reverses: mint-secret
when: client_type == confidential
action: 'covered by client-secret-path: one metadata delete, after deliver-secret
is reversed'
- reverses: ensure-groups
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: client-secret-path
when: client_type == confidential
action: delete metadata and all versions at platform/workloads/keycape/{client_id},
after the ExternalSecret is gone (this also reverses mint-secret)
- reverses: eso-role
when: client_type == confidential
action: delete Kubernetes-auth role external-secrets-keycape-{client_id}
- reverses: keycape-reader-policy
when: client_type == confidential
action: delete policy workload-kv-read-keycape-{client_id}-eso, after eso-role
- reverses: consumer-eso-role
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-reader-policy
when: client_type == confidential
action: delete policy workload-kv-read-keycape-{client_id}-{consuming_service}
- reverses: catalog-entry
action: remove catalog entry {consuming_service}-keycape-client
acceptance:
accepted_by:
- owner
- founder
risk_class: medium

View file

@ -147,3 +147,18 @@ keeps canonicalcaseproposed, ordinary admission blocked and executionfalse.
Original eeb changes-requested review and prepackage12ce failures remain history,
not new scored successes. Final source agreement is separate receipt only;
no actual founder acknowledgment, native intake, acceptance or runtime change.
2026-10-11T06:47:39Z source-recording preparation, same T06 trial: latest native
outcome confirms nonstale person ACCEPT of exactmemo1, approval
8e9332c8-754a-420c-b8b7-445cb4fe6765, disposition
disp-315d54ad-20f1-40e6-862c-6c7d2e8f0ea8. Prepared external acknowledgment
receipt and complete acknowledged1.2 package in explicit version source root
security-case-type-revisions/1.2, changing type semantic status only. Independent
fullvalidator and22 adapted-source tests pass; schema/versionload/render checks
pass and normalcase admission remains refused. Packet-bound proposed sources
and defaultcanonical1.1 package/case stay byte-identical. Separate Apps design
receipt transcribes the actual human source scope, not an agent ownerreview or
canonicalcase acceptance. Requesting coordinator records actual foundergo; no
worker native/credential/grant action. Canonical1.2case remains proposed without
acceptance; implementation followthrough remains existing NK0048-T06/project
owner tasks. No new trial, taskT07, broad plan or whole-workplan finish.

View file

@ -9,7 +9,7 @@ flavor: implementation
owner: claude-code
topic_slug: netkingdom
created: "2026-10-08"
updated: "2026-10-09"
updated: "2026-10-10"
depends_on: []
related_repos:
- ops-mason
@ -324,7 +324,7 @@ the rationale. The type is `acknowledged`; it becomes `implemented` with T06.
id: NK-WP-0048-T06
status: wait
depends_on: [NK-WP-0048-T05, NK-WP-0048-T08, NK-WP-0048-T09, MASON-WP-0010-T03, WARDEN-WP-0044-T03]
blocking_reason: "Type 1.1, both light paths and the mint lane exist (RPF-WP-0054; CCR-2026-0040/0041/0043 applied). Waits on: CCR-2026-0042 consumer reader (in_flight, platform-owner review); the mint-secret run; ops-warden's run sheet (WARDEN-WP-0044-T03); then the founder's attended session (bind-env, ensure-groups, register-client with --check-config) in a quiet window."
blocking_reason: "Type1.2 architecture has a confirmed source-only founder acknowledgment; canonical1.1 remains unchanged/default and the1.2 reference case stays proposed. Needs explicit version selection/reference-source integration without normal admission bypass, closed owner adapters plus global/native receipt verifier (WARDEN-WP-0044-T03), independently verified six-object structural materialization and CCR42 claims/created-only provenance, exact broker/case/source reconciliation, then separately authorized native mint/delivery and attended registry/consumer verification. Source acknowledgment, a bundle or local tests do not prove implemented/materialized/live status."
priority: high
state_hub_task_id: "d9b26bcf-a7c6-59a2-92a0-f913d76a203c"
```
@ -500,3 +500,50 @@ and for confidential clients adds `deliver-secret` (delivery from custody into
the sso namespace) and `bind-env` (Deployment env), attended in the same session
as `register-client`. The per-client helpers stay until their clients are
adopted as cases.
2026-10-10 — NetKingdom owner review of the execution seam, source only:
ops-warden/docs/security-case-execution-proposal.md SHA256 78ab1439e4c5beb205aeccf15b1b2e706511be55ab195c5a3aa682f326c7c77c
was reviewed against INTENT, SecurityCase canon, acknowledged type1.1, current
case and owner source. docs/security-case-execution-owner-review.md supports
the closed adapter/receipt direction with explicit versioned schema, structural
materialization provenance, unchanged caller/session boundaries, safe CAS
reconciliation and exact-created-object rollback requirements. This is owner
review, not approval. Supporting file digests are in the adjacent sources JSON.
Current source exposes a circular wait: ops-mason T03 waits on mint while Warden
and the broker refuse a non-materialized case. Structural acceptance therefore
needs its own native pinned receipt before mint, not a successful mint before
materialized. The platform broker additionally pins type1.0 while Forgejo is
accepted at1.1; platform-owner alignment and tests are required, not an unchecked
version bypass. T06 remains wait. No case/type lifecycle status, grant, authority
or live runtime changed by this review. A proposed informed-decision would
adopt the source contract only; native materialization and execution acceptance
stay distinct.
Final proposal re-review: staged Warden proposal SHA256 78ab1439e4c5beb205aeccf15b1b2e706511be55ab195c5a3aa682f326c7c77c
adds only the explicitly local reducer appendix, not an accepted wire protocol
or executor. The exact-final review and sources JSON supersede the earlier
1035f049... proposal review. Platform staged the exact type1.1 broker correction
with ten fake-backend subprocess checks (script SHA256
9576cd211cfc06526ec4cc9bd0a5b06f0f59287a68931bb2d6e3592a951ddc7d).
The next source work is the versioned closed adapter/receipt/materialization
contract, not another relaxation of the broker's status gate. Native work still
requires installed broker provenance, structural reader receipts, exact new
materialized-case bytes, caller grant/session revocation and verified execution.
No installed/native acceptance is inferred from that staged correction.
2026-10-11 — new source-only type1.2 architecture acknowledgment:
Confirmed native founder ACCEPT of infd-20261011-forgejo-type12-source-r1@1
at06:47:39Z, approval8e9332c8-754a-420c-b8b7-445cb4fe6765. Exact frozen packet
0b377d647ca748cd03c92f9792396412048055d4bde9f7bb06ff6d413f7acd68 and submission
585cee731de30d2b37883a57abfd9eb32f023ee694e8d911989109d5caf80569; native receipt
retained in docs/evidence/2026-10-11-forgejo-type12-source-acknowledgment/.
The complete acknowledged1.2 source package is isolated under
security-case-type-revisions/1.2/oidc-browser-relying-party; default loader and
current accepted1.1 case remain untouched because load_type is single-version.
The new proposed1.2 case is NOT accepted/materialized/live and has no acceptance
fields. Actual reference-migration design approval is a separate Apps owner
receipt; no1.1 approval is inherited. Source-recording review/test proof and exact
next gates are in docs/forgejo-type12-source-acknowledgment-followthrough.md.
T06 remains wait and T07 remains its existing dependent task; type is NOT
implemented and no first-case/native grant or broader workplan finish is asserted.