From a92feddce9c61c69d104fcc4f19f75a9345282f5 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 13 Jul 2026 01:51:35 +0100 Subject: [PATCH] Type secret policy closure semantics --- epiphany-core/src/bin/epiphany-work.rs | 281 ++++++++++++++---- ...onceptual-substitution-audit-2026-07-12.md | 11 + notes/fresh-workspace-handoff.md | 3 + state/ledgers.msgpack | Bin 457859 -> 458287 bytes state/map.yaml | 2 +- 5 files changed, 244 insertions(+), 53 deletions(-) diff --git a/epiphany-core/src/bin/epiphany-work.rs b/epiphany-core/src/bin/epiphany-work.rs index 31f2e4d8..14269d47 100644 --- a/epiphany-core/src/bin/epiphany-work.rs +++ b/epiphany-core/src/bin/epiphany-work.rs @@ -8637,107 +8637,77 @@ fn closure_family_assertions( ); } "repo.secret_policy_request" => { + let parsed = parse_repo_secret_policy_request(&content); + let request = parsed.as_ref().ok(); + push_assertion( + &mut assertions, + "secret-policy-request-typed-toml", + parsed.is_ok(), + match parsed.as_ref() { + Ok(_) => "Committed secret policy request parses as typed TOML.".to_string(), + Err(error) => { + format!("Committed secret policy request parse failed: {error:#}") + } + }, + ); push_assertion( &mut assertions, "secret-policy-request-schema-present", - content.contains("schema_version = \"epiphany.repo_secret_policy_request.v0\""), + request.is_some_and(RepoSecretPolicyRequest::has_canonical_identity), "Committed secret policy request carries the schema version.".to_string(), ); push_assertion( &mut assertions, "secret-policy-request-family-present", - content.contains("safe_action_family = \"repo.secret_policy_request\""), + request.is_some_and(RepoSecretPolicyRequest::has_canonical_identity), "Committed secret policy request carries the safe action family.".to_string(), ); push_assertion( &mut assertions, "secret-policy-request-summary-present", - content.contains(&compact_summary), + request.is_some_and(|request| request.summary == compact_summary), "Committed secret policy request contains the accepted pressure summary." .to_string(), ); push_assertion( &mut assertions, "secret-policy-request-awaits-review", - content.contains("[request]") - && content.contains("status = \"awaiting-security-review\"") - && content.contains("requested_owner = \"Maintainer/Soul/Bifrost\"") - && content.contains( - "requested_effect = \"review-repo-secret-and-write-permission-policy\"", - ) - && content.contains("requires_secret_inventory_without_values = true") - && content.contains("requires_write_permission_scope = true") - && content.contains("requires_public_private_export_boundary = true"), + request.is_some_and(RepoSecretPolicyRequest::awaits_security_review), "Committed secret policy request waits for security review before consequence." .to_string(), ); push_assertion( &mut assertions, "secret-policy-request-antecedents-present", - content.contains("[antecedents]") - && content.contains("source_grounding_required = true") - && content.contains("soul_review_required = true") - && content.contains("mind_adoption_required = true") - && content.contains("maintainer_review_required = true") - && content.contains("bifrost_publication_review_required = true"), + request.is_some_and(RepoSecretPolicyRequest::has_review_antecedents), "Committed secret policy request requires source grounding, Soul, Mind, maintainer, and Bifrost review antecedents." .to_string(), ); push_assertion( &mut assertions, "secret-policy-request-receipt-contract", - content.contains("[required_receipts]") - && content.contains("source_grounding = \"epiphany.eyes.evidence_packet\"") - && content.contains( - "soul_review = \"epiphany.repo_work_closure_review.v0\"", - ) - && content.contains( - "mind_adoption = \"epiphany.repo_work_mind_adoption_decision.v0\"", - ) - && content.contains( - "maintainer_review = \"gamecult.maintainer.review_receipt.v0\"", - ) - && content.contains( - "bifrost_publication_review = \"gamecult.bifrost.publication_review_receipt.v0\"", - ), + request.is_some_and(RepoSecretPolicyRequest::has_receipt_contract), "Committed secret policy request names Eyes, Soul, Mind, maintainer, and Bifrost review receipts." .to_string(), ); push_assertion( &mut assertions, "secret-policy-request-packet-contract", - content.contains("[security_packet]") - && content.contains("requires_secret_locations_without_values = true") - && content.contains("requires_credential_owner = true") - && content.contains("requires_write_scope_matrix = true") - && content.contains("requires_public_export_redaction_rules = true") - && content.contains("requires_deployment_authority_owner = true") - && content.contains("requires_incident_rollback_plan = true"), + request.is_some_and(RepoSecretPolicyRequest::has_security_packet_contract), "Committed secret policy request names secret-location, credential-owner, write-scope, export, deployment, and rollback requirements." .to_string(), ); push_assertion( &mut assertions, "secret-policy-request-authority-seals", - content.contains("[authority]") - && content.contains("direct_secret_access_authority = false") - && content.contains("secret_value_materialization = false") - && content.contains("write_permission_authority = false") - && content.contains("deployment_authority = false") - && content.contains("publication_authorized = false") - && content.contains("merge_authorized = false") - && content.contains("service_lifecycle_authority = false") - && content.contains("cross_body_mutation_authorized = false") - && content.contains("private_verse_rummaging = false") - && content - .contains("maintainer_or_soul_security_authority_required = true"), + request.is_some_and(RepoSecretPolicyRequest::has_authority_seals), "Committed secret policy request denies secret/write/deployment/publication/service/cross-body authority." .to_string(), ); push_assertion( &mut assertions, "secret-policy-request-private-seal", - content.contains("private_state_exposed = false"), + request.is_some_and(|request| !request.private_state_exposed), "Committed secret policy request preserves the private-state seal.".to_string(), ); } @@ -12342,6 +12312,135 @@ fn parse_repo_deployment_config(text: &str) -> Result { toml::from_str(text).context("deployment config is not valid typed TOML") } +#[derive(Debug, Deserialize)] +struct RepoSecretPolicyRequest { + schema_version: String, + safe_action_family: String, + summary: String, + private_state_exposed: bool, + request: RepoSecretPolicyRequestBody, + antecedents: RepoSecretPolicyAntecedents, + required_receipts: RepoSecretPolicyReceipts, + security_packet: RepoSecretPolicyPacket, + authority: RepoSecretPolicyAuthority, +} + +#[derive(Debug, Deserialize)] +struct RepoSecretPolicyRequestBody { + status: String, + requested_owner: String, + requested_effect: String, + requires_secret_inventory_without_values: bool, + requires_write_permission_scope: bool, + requires_public_private_export_boundary: bool, +} + +#[derive(Debug, Deserialize)] +struct RepoSecretPolicyAntecedents { + source_grounding_required: bool, + soul_review_required: bool, + mind_adoption_required: bool, + maintainer_review_required: bool, + bifrost_publication_review_required: bool, +} + +#[derive(Debug, Deserialize)] +struct RepoSecretPolicyReceipts { + source_grounding: String, + soul_review: String, + mind_adoption: String, + maintainer_review: String, + bifrost_publication_review: String, +} + +#[derive(Debug, Deserialize)] +struct RepoSecretPolicyPacket { + requires_secret_locations_without_values: bool, + requires_credential_owner: bool, + requires_write_scope_matrix: bool, + requires_public_export_redaction_rules: bool, + requires_deployment_authority_owner: bool, + requires_incident_rollback_plan: bool, +} + +#[derive(Debug, Deserialize)] +struct RepoSecretPolicyAuthority { + direct_secret_access_authority: bool, + secret_value_materialization: bool, + write_permission_authority: bool, + deployment_authority: bool, + publication_authorized: bool, + merge_authorized: bool, + service_lifecycle_authority: bool, + cross_body_mutation_authorized: bool, + private_verse_rummaging: bool, + maintainer_or_soul_security_authority_required: bool, +} + +impl RepoSecretPolicyRequest { + fn has_canonical_identity(&self) -> bool { + self.schema_version == "epiphany.repo_secret_policy_request.v0" + && self.safe_action_family == "repo.secret_policy_request" + } + + fn awaits_security_review(&self) -> bool { + let request = &self.request; + request.status == "awaiting-security-review" + && request.requested_owner == "Maintainer/Soul/Bifrost" + && request.requested_effect == "review-repo-secret-and-write-permission-policy" + && request.requires_secret_inventory_without_values + && request.requires_write_permission_scope + && request.requires_public_private_export_boundary + } + + fn has_review_antecedents(&self) -> bool { + let antecedents = &self.antecedents; + antecedents.source_grounding_required + && antecedents.soul_review_required + && antecedents.mind_adoption_required + && antecedents.maintainer_review_required + && antecedents.bifrost_publication_review_required + } + + fn has_receipt_contract(&self) -> bool { + let receipts = &self.required_receipts; + receipts.source_grounding == "epiphany.eyes.evidence_packet" + && receipts.soul_review == "epiphany.repo_work_closure_review.v0" + && receipts.mind_adoption == "epiphany.repo_work_mind_adoption_decision.v0" + && receipts.maintainer_review == "gamecult.maintainer.review_receipt.v0" + && receipts.bifrost_publication_review + == "gamecult.bifrost.publication_review_receipt.v0" + } + + fn has_security_packet_contract(&self) -> bool { + let packet = &self.security_packet; + packet.requires_secret_locations_without_values + && packet.requires_credential_owner + && packet.requires_write_scope_matrix + && packet.requires_public_export_redaction_rules + && packet.requires_deployment_authority_owner + && packet.requires_incident_rollback_plan + } + + fn has_authority_seals(&self) -> bool { + let authority = &self.authority; + !authority.direct_secret_access_authority + && !authority.secret_value_materialization + && !authority.write_permission_authority + && !authority.deployment_authority + && !authority.publication_authorized + && !authority.merge_authorized + && !authority.service_lifecycle_authority + && !authority.cross_body_mutation_authorized + && !authority.private_verse_rummaging + && authority.maintainer_or_soul_security_authority_required + } +} + +fn parse_repo_secret_policy_request(text: &str) -> Result { + toml::from_str(text).context("secret policy request is not valid typed TOML") +} + fn run_deployment_config_audit(args: DeploymentConfigAuditArgs) -> Result { let workspace = args .workspace @@ -15517,6 +15616,84 @@ idunn_deployment_authority_required = true assert!(!branch.contains("content.contains")); } + fn secret_policy_fixture() -> String { + r#" +schema_version = "epiphany.repo_secret_policy_request.v0" +safe_action_family = "repo.secret_policy_request" +summary = "test summary" +private_state_exposed = false + +[request] +status = "awaiting-security-review" +requested_owner = "Maintainer/Soul/Bifrost" +requested_effect = "review-repo-secret-and-write-permission-policy" +requires_secret_inventory_without_values = true +requires_write_permission_scope = true +requires_public_private_export_boundary = true + +[antecedents] +source_grounding_required = true +soul_review_required = true +mind_adoption_required = true +maintainer_review_required = true +bifrost_publication_review_required = true + +[required_receipts] +source_grounding = "epiphany.eyes.evidence_packet" +soul_review = "epiphany.repo_work_closure_review.v0" +mind_adoption = "epiphany.repo_work_mind_adoption_decision.v0" +maintainer_review = "gamecult.maintainer.review_receipt.v0" +bifrost_publication_review = "gamecult.bifrost.publication_review_receipt.v0" + +[security_packet] +requires_secret_locations_without_values = true +requires_credential_owner = true +requires_write_scope_matrix = true +requires_public_export_redaction_rules = true +requires_deployment_authority_owner = true +requires_incident_rollback_plan = true + +[authority] +direct_secret_access_authority = false +secret_value_materialization = false +write_permission_authority = false +deployment_authority = false +publication_authorized = false +merge_authorized = false +service_lifecycle_authority = false +cross_body_mutation_authorized = false +private_verse_rummaging = false +maintainer_or_soul_security_authority_required = true +"# + .to_string() + } + + #[test] + fn secret_policy_closure_refuses_comment_authority_seals() { + let valid = parse_repo_secret_policy_request(&secret_policy_fixture()).unwrap(); + assert!(valid.has_authority_seals()); + + let counterfeit = secret_policy_fixture().replace( + "direct_secret_access_authority = false", + "# direct_secret_access_authority = false\ndirect_secret_access_authority = true", + ); + let parsed = parse_repo_secret_policy_request(&counterfeit).unwrap(); + assert!(parsed.authority.direct_secret_access_authority); + assert!(!parsed.has_authority_seals()); + + let source = include_str!("epiphany-work.rs"); + let start = source + .find("\"repo.secret_policy_request\" => {") + .expect("secret policy closure branch"); + let end = source[start..] + .find("\n \"repo.dependency_policy_request\" => {") + .map(|offset| start + offset) + .expect("end of secret policy closure branch"); + let branch = &source[start..end]; + assert!(branch.contains("parse_repo_secret_policy_request")); + assert!(!branch.contains("content.contains")); + } + #[test] fn queue_selection_rows_preserve_typed_scheduler_state() { let overview = EpiphanyCultMeshRepoWorkOverviewEntry { diff --git a/notes/conceptual-substitution-audit-2026-07-12.md b/notes/conceptual-substitution-audit-2026-07-12.md index 0d11452b..ec7a6997 100644 --- a/notes/conceptual-substitution-audit-2026-07-12.md +++ b/notes/conceptual-substitution-audit-2026-07-12.md @@ -735,6 +735,17 @@ summary equality. Closure cannot bless a config that only mentions the desired values in comments or unrelated tables, and no deployment closure branch uses `content.contains` as authority. +## Secret-policy prose substituted for security authority + +`repo.secret_policy_request` closure used substring checks for secret-access, +write-permission, deployment, publication, service, cross-body, and private +Verse denials. A comment containing the desired `false` line could coexist with +an actual `true` authority value and still satisfy closure. The family now has +a typed TOML model for request scope, antecedents, receipt contracts, security +packet, and authority seals. Closure requires semantic predicates and exact +accepted-summary equality; the branch contains no substring authority. A +commented denial cannot conceal granted secret access. + ## Unresolved: provider receipts without chronology Bifrost body-change/GitHub publication receipts are externally owned and their diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index e5f826a4..50c02e0f 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -185,6 +185,9 @@ The confirmed conceptual substitutions have been cut: longer substitute for valid deployment configuration. - Repo-work deployment closure uses that same typed model and semantic predicates; the duplicate substring validator is deleted. +- Secret-policy request closure parses typed TOML and validates request, + antecedent, receipt, security-packet, and authority semantics. Comment prose + cannot counterfeit secret/write/deployment denials. - Bifrost provider receipt contracts still lack provider timestamp/revision. Do not invent consumer-side ordering; repair that in a Bifrost-owned schema. diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index 15f0117ef55076e500777d89d95165d09b6158fa..1b9ca9a793f940a8575c4bde2b77cf086b027730 100644 GIT binary patch delta 394 zcmXv~Jxjwt7&g&n(ZNlj%L}g6&_WlT6$HgWad5j_UfZL|-Syr}Yd~=5;4dio843>0 zE{?8(tGlC6KfpHuhlhjb?)kdeqJ8(%zTXU1``z7M@8WqW`dxe23dTXOKbwcQ^Dto4 z=Q3l3(R!SR(Z{0t{)*Paez$shkJ>kH!SyLhhko0dOvw@)jte9YGBZ>-gn}>yDiZQe z=>f5k%pKh6N?0sFlbP z+JQq4+DyR;M@ZmH%YkPn$44M^3KNm3l$G>fti!ZNiLCe3VOFBDT-RvtgsdsCH+IQX+BL10$Os NNlGh-D)AY0{{RcClr8`O delta 57 zcmZ4gN4oi^^acq=ZWD7W1GA`O3~av>HY+n0GBUa}Pi1PK%ESo7AetG7S%8>z`&1^j GcRv9&0TV_5 diff --git a/state/map.yaml b/state/map.yaml index 6eda71ac..3f60b95a 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -660,4 +660,4 @@ current_status: - Service lifecycle receipt history is now event-only: `load_epiphany_cultmesh_daemon_service_lifecycle_receipts` filters out the `epiphany-local/daemon-service-lifecycle-receipt/latest` mirror, while `load_latest_epiphany_cultmesh_daemon_service_lifecycle_receipt` remains the latest-state reader. Focused unit test `service_lifecycle_receipt_history_excludes_latest_mirror` proves two per-receipt writes return exactly two history records and latest points at the second. Fresh smoke `verse-query-lifecycle-history-filter-smoke` and live overview/triage `local-20260618-145632-497-efac6f0d` / `local-20260618-145632-321-867947af` prove compact swarm sights still expose service lifecycle attention plus the present elevated runbook artifact without daemon pokes or service mutation. Do not use a broad unscoped cargo test filter for this check on Windows; it fans out across bin harnesses and hit a broken pipe during this pass. - `epiphany-verse-query seed-compact` is the compact seed receipt for wrappers and read-only rites. The older `seed` command still prints the full local Verse context for explicit debugging, but compact wrapper modes now avoid full `seed`/final `query` readback after the combined overview proof exposed Windows debug stack overflow from full-context serialization pressure. last_completed_repo_swarm_cut: Huginn live-fire has crossed the first real repo Body from Persona pressure to branch-local Hands commit and Soul/Mind closure, and now has repeatable closure and redacted-public-proof mouths. On `E:\Projects\Huginn` branch `epiphany/huginn/first-awakening`, `tools/epiphany_local_run.ps1 -Mode repo-persona-intake` accepted item `huginn-inspection-readback-livefire`, Weksa/Persona intake remained sealed, and `epiphany-work derive-plan` lowered it to model-authored safe family `repo.status_section` for `README.md` only. `tools/epiphany_local_run.ps1 -Mode repo-swarm-run` advanced four bounded pulses: run-from-plan, adopt-from-plan, execute-from-plan, and close-from-execute. Huginn commit `e9b07c38fceabbdc89ea35c2156326c80c0393a2` updated only `README.md`; closure receipt `.epiphany\work\work-close-huginn-inspection-readback-livefire.json` records status `closed`, Soul verdict `passed`, Mind state commit `repo-work-close-huginn-inspection-readback-livefire-mind-commit`, safe family `repo.status_section`, path scope `README.md`, Bifrost publication gate, and `privateStateExposed=false`. Verification also ran Huginn's TypeScript compiler through concrete Node path: `C:\Program Files\nodejs\node.exe E:\Projects\Huginn\node_modules\typescript\bin\tsc -p tsconfig.json` passed. Native verifier `epiphany-repo-livefire-closure-smoke --workspace E:\Projects\Huginn --item huginn-inspection-readback-livefire --expected-path README.md --expected-family repo.status_section --expected-gate awaiting-publication --expected-blocker bifrost-publication-missing` checks closure receipt, Mind map entry, overview gate/blocker, authority seals, and `git show` changed paths, returning `status=ok`, `soulVerdict=passed`, `publicationGate=Bifrost`, and `privateStateExposed=false`. Wrapper `tools/epiphany_local_run.ps1 -Mode repo-livefire-closure -Workspace E:\Projects\Huginn -RepoWorkItem huginn-inspection-readback-livefire -SkipBuild` exposes the same read-only proof through the local operator mouth; artifact `local-20260621-190156-803-2f85ba15` printed commit, path, gate, blocker, Soul verdict, Mind commit receipt, and `privateStateExposed=False` without push, merge, publication, or target mutation. New wrapper `tools/epiphany_local_run.ps1 -Mode repo-work-public-proof -Workspace E:\Projects\Huginn -RepoWorkItem huginn-inspection-readback-livefire -SkipBuild` exports the redacted proof bundle and repo-local Verse index without publishing; artifact `local-20260621-190645-345-4555b1dc` wrote `.epiphany\public\proof-bundles\repo-work-public-proof-huginn-inspection-readback-livefire.json`, proof id `repo-work-public-proof-huginn-inspection-readback-livefire`, SHA-256 `857545b199f3e37eb06c2e757e5cfc201958e46667bb1f8403fd333a22620f63`, nine artifact rows, zero publication rows, and `privateStateExposed=False`. swarm overview readback `local-20260621-190701-140-b9519ec6` sees the `REPO-WORK-PUBLIC-PROOF` row and action row from Huginn's repo-local Verse with the same SHA-256 while Bifrost publication remains missing. Launcher compact modes are now named compact operator-context modes instead of read-only modes, and `bifrost-public-proof` summaries print item, target public Verse, room, proof SHA-256, review receipts, and credit receipts so publication receipts are auditable without claiming upstream sync. - next_action: Continue the conceptual-substitution modeling pass beyond receipt writers. Operational/evidence/self-state and operator surfaces with owned clocks are event-time ordered; operator receipts bind intents by run identity rather than global chronology; Eve/tool/Bifrost/collaboration projections join chains only by typed identity; repo-work scheduling and service-runbook selection use typed rows/IDs rather than reparsed presentation prose; deployment operational audit, runbook, and closure share typed TOML semantics; writerless readiness-review is deleted. Bifrost provider receipts still need provider-owned chronology, and artifact/metrics receipts need explicit repo-work request identity; accounting refuses closure until those contracts exist. Continue auditing remaining closure validators, evidence/security mirrors, service configuration claims, adapters, and destructive path consumers for borrowed authority. + next_action: Continue the conceptual-substitution modeling pass beyond receipt writers. Operational/evidence/self-state and operator surfaces with owned clocks are event-time ordered; operator receipts bind intents by run identity rather than global chronology; Eve/tool/Bifrost/collaboration projections join chains only by typed identity; repo-work scheduling and service-runbook selection use typed rows/IDs rather than reparsed presentation prose; deployment and secret-policy closure use typed TOML semantics; writerless readiness-review is deleted. Bifrost provider receipts still need provider-owned chronology, and artifact/metrics receipts need explicit repo-work request identity; accounting refuses closure until those contracts exist. Continue converting remaining authority-bearing closure validators, then audit evidence/security mirrors, service configuration claims, adapters, and destructive path consumers for borrowed authority.