Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
27083eb
mtcollins1_boot: WIF-trusted recurring effect through the auth patter…
Sep 23, 2026
f5d09c9
Regenerate fleet-converge.yml from its authority; job-roster witness …
Sep 23, 2026
d80596b
Merge origin/main into session/proud-dove-705
Sep 23, 2026
398612d
Review 5286225278: five walls for the mtcollins1 boot
Sep 23, 2026
78121fd
Forged-proof probe witness: class-scoped harness control (the hold mo…
Sep 23, 2026
54038e9
Merge origin/main into session/proud-dove-705
Sep 23, 2026
186f2cf
Standing ruling confirmed by the operator's stored approval (review 7…
Sep 23, 2026
6c2e45c
Floor cost: claims read their interface; standing ruling: SHA-256 dig…
Sep 23, 2026
96690ff
Merge origin/main into session/proud-dove-705
Sep 23, 2026
1ce25ec
Standing ruling: one derived value for both destructive roots; inject…
Sep 23, 2026
37ea4c8
Unit hold owner is a declared sum; release outcome is typed (review 7…
Sep 23, 2026
1a75fea
Ruling witness: supply digests at the interface; cite an existing int…
Sep 23, 2026
1cf802b
One inhabitance claim runs the real standing-ruling digest; admitted …
Sep 23, 2026
545fc90
Ruling-digest cost: its own one-member drop; App Attest drop restored…
Sep 23, 2026
10a2bc8
Cost-admission prose: the Mt. Collins row gets its own list and parag…
Sep 23, 2026
3c7c346
Merge origin/main into session/proud-dove-705 (re-queue after failed_…
Sep 23, 2026
65e1552
Merge origin/main (0095b486bbb) into session/proud-dove-705
Sep 23, 2026
7c788e4
Merge origin/main (ee04f784624) into session/proud-dove-705; split th…
Sep 23, 2026
e642cc7
Merge origin/main (cc90b751bb7) into session/proud-dove-705; delete t…
Sep 24, 2026
e508593
Merge origin/main (b3f9d33319c, includes #12189) into session/proud-d…
Sep 24, 2026
6514b68
Merge origin/main (8197ed5cae4) into session/proud-dove-705
Sep 24, 2026
ab70f23
Merge origin/main (318345ec761) into session/proud-dove-705; port #12…
Sep 24, 2026
ba326f0
Merge origin/main (1eda053f5f2) into session/proud-dove-705; boot-job…
Sep 24, 2026
e5e2681
Merge origin/main (eea7e8ea865) into session/proud-dove-705; regenera…
Sep 24, 2026
9c103af
mtcollins1 boot: refuse a dispatch naming another host instead of ski…
Sep 24, 2026
854fe12
Merge origin/main (59aaecbe519, includes #12222) into session/proud-d…
Sep 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 129 additions & 49 deletions .github/workflows/fleet-converge.yml

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions dag/extdeps/cloud/gcp/gcp.dag
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,35 @@ type WifProvider {
attribute_condition: String?
}

// THE WIRE SHAPES A READ OF A POOL AND ITS PROVIDERS RETURNS (cloud.google.com/iam/docs/reference/rest,
// projects.locations.workloadIdentityPools get and .providers list, read 2026-09-23). A provisioning
// run that finds a pool, provider or account already present must READ what is there before it
// grants anything through it; these are what it reads. Names are the full resource names the service
// answers in; state is ACTIVE or DELETED.
type WifOidcWire {
issuer_uri: String
}

type WifProviderWire {
name: String
disabled: Bool?
state: String?
attribute_mapping: Map<String, String>?
attribute_condition: String?
oidc: WifOidcWire?
}

type WifPoolWire {
name: String
display_name: String?
disabled: Bool?
state: String?
}

type WifProviderListWire {
workload_identity_pool_providers: List<WifProviderWire>?
}

fn wif_pool_resource(project_number: String, pool_id: String) -> String {
concat(
concat(concat("projects/", project_number), "/locations/global/workloadIdentityPools/"),
Expand Down
46 changes: 44 additions & 2 deletions dag/extdeps/cloud/gcp/iam_admin.dag
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ module extdeps.cloud.gcp.iam_admin

import extdeps.external_authority { ExternalAuthority }
import extdeps.uri { Uri, Https }
import extdeps.cloud.gcp.gcp { GcpProjectId, ServiceAccountEmail }
import extdeps.cloud.gcp.gcp { GcpProjectId, ServiceAccountEmail, WifPoolWire, WifProviderWire, WifProviderListWire }
import extdeps.cloud.gcp.iam { GcpPolicy, GcpBinding }
import std.types { Int, List, Map, NonEmptyStr, Secret, String }
import std.types { Bool, Int, List, Map, NonEmptyStr, Secret, String }
import extdeps.transports.rest { RestOutcome }
import v2.std.network { POST }
import extdeps.transports.rest { RestOutcome }
Expand Down Expand Up @@ -54,6 +54,11 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority {
// goes through. The WRITE carries the same optionality for the same reason and one nobody had hit:
// setIamPolicy returns the policy it stored, so revoking the LAST binding answers with an etag alone.
// Rostered as gunbc.recurring_failure_mode required_output_field_absent_for_an_empty_upstream_resource.
// ListWorkloadIdentityPoolProviders READS THE WHOLE PROVIDER POPULATION OF ONE POOL, deleted ones
// included: a soft-deleted provider can be undeleted into the pool within its retention window, so a
// classification that could not see it would call a pool single-provider while a second admission
// rule waits one call away. GetWorkloadIdentityPool and it are what a provisioning run reads before
// it writes anything through an existing pool (gunbc.auth.heal_publisher_provision).
service gcp.IamAdmin {
config {
endpoint: "https://iam.googleapis.com"
Expand Down Expand Up @@ -217,4 +222,41 @@ service gcp.IamAdmin {
5xx => GcpErrorShape
}
}

operation GetWorkloadIdentityPool {
input { access_token: Secret, project_id: GcpProjectId, pool_id: NonEmptyStr }
output { pool_name: String from "name", display_name: String?, disabled: Bool?, state: String?, outcome: RestOutcome }
readonly
transport rest {
method: GET,
path: "/v1/projects/\{project_id\}/locations/global/workloadIdentityPools/\{pool_id\}"
}
response {
200 => WifPoolWire
401 => GcpErrorShape
403 => GcpErrorShape
404 => GcpErrorShape
429 => GcpErrorShape
5xx => GcpErrorShape
}
}

operation ListWorkloadIdentityPoolProviders {
input { access_token: Secret, project_id: GcpProjectId, pool_id: NonEmptyStr }
output { providers: List<WifProviderWire>? from "workloadIdentityPoolProviders", outcome: RestOutcome }
readonly
transport rest {
method: GET,
path: "/v1/projects/\{project_id\}/locations/global/workloadIdentityPools/\{pool_id\}/providers",
query: { showDeleted: true }
}
response {
200 => WifProviderListWire
401 => GcpErrorShape
403 => GcpErrorShape
404 => GcpErrorShape
429 => GcpErrorShape
5xx => GcpErrorShape
}
}
}
5 changes: 5 additions & 0 deletions dag/extdeps/github/actions.dag
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,15 @@ type WorkflowSecret {
scope: SecretScope
}

// `environment` is the job's deployment environment (docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idenvironment,
// read 2026-09-23). It is a real job key with a security consequence: a job that names one carries it
// in its OIDC token as the `environment` claim and its `sub` becomes
// repo:<owner>/<repo>:environment:<name>, so a federation can pin one job by it.
type Job {
id: String
name: String?
runner: RunnerSpec
environment: String?
steps: List<Step>
needs: List<String>

Expand Down
19 changes: 11 additions & 8 deletions dag/extdeps/languages/yaml/gha_workflow.dag
Original file line number Diff line number Diff line change
Expand Up @@ -456,20 +456,23 @@ fn job_yaml(job: Job) -> YamlValue {
concat(
optional_string_list_kv(key: "needs", items: job.needs),
concat(
optional_int_kv(key: "timeout-minutes", value: job.timeout_minutes),
optional_string_kv(key: "environment", value: job.environment),
concat(
optional_string_kv(key: "if", value: job.if_condition),
optional_int_kv(key: "timeout-minutes", value: job.timeout_minutes),
concat(
optional_job_permissions_kv(perms: job.permissions),
optional_string_kv(key: "if", value: job.if_condition),
concat(
optional_job_concurrency_kv(spec: job.concurrency),
optional_job_permissions_kv(perms: job.permissions),
concat(
optional_job_outputs_kv(entries: job.outputs),
optional_job_concurrency_kv(spec: job.concurrency),
concat(
[kv(key: "steps", value: steps_yaml(steps: job.steps))],
optional_job_outputs_kv(entries: job.outputs),
concat(
optional_env_mapping(entries: job.env),
optional_bool_kv(key: "continue-on-error", value: job.continue_on_error)
[kv(key: "steps", value: steps_yaml(steps: job.steps))],
concat(
optional_env_mapping(entries: job.env),
optional_bool_kv(key: "continue-on-error", value: job.continue_on_error)
)
)
)
)
Expand Down
1 change: 1 addition & 0 deletions dag/gunbc/assimilate/bmc_token_federation.dag
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ fn bmc_token_smoke_job() -> Job {
id: "bmc_token_smoke",
name: none,
runner: gunbc_ci_runner_spec(),
environment: none,
steps: [bmc_checkout_step(), gcp_wif_auth_step(), gcp_token_smoke_step()],
needs: [],
env: none,
Expand Down
56 changes: 52 additions & 4 deletions dag/gunbc/auth/authorization_pattern_selection.dag
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,36 @@ type BillingConsequence
= BillsExternally
| NoBillingConsequence

// A STANDING AUTHORIZATION FOR A RECURRING DESTRUCTIVE EFFECT (operator ruling 2026-09-23, the Mt.
// Collins boot; side-chat review 5286225278 on gunbc#12101). An irreversible effect owes a human
// witness; a RECURRING one must run unattended; the two together select nothing (NoAdmissiblePattern),
// and relabelling the effect reversible to escape that is the fabricated input the review refused.
// The honest third reading is that the operator has witnessed the CLASS once, ahead of every
// instance, and made that consent conditional on a durable physical-safety interlock the run must
// observe released. That is what this carries: who ruled, when, over which effect, and the interlock
// the consent is conditional on. It discharges ONLY the irreversibility ground of the witness
// obligation -- a wide credential, a third-party bill or a break-glass effect is still witnessed per
// instance.
//
// THIS RECORD IS NOT THE CONSENT, AND IT MUST NAME WHAT IS (review 70369). A row in the corpus is
// author-written, so it cannot attest that the operator agreed (DESIGN §5: approval is external to
// the diff). confirmation_read names the effectful read that finds the operator's stored approval of
// the ruling's exact words; the site's realization must require its result before any write, so a
// forged row yields a selection but no effect. What the census checks statically is only that the
// interlock and the confirmation route are named against the site
// (gunbc.auth.privileged_effect_census rulings_without_a_rostered_interlock); the attestation itself
// is the operator's tap, read at run time.
type StandingDestructiveAuthorization {
ruling_text: NonEmptyStr
effect_subject: NonEmptyStr
interlock: DeclarationRef
confirmation_read: DeclarationRef
}

type WitnessDischarge
= NoWitnessDischarge
| StandingRulingUnderInterlock { ruling: StandingDestructiveAuthorization }

type PrivilegedEffect {
subject: NonEmptyStr
frequency: HumanInterventionFrequency
Expand All @@ -99,6 +129,7 @@ type PrivilegedEffect {
workload_identity: WorkloadIdentityStanding
minted_reach: MintedCredentialReach
billing: BillingConsequence
witness_discharge: WitnessDischarge
}

// ── Two obligations DERIVED from the characteristics, never accepted as input ─────────────────
Expand All @@ -109,8 +140,12 @@ type PrivilegedEffect {
// file, and §5 says a check that can be satisfied by editing the declaration while the realization
// still lies was validation standing where construction was available.
fn witness_required(e: PrivilegedEffect) -> Bool {
let irreversible = match e.reversibility {
IrreversibleEffect { what_is_lost: _ } => true
let irreversible_undischarged = match e.reversibility {
IrreversibleEffect { what_is_lost: _ } =>
match e.witness_discharge {
NoWitnessDischarge => true
StandingRulingUnderInterlock { ruling: _ } => false
}
ReversibleByReapply => false
}
let wide = match e.minted_reach {
Expand All @@ -129,7 +164,7 @@ fn witness_required(e: PrivilegedEffect) -> Bool {
DeviceOnce => false
EveryProvision => false
}
irreversible || wide || bills || break_glass
irreversible_undischarged || wide || bills || break_glass
}

// AN EFFECT PAID ON EVERY PROVISION MUST RUN UNATTENDED. There is no human at the end of a cron, and
Expand Down Expand Up @@ -438,6 +473,7 @@ data id_param_surface: DeclarationRef = decl_ref(module_path: "gunbc.auth.author
data id_param_workload_identity: DeclarationRef = decl_ref(module_path: "gunbc.auth.authorization_pattern_selection", decl_name: "param_workload_identity")
data id_param_minted_reach: DeclarationRef = decl_ref(module_path: "gunbc.auth.authorization_pattern_selection", decl_name: "param_minted_reach")
data id_param_billing: DeclarationRef = decl_ref(module_path: "gunbc.auth.authorization_pattern_selection", decl_name: "param_billing")
data id_param_witness_discharge: DeclarationRef = decl_ref(module_path: "gunbc.auth.authorization_pattern_selection", decl_name: "param_witness_discharge")

data var_authorization_pattern: DecisionVariable = DecisionVariable { identity: id_var_pattern }

Expand Down Expand Up @@ -467,9 +503,10 @@ data param_surface: ContextParameter = ContextParameter { identity: id_param_sur
data param_workload_identity: ContextParameter = ContextParameter { identity: id_param_workload_identity }
data param_minted_reach: ContextParameter = ContextParameter { identity: id_param_minted_reach }
data param_billing: ContextParameter = ContextParameter { identity: id_param_billing }
data param_witness_discharge: ContextParameter = ContextParameter { identity: id_param_witness_discharge }

fn context_parameters() -> List<ContextParameter> {
[param_frequency, param_reversibility, param_surface, param_workload_identity, param_minted_reach, param_billing]
[param_frequency, param_reversibility, param_surface, param_workload_identity, param_minted_reach, param_billing, param_witness_discharge]
}

fn frequency_text(f: HumanInterventionFrequency) -> String {
Expand Down Expand Up @@ -511,6 +548,16 @@ fn minted_reach_text(m: MintedCredentialReach) -> String {
}
}

// THE RULING IS QUOTED WITH ITS AUTHOR, DATE AND INTERLOCK, so a receipt minted under a standing
// authorization is a different decision scope from one minted without it.
fn witness_discharge_text(d: WitnessDischarge) -> String {
match d {
NoWitnessDischarge => "NoWitnessDischarge"
StandingRulingUnderInterlock { ruling: r } =>
join(["StandingRulingUnderInterlock: confirmed by ", declaration_ref_display_key(ref: r.confirmation_read), " under ", declaration_ref_display_key(ref: r.interlock), "; ruling ", r.ruling_text as String], "")
}
}

fn billing_text(b: BillingConsequence) -> String {
match b {
BillsExternally => "BillsExternally"
Expand All @@ -528,6 +575,7 @@ fn parameter_dispositions(e: PrivilegedEffect) -> List<ParameterDisposition> {
ParameterBound { parameter: id_param_workload_identity, evidence: workload_identity_text(w: e.workload_identity) as NonEmptyStr },
ParameterBound { parameter: id_param_minted_reach, evidence: minted_reach_text(m: e.minted_reach) as NonEmptyStr },
ParameterBound { parameter: id_param_billing, evidence: billing_text(b: e.billing) as NonEmptyStr },
ParameterBound { parameter: id_param_witness_discharge, evidence: witness_discharge_text(d: e.witness_discharge) as NonEmptyStr },
]
}

Expand Down
Loading