diff --git a/identity-and-access/module.json b/identity-and-access/module.json index 20e2d2c..4f3b3f3 100644 --- a/identity-and-access/module.json +++ b/identity-and-access/module.json @@ -23,6 +23,16 @@ "series": "0.1", "generated-from": "." }, + { + "name": "go-meshgrants", + "kind": "package", + "language": "go", + "paths": [ + "go/seats/meshgrants" + ], + "series": "0.1", + "generated-from": "." + }, { "name": "go-meshvaultclient", "kind": "package", @@ -60,6 +70,16 @@ ], "series": "0.1", "generated-from": "." + }, + { + "name": "ts-meshgrants", + "kind": "package", + "language": "typescript", + "paths": [ + "ts/seats/meshgrants" + ], + "series": "0.1", + "generated-from": "." } ] }, diff --git a/identity-and-access/seats/index.json b/identity-and-access/seats/index.json index 72e28e3..c8222f2 100644 --- a/identity-and-access/seats/index.json +++ b/identity-and-access/seats/index.json @@ -1,6 +1,7 @@ { "format": 1, "seats": [ + "mesh-grants", "mesh-node-enroller", "mesh-vault", "node-secret-service" diff --git a/identity-and-access/seats/mesh-grants/fixtures/events.json b/identity-and-access/seats/mesh-grants/fixtures/events.json new file mode 100644 index 0000000..6e72de6 --- /dev/null +++ b/identity-and-access/seats/mesh-grants/fixtures/events.json @@ -0,0 +1,56 @@ +[ + { + "name": "a granting wait held", + "of": "event:wait-held", + "subject": "mesh.seat.mesh-grants.event.wait-held", + "given": { + "step": "grant", + "part": "mesh-grants", + "version": "src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "module": "mesh-tools", + "fp": "src2:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "since": "2026-11-09T21:00:00Z", + "bound": "10m", + "clock-from": "2026-11-09T20:55:00Z" + } + }, + { + "name": "a granting wait released", + "of": "event:wait-ended", + "subject": "mesh.seat.mesh-grants.event.wait-ended", + "given": { + "step": "grant", + "part": "mesh-grants", + "version": "src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "module": "mesh-tools", + "fp": "src2:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "since": "2026-11-09T21:00:00Z", + "bound": "10m", + "how": "released", + "by": "jochen: the new grants part is stuck", + "clock-from": "2026-11-09T20:55:00Z" + } + }, + { + "name": "filling is said past 80 %", + "of": "event:filling", + "subject": "mesh.seat.mesh-grants.event.filling", + "given": { + "store": "SEAT_mesh-pipeline-runner_pipeline-ended", + "bytes": 161061273, + "cap": 201326592, + "at": "2026-11-11T09:00:00Z" + } + }, + { + "name": "room is said below 70 %", + "of": "event:room", + "subject": "mesh.seat.mesh-grants.event.room", + "given": { + "store": "SEAT_mesh-pipeline-runner_pipeline-ended", + "bytes": 100663296, + "cap": 201326592, + "at": "2026-11-11T10:00:00Z" + } + } +] diff --git a/identity-and-access/seats/mesh-grants/fixtures/verbs.json b/identity-and-access/seats/mesh-grants/fixtures/verbs.json new file mode 100644 index 0000000..e2bd9f1 --- /dev/null +++ b/identity-and-access/seats/mesh-grants/fixtures/verbs.json @@ -0,0 +1,28 @@ +[ + { + "name": "grants-for answers the grants a candidate adds", + "of": "verb:grants-for.answer", + "given": { + "modules": [ + { + "module": "mesh-tools", + "added": [ + { + "subject": "mesh.seat.node-engine.verb.manifest-reads", + "verb": "manifest-reads" + } + ], + "removed": [] + } + ] + } + }, + { + "name": "grants-for asks a source revision on a branch", + "of": "verb:grants-for.input", + "given": { + "source": "a1b2c3d4", + "branch": "main" + } + } +] diff --git a/identity-and-access/seats/mesh-grants/seat.json b/identity-and-access/seats/mesh-grants/seat.json new file mode 100644 index 0000000..8fdb2ca --- /dev/null +++ b/identity-and-access/seats/mesh-grants/seat.json @@ -0,0 +1,222 @@ +{ + "format": 1, + "seat": "mesh-grants", + "scope": "mesh", + "grain": "whole", + "domain": "Identity and access", + "decision": "novox/hq ADR 0656, ADR 0547, ADR 0636", + "description": "Who may say what on the bus: the grants part composes each module's membership, its buckets, logs and streams, the bus's user list and grants (design 47 'The grants part'). An acting part of the step grant (ADR 0656 1): an entry whose grant waits for its new version is held on its running build within the bound, said by wait-held and wait-ended; a store passing 80 % of its cap is said by filling, and back below 70 % by room; grants-for answers the grants a candidate would compose (design 47 G 331, 441).", + "acts": [ + { + "step": "grant", + "on": "every" + } + ], + "verbs": [ + { + "name": "grants-for", + "description": "The grants a candidate would compose, per module: the grants it would add and remove against the branch's newest, each named by its subject and verb. The candidate's catalog half is taken by mesh-catalog's revision (design 47 G 441).", + "class": "read", + "input": { + "type": "object", + "properties": { + "source": { + "type": "string", + "description": "the candidate's source revision" + }, + "run": { + "type": "string", + "description": "or the id of a run" + }, + "branch": { + "type": "string", + "description": "its watched branch" + } + }, + "required": [ + "branch" + ], + "additionalProperties": false + }, + "answer": { + "$ref": "#/defs/GrantsFor" + } + } + ], + "events": [ + { + "name": "wait-held", + "body": { + "$ref": "#/defs/Wait" + } + }, + { + "name": "wait-ended", + "body": { + "$ref": "#/defs/Wait" + } + }, + { + "name": "filling", + "body": { + "$ref": "#/defs/Fill" + } + }, + { + "name": "room", + "body": { + "$ref": "#/defs/Fill" + } + } + ], + "family": { + "name": "mesh-grants.events", + "max-age-days": 7 + }, + "defs": { + "Wait": { + "type": "object", + "description": "a granting wait the grants part holds: an entry whose grant waits until the grants part's new version runs (design 47 *Each step's wait is its own part's*)", + "properties": { + "step": { + "type": "string", + "description": "the step, grant", + "enum": [ + "grant" + ] + }, + "part": { + "type": "string", + "description": "the acting part waited for" + }, + "version": { + "type": "string", + "description": "its new version's fingerprint" + }, + "module": { + "type": "string", + "description": "the entry that waits" + }, + "fp": { + "type": "string", + "description": "the entry's fingerprint, whose grant waits" + }, + "since": { + "type": "string", + "format": "date-time" + }, + "bound": { + "type": "string", + "description": "a duration such as 10m" + }, + "how": { + "type": "string", + "description": "on wait-ended: ran or released", + "enum": [ + "ran", + "released" + ] + }, + "by": { + "type": "string", + "description": "on a release, who released it and why" + }, + "clock-from": { + "type": "string", + "format": "date-time", + "description": "when the new version's build was done, as the builder's build.ended says; the bound's clock starts there (design 47 G 266)" + } + }, + "required": [ + "step", + "part", + "version", + "module", + "since", + "bound", + "clock-from" + ] + }, + "Fill": { + "type": "object", + "description": "a store's fill against its cap", + "properties": { + "store": { + "type": "string", + "description": "the store" + }, + "bytes": { + "type": "integer" + }, + "cap": { + "type": "integer", + "description": "bytes" + }, + "at": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "store", + "bytes", + "cap" + ] + }, + "Grant": { + "type": "object", + "properties": { + "subject": { + "type": "string", + "description": "the bus subject" + }, + "verb": { + "type": "string", + "description": "the verb or event the grant is for" + } + }, + "required": [ + "subject", + "verb" + ] + }, + "GrantsFor": { + "type": "object", + "description": "the grants a candidate would compose, per module, added and removed against the branch's newest", + "properties": { + "modules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "module": { + "type": "string" + }, + "added": { + "type": "array", + "items": { + "$ref": "#/defs/Grant" + } + }, + "removed": { + "type": "array", + "items": { + "$ref": "#/defs/Grant" + } + } + }, + "required": [ + "module", + "added", + "removed" + ] + } + }, + "error": { + "type": "string", + "description": "why it could not be answered: the catalog half of the candidate is not held" + } + } + } + } +} diff --git a/identity-and-access/seats/mesh-vault/seat.json b/identity-and-access/seats/mesh-vault/seat.json index 749f148..7c93f1b 100644 --- a/identity-and-access/seats/mesh-vault/seat.json +++ b/identity-and-access/seats/mesh-vault/seat.json @@ -597,9 +597,7 @@ "name": "retire", "optional": true, "description": "Retire one module's own secret, by node, module and name, on the operator's warrant bound to exactly those three (design 32 *A value no longer read*). Emits own-retired.", - "callers": [ - "seat:mesh-config" - ], + "callers": "the holder of the seat mesh-config alone", "input": { "type": "object", "properties": {