@githolon/dsl 0.108.7 → 0.110.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/operation-contract.wasm +0 -0
- package/check_package.mjs +12 -15
- package/compile_package.mjs +17 -18
- package/compile_proof.mjs +16 -1
- package/dart/CHANGELOG.md +80 -1
- package/dart/README.md +25 -2
- package/dart/lib/src/admission_decision.dart +41 -0
- package/dart/lib/src/application_framework_calls.dart +52 -2
- package/dart/lib/src/application_model_adoption.dart +187 -0
- package/dart/lib/src/application_status.dart +73 -0
- package/dart/lib/src/console_enrolment.dart +271 -0
- package/dart/lib/src/console_http_io.dart +26 -0
- package/dart/lib/src/console_http_stub.dart +7 -0
- package/dart/lib/src/dev_cloud.dart +69 -22
- package/dart/lib/src/generated_call.dart +83 -23
- package/dart/lib/src/kernel_primitives.dart +119 -0
- package/dart/lib/src/nms_conformance_runtime.dart +1 -1
- package/dart/lib/src/nms_generated_runtime.dart +32 -10
- package/dart/lib/src/nms_test_environment.dart +1 -1
- package/dart/lib/src/node_runner_transport.dart +41 -46
- package/dart/lib/src/observed_session_directory.dart +70 -0
- package/dart/lib/src/operation_receipts.dart +112 -0
- package/dart/lib/src/peer_application_streams.dart +103 -0
- package/dart/lib/src/reception/dart_reception.dart +4280 -0
- package/dart/lib/src/reception/event_desk.dart +214 -0
- package/dart/lib/src/reception/extremum_read.dart +46 -0
- package/dart/lib/src/reception/local_copies.dart +371 -0
- package/dart/lib/src/reception/peer_office_connection.dart +11 -0
- package/dart/lib/src/reception/progress_desk.dart +268 -0
- package/dart/lib/src/reception/reception_contract.dart +11 -0
- package/dart/lib/src/reception/reception_session.dart +284 -0
- package/dart/lib/src/reception/sync_diagnostics.dart +26 -0
- package/dart/lib/src/reception/workspace_preparation_report.dart +126 -0
- package/dart/lib/src/replica_readiness.dart +123 -0
- package/dart/lib/src/runner/node-entry.mjs +23950 -15776
- package/dart/lib/src/runtime_v2_gateway.dart +56 -3
- package/dart/lib/src/runtime_v2_transport.dart +544 -3
- package/dart/lib/src/session_bound.dart +200 -311
- package/dart/lib/src/signing_identity_kernel.dart +84 -0
- package/dart/lib/src/sync_status_projection.dart +550 -0
- package/dart/lib/src/sync_status_reducer.dart +170 -0
- package/dart/lib/src/test_harness.dart +809 -1153
- package/dart/lib/src/testing/test_custody.dart +66 -0
- package/dart/lib/src/testing/test_peer.dart +328 -0
- package/dart/lib/src/typed_watch_registry.dart +169 -0
- package/dart/lib/src/workspace_open_progress.dart +27 -0
- package/dart/pubspec.lock +24 -1
- package/dart/pubspec.yaml +7 -2
- package/dart/pubspec_overrides.yaml +2 -0
- package/dart/test/admission_decision_test.dart +48 -0
- package/dart/test/background_model_adoption_test.dart +228 -0
- package/dart/test/bundle_version_pairing_test.dart +4 -4
- package/dart/test/child_authentication_repair_test.dart +359 -0
- package/dart/test/cloud_bound_local_shell_test.dart +119 -0
- package/dart/test/console_enrolment_refusal_test.dart +52 -0
- package/dart/test/console_enrolment_test.dart +227 -0
- package/dart/test/errors_test.dart +5 -5
- package/dart/test/event_plane_seam_test.dart +50 -164
- package/dart/test/extremum_read_test.dart +58 -0
- package/dart/test/fixtures/wedge/wedge-entry.mjs +3 -21
- package/dart/test/generated_query_test.dart +32 -0
- package/dart/test/harness_phase_timeout_test.dart +18 -23
- package/dart/test/kernel_author_after_read_test.dart +242 -0
- package/dart/test/kernel_fence_test.dart +137 -0
- package/dart/test/local_copies_test.dart +222 -0
- package/dart/test/model_adoption_test.dart +198 -0
- package/dart/test/node_peer_local_custody_test.dart +153 -0
- package/dart/test/offer_authentication_proof_test.dart +352 -52
- package/dart/test/operation_compatibility_test.dart +151 -0
- package/dart/test/platform_credential_effect_test.dart +386 -0
- package/dart/test/receiving_group_open_test.dart +213 -0
- package/dart/test/reception/workspace_preparation_report_test.dart +103 -0
- package/dart/test/reception_event_desk_close_test.dart +16 -0
- package/dart/test/reception_span_trace_test.dart +23 -0
- package/dart/test/replica_readiness_test.dart +156 -0
- package/dart/test/runtime_projections_test.dart +92 -0
- package/dart/test/runtime_v2_gateway_test.dart +131 -0
- package/dart/test/signing_identity_kernel_test.dart +75 -0
- package/dart/test/sync_status_preparation_report_test.dart +29 -0
- package/dart/test/sync_status_reducer_test.dart +419 -0
- package/dart/test/test_harness_test.dart +71 -95
- package/dart/test/typed_query_watch_test.dart +170 -0
- package/dart/test/typed_watch_registry_test.dart +249 -0
- package/dart_lints/README.md +18 -0
- package/dart_lints/lib/nomos_lints.dart +70 -0
- package/dart_lints/pubspec.lock +580 -0
- package/dart_lints/pubspec.yaml +12 -0
- package/dart_lints/test/reference_identity_test.dart +75 -0
- package/dart_types/CHANGELOG.md +18 -0
- package/dart_types/lib/nomos_kernel_protocol.dart +21 -1
- package/dart_types/lib/nomos_types.dart +9 -1
- package/dart_types/lib/src/admission_decision.dart +37 -0
- package/dart_types/lib/src/aggregate_meta.dart +1 -1
- package/dart_types/lib/src/approved_model.dart +65 -0
- package/dart_types/lib/src/custody.dart +10 -18
- package/dart_types/lib/src/error_info.dart +4 -4
- package/dart_types/lib/src/errors.dart +29 -29
- package/dart_types/lib/src/foreign_ref.dart +62 -33
- package/dart_types/lib/src/local_work_rejected.dart +3 -3
- package/dart_types/lib/src/nomos_ref.dart +3 -1
- package/dart_types/lib/src/principal.dart +2 -2
- package/dart_types/lib/src/proto/google/protobuf/any.pb.dart +163 -0
- package/dart_types/lib/src/proto/google/protobuf/any.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pb.dart +137 -0
- package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +20721 -10433
- package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +555 -27
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pb.dart +387 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pbenum.dart +46 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pb.dart +295 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pbenum.dart +139 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pb.dart +269 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pbenum.dart +103 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pb.dart +417 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pbenum.dart +62 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pb.dart +9968 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pbenum.dart +133 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pb.dart +204 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pbenum.dart +54 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pb.dart +1550 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pb.dart +710 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pb.dart +845 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pb.dart +198 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pb.dart +369 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pb.dart +609 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pbenum.dart +65 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pb.dart +358 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pbenum.dart +100 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pb.dart +2231 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pbenum.dart +271 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pb.dart +1286 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pb.dart +636 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pbenum.dart +116 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pb.dart +1637 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pbenum.dart +175 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pb.dart +1269 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pbenum.dart +129 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pb.dart +2782 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pbenum.dart +97 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +2232 -8627
- package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pbenum.dart +0 -358
- package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pb.dart +1639 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pbenum.dart +46 -0
- package/dart_types/lib/src/runtime_outcome.dart +133 -0
- package/dart_types/lib/src/subscriptions.dart +116 -23
- package/dart_types/pubspec.yaml +1 -1
- package/dart_types/test/extremum_subscriptions_test.dart +40 -0
- package/dart_types/test/foreign_ref_resolution_test.dart +75 -0
- package/dart_types/test/nomos_ref_address_test.dart +25 -0
- package/dart_types/test/ordered_subscriptions_test.dart +34 -0
- package/operation_contract_check.mjs +24 -0
- package/package.json +11 -6
- package/src/aggregate.ts +70 -10
- package/src/application_topology.ts +18 -11
- package/src/attested.ts +3 -0
- package/src/attested_core.ts +46 -3
- package/src/birth_meter_ensure.ts +19 -7
- package/src/births.ts +29 -4
- package/src/build_package.ts +140 -13
- package/src/business_birth.ts +181 -4
- package/src/codegen_call_proto.ts +1276 -0
- package/src/codegen_call_usda.ts +49 -6
- package/src/codegen_dart.ts +83 -44
- package/src/codegen_dart_client.ts +458 -800
- package/src/{codegen_dart_application.ts → codegen_dart_facade.ts} +331 -582
- package/src/codegen_dart_framework_calls.ts +320 -37
- package/src/codegen_dart_indexed_variant.ts +159 -0
- package/src/codegen_dart_scenario.ts +42 -13
- package/src/codegen_proof.ts +3 -3
- package/src/codegen_provider_dart.ts +5 -0
- package/src/codegen_query_proto.ts +158 -0
- package/src/codegen_refusal.ts +189 -0
- package/src/codegen_result_proto.ts +931 -0
- package/src/codegen_result_usda.ts +4 -0
- package/src/codegen_ts.ts +464 -616
- package/src/codegen_workspace_access.ts +105 -0
- package/src/compatibility_graph.ts +759 -0
- package/src/compatibility_usda.ts +264 -0
- package/src/compile_package_main.ts +2017 -1195
- package/src/custody_placement.ts +156 -0
- package/src/custody_placement_usda.ts +91 -0
- package/src/decl_shapes.ts +21 -2
- package/src/describe_model.ts +1 -0
- package/src/directive.ts +59 -2
- package/src/drivers.ts +51 -0
- package/src/engine_entry.ts +52 -8
- package/src/evolve_preview.ts +11 -4
- package/src/exists.ts +2 -0
- package/src/fields.ts +75 -11
- package/src/flow_gate.ts +2 -1
- package/src/framework/application_home.ts +170 -18
- package/src/framework/attested_receipts.ts +8 -3
- package/src/framework/auth_provider_law.ts +169 -9
- package/src/framework/birth_certificate_law.ts +4 -0
- package/src/framework/capability.ts +34 -3
- package/src/framework/child_authentication.ts +346 -0
- package/src/framework/console_governance.ts +295 -0
- package/src/framework/delegated_roles.ts +301 -0
- package/src/framework/domain_lifecycle.ts +26 -13
- package/src/framework/founding_genesis.ts +193 -0
- package/src/framework/framework_aggregates.ts +1 -1
- package/src/framework/genesis.ts +6 -1
- package/src/framework/governance_relations.ts +19 -0
- package/src/framework/home.ts +5 -734
- package/src/framework/legacy/child_auth_provider_epoch.ts +73 -0
- package/src/framework/model_authority_repair.ts +116 -0
- package/src/framework/model_authority_seed.ts +185 -0
- package/src/framework/model_transition.ts +211 -0
- package/src/framework/owned_custody.ts +1 -1
- package/src/framework/principal_enrollment.ts +302 -0
- package/src/framework/receiving_group.ts +857 -0
- package/src/framework/receiving_group_recovery.ts +314 -0
- package/src/framework/relations.ts +4 -8
- package/src/framework/signing_identity.ts +242 -95
- package/src/framework/source_roster.ts +11 -5
- package/src/framework/workspace_access.ts +149 -0
- package/src/framework/workspace_invariant.ts +73 -52
- package/src/framework/workspaces.ts +407 -40
- package/src/framework_call_definitions.ts +32 -3
- package/src/generated_client_bundle_boundary.ts +97 -0
- package/src/generated_client_names.ts +1 -0
- package/src/identity_usda.ts +27 -0
- package/src/index.ts +183 -12
- package/src/indexed_variant.ts +83 -0
- package/src/intent.ts +173 -45
- package/src/law_check.ts +8 -5
- package/src/law_dependency_index.ts +231 -0
- package/src/law_graph.ts +508 -71
- package/src/law_graph_usda.ts +170 -24
- package/src/law_identity.ts +119 -81
- package/src/law_source_map.ts +4 -1
- package/src/law_units.ts +498 -0
- package/src/law_value_type.ts +7 -3
- package/src/member_authentication.ts +302 -0
- package/src/null_meta.ts +1 -1
- package/src/openusd_compiled_layer.ts +132 -0
- package/src/operation_contract_check.ts +31 -0
- package/src/ordered_read.ts +2 -1
- package/src/package_config.ts +33 -12
- package/src/package_dependencies.ts +1 -0
- package/src/plan_source_slice.ts +30 -1
- package/src/protobuf_field_number.ts +36 -0
- package/src/provenance_wire.ts +6 -0
- package/src/query.ts +2 -1
- package/src/read.ts +50 -0
- package/src/relation.ts +4 -1
- package/src/relation_schema.ts +15 -2
- package/src/report.ts +2 -2
- package/src/sqlite_computation_bundle.ts +78 -0
- package/src/sqlite_computed.ts +102 -0
- package/src/sqlite_counts.ts +154 -0
- package/src/sqlite_layout.ts +823 -0
- package/src/sqlite_reads.ts +275 -0
- package/src/sqlite_samples.ts +185 -0
- package/src/stable_id_identity_bridge.ts +1 -1
- package/src/stable_ids_for_module.ts +16 -4
- package/src/test_call_usda.ts +6 -6
- package/src/usda_relationship_integrity.ts +20 -3
- package/src/usda_text.ts +21 -1
- package/src/value_object.ts +81 -11
- package/src/wire.ts +22 -0
- package/src/wire_encode.ts +227 -20
- package/src/workspace_sharding.ts +15 -6
- package/src/workspace_sharing.ts +51 -49
- package/src/zod_introspection.ts +2 -0
- package/compat_package.mjs +0 -46
- package/dart/lib/src/home.dart +0 -15
- package/dart/lib/src/runner/offline-install.mjs +0 -15367
- package/dart/lib/src/source_trust.dart +0 -51
- package/dart/lib/src/webview_bridge.dart +0 -6540
- package/dart/lib/src/workspace_name.dart +0 -30
- package/dart/test/acquire_session_credentials_test.dart +0 -150
- package/dart/test/acquire_session_test.dart +0 -534
- package/dart/test/adv_realm_interference_test.dart +0 -600
- package/dart/test/cloud_bound_topology_test.dart +0 -168
- package/dart/test/cluster_births_test.dart +0 -202
- package/dart/test/cluster_device_keyed_acceptance_test.dart +0 -105
- package/dart/test/cluster_local_autosync_test.dart +0 -123
- package/dart/test/cluster_scale_test.dart +0 -122
- package/dart/test/compat_test.dart +0 -61
- package/dart/test/dlq_session_surface_test.dart +0 -222
- package/dart/test/first_app_gauntlet_test.dart +0 -386
- package/dart/test/fixtures/wedge/fake-install.mjs +0 -11
- package/dart/test/four_layer_nested_topology_test.dart +0 -290
- package/dart/test/home_parity_test.dart +0 -13
- package/dart/test/local_sync_inert_test.dart +0 -107
- package/dart/test/node_runner_transport_test.dart +0 -78
- package/dart/test/parent_signer_recovery_test.dart +0 -155
- package/dart/test/residency_refusal_test.dart +0 -49
- package/dart/test/sealing_client_test.dart +0 -181
- package/dart/test/session_bound_test.dart +0 -285
- package/dart/test/stale_bundle_test.dart +0 -80
- package/dart/test/vo_read_typing_test.dart +0 -131
- package/dart/test/watch_after_offer_stall_test.dart +0 -100
- package/dart/test/webview_bridge_test.dart +0 -1930
- package/dart/test/workspace_name_test.dart +0 -24
- package/runtime/generated-application-host.js +0 -22860
- package/src/codegen_query_usda.ts +0 -214
- package/src/compat_manifest.ts +0 -26
- package/src/compat_package_main.ts +0 -224
- package/src/shape_compat.ts +0 -352
- package/src/usd_state.ts +0 -505
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
// NOMOS — Nomos Sovereign: participants act · verify · remember LOCALLY; hosted
|
|
2
|
+
// remotes are replaceable custody/transport, not truth. ⇒ ONE Nomos GitHolon
|
|
3
|
+
// wasm32-wasip1 artifact {kernel · projection · embedded QuickJS engine}.
|
|
4
|
+
// If a file isn't this / hosting this / authoring for this / proving this — it's gone.
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* framework/principal_enrollment.ts — how the FIRST key of a principal reaches the ledger
|
|
8
|
+
* (identity target model D22: the kernel is the authentication).
|
|
9
|
+
*
|
|
10
|
+
* `admit`'s whole authentication rule is: the signature verifies under key K, K is an active signer of
|
|
11
|
+
* the claimed principal P in parent state (`identity:P#signer@key:<sha256(K)>`, `signing_identity.ts`),
|
|
12
|
+
* and P's scope is the scope the directive's provider declares. A principal is `<scope>:<subject>`,
|
|
13
|
+
* exactly its Zanzibar subject. Its first signer tuple lands one of two ways:
|
|
14
|
+
*
|
|
15
|
+
* - **Enrolled scope.** A principal holding `principalScope:<scope>#enroller` (the tenant's backend, or
|
|
16
|
+
* the console hosting one) verified the provider's token OFF the ledger and writes
|
|
17
|
+
* {@link enrollDevice}. The enroller is recorded as the tuple's `grantedBy`; no token, issuer or
|
|
18
|
+
* `verifiedVia` provenance is law. {@link revokeDevice} is its mirror.
|
|
19
|
+
* - **Sovereign scope.** The principal is `<scope>:<sha256(root key)>` and certifies itself:
|
|
20
|
+
* {@link sovereignSelfCertification} writes the founding tuple, marked
|
|
21
|
+
* `nomos:selfCertifyingPrincipal = "true"` so the kernel admits it iff the signing key's sha256 is
|
|
22
|
+
* the principal's subject.
|
|
23
|
+
*
|
|
24
|
+
* Every further device, either scope, is proof of possession: an active signer of P writes
|
|
25
|
+
* `enrollSigner` for the new key. A principal always revokes its own keys with `revokeSigner`.
|
|
26
|
+
*
|
|
27
|
+
* `enroller` is a framework-global relation on the framework object type `principalScope`, granted and
|
|
28
|
+
* revoked by an admin (`grantEnroller`/`revokeEnroller`, `workspaces.ts`) and copied into a child at
|
|
29
|
+
* birth exactly like `operator` (D15/D18: `readInheritedEnrollers` → `buildGenesisChain`).
|
|
30
|
+
*/
|
|
31
|
+
import { z } from "zod";
|
|
32
|
+
import { directive, type RequirableDirective } from "../directive.js";
|
|
33
|
+
import { query } from "../query.js";
|
|
34
|
+
import { readFrameworkDeclaredRows } from "../read.js";
|
|
35
|
+
import { relationType, self, user, key } from "../relation_schema.js";
|
|
36
|
+
import { endorsementOf } from "../principal_evidence.js";
|
|
37
|
+
import {
|
|
38
|
+
authenticatesWith,
|
|
39
|
+
consolePrincipals,
|
|
40
|
+
CONSOLE_PRINCIPAL_SCOPE,
|
|
41
|
+
custodianPrincipals,
|
|
42
|
+
CUSTODIAN_PRINCIPAL_SCOPE,
|
|
43
|
+
isAuthenticationProvider,
|
|
44
|
+
principalScopeOf,
|
|
45
|
+
principalsOf,
|
|
46
|
+
RESERVED_PROVIDER_SCOPES,
|
|
47
|
+
type SovereignProviderRef,
|
|
48
|
+
} from "../member_authentication.js";
|
|
49
|
+
import { PRINCIPAL_SCOPE_ENROLLER_RELATION } from "./governance_relations.js";
|
|
50
|
+
import { RelationTuple, removeTuple, writeTuple } from "./relations.js";
|
|
51
|
+
import { signerObject, SIGNER_RELATION } from "./signing_identity.js";
|
|
52
|
+
|
|
53
|
+
/** The framework object type naming one provider scope: `principalScope:<scope>`. */
|
|
54
|
+
export const PRINCIPAL_SCOPE_OBJECT_TYPE = "principalScope" as const;
|
|
55
|
+
|
|
56
|
+
/** The Zanzibar object on which a scope's enrollers are seated. */
|
|
57
|
+
export function principalScopeObject(scope: string): string {
|
|
58
|
+
return `${PRINCIPAL_SCOPE_OBJECT_TYPE}:${requireProviderScope(scope)}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const scopePattern = /^[A-Za-z][A-Za-z0-9._-]{0,127}$/;
|
|
62
|
+
const sha256Hex = z.string().regex(/^[0-9a-f]{64}$/, "expected lowercase sha256 hex (a public key hash)");
|
|
63
|
+
|
|
64
|
+
function requireProviderScope(scope: string): string {
|
|
65
|
+
if (typeof scope !== "string" || !scopePattern.test(scope) || RESERVED_PROVIDER_SCOPES.includes(scope)) {
|
|
66
|
+
throw new Error(`'${String(scope)}' is not a provider scope`);
|
|
67
|
+
}
|
|
68
|
+
return scope;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** A provider scope in a payload: bounded, and never a framework subject type. */
|
|
72
|
+
export const providerScopeField = z
|
|
73
|
+
.string()
|
|
74
|
+
.regex(scopePattern, "a provider scope is a bounded identifier")
|
|
75
|
+
.refine((scope) => !RESERVED_PROVIDER_SCOPES.includes(scope), "a reserved scope names no principals");
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The framework governance relations' subject classes (`workspace:self#operator`,
|
|
79
|
+
* `principalScope:<s>#enroller`): `user:` and `key:`, the console's enrolled principals
|
|
80
|
+
* (`console:<subject>`), and the framework's sovereign custodian principals (`custodian:<keyhash>`, the
|
|
81
|
+
* founding admin of a root born by token-free genesis). The framework cannot name a tenant's scopes — law
|
|
82
|
+
* is installed per domain (D21) and the framework's unit is composed with every tenant's — so the only
|
|
83
|
+
* provider scopes its own relations admit are the two the framework itself declares: the console's,
|
|
84
|
+
* whose principals are the operators who install law and the hosted enrollers that act for tenants
|
|
85
|
+
* (D18, D22), and the custodians'. Leaf-only: never a userset or wildcard.
|
|
86
|
+
*/
|
|
87
|
+
export const GOVERNANCE_SUBJECTS = Object.freeze([
|
|
88
|
+
user(),
|
|
89
|
+
key(),
|
|
90
|
+
principalsOf(consolePrincipals),
|
|
91
|
+
// Token-free genesis (D22): a root's founding admin is a sovereign custodian principal, and it is the
|
|
92
|
+
// root's first enroller and operator, so the framework's governance relations must admit it.
|
|
93
|
+
principalsOf(custodianPrincipals),
|
|
94
|
+
]);
|
|
95
|
+
|
|
96
|
+
/** The Zanzibar subject classes {@link GOVERNANCE_SUBJECTS} admits, as a predicate over one subject. */
|
|
97
|
+
export function isGovernanceSubject(subject: string): boolean {
|
|
98
|
+
if (/^user:.+/.test(subject)) return true;
|
|
99
|
+
if (/^key:[0-9a-f]{64}$/.test(subject)) return true;
|
|
100
|
+
const scope = principalScopeOf(subject);
|
|
101
|
+
return scope === CONSOLE_PRINCIPAL_SCOPE || scope === CUSTODIAN_PRINCIPAL_SCOPE;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** `principalScope:<scope>#enroller` — see {@link PRINCIPAL_SCOPE_ENROLLER_RELATION}. */
|
|
105
|
+
export const principalScopeRelations = relationType(PRINCIPAL_SCOPE_OBJECT_TYPE)
|
|
106
|
+
// GLOBAL, like `workspace` and `identity`: the object is addressed by its bare type on every door.
|
|
107
|
+
.asGlobal()
|
|
108
|
+
.relation(PRINCIPAL_SCOPE_ENROLLER_RELATION, { rewrite: self(), allow: [...GOVERNANCE_SUBJECTS] });
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* A governance grant names its subject exactly one way: a device key (`keyHash` → `key:<hash>`), a
|
|
112
|
+
* legacy user (`principal` → `user:<uid>`), or a console principal (`consolePrincipal`, the full
|
|
113
|
+
* `console:<subject>`).
|
|
114
|
+
*/
|
|
115
|
+
export const governanceSubjectFields = {
|
|
116
|
+
keyHash: sha256Hex.optional(),
|
|
117
|
+
principal: z.string().min(1).optional(),
|
|
118
|
+
consolePrincipal: z
|
|
119
|
+
.string()
|
|
120
|
+
.refine((value) => principalScopeOf(value) === CONSOLE_PRINCIPAL_SCOPE, "a console principal is console:<subject>")
|
|
121
|
+
.optional(),
|
|
122
|
+
} as const;
|
|
123
|
+
|
|
124
|
+
type GovernanceSubjectPayload = {
|
|
125
|
+
keyHash?: string | undefined;
|
|
126
|
+
principal?: string | undefined;
|
|
127
|
+
consolePrincipal?: string | undefined;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
/** Exactly one subject form is present. */
|
|
131
|
+
export function hasOneGovernanceSubject(payload: GovernanceSubjectPayload): boolean {
|
|
132
|
+
return [payload.keyHash, payload.principal, payload.consolePrincipal].filter((value) => !!value).length === 1;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** The Zanzibar subject a governance grant names. Refuses anything but exactly one well-formed form. */
|
|
136
|
+
export function governanceSubject(payload: GovernanceSubjectPayload): string {
|
|
137
|
+
if (!hasOneGovernanceSubject(payload)) {
|
|
138
|
+
throw new Error("a governance grant names exactly one of keyHash, principal or consolePrincipal");
|
|
139
|
+
}
|
|
140
|
+
if (payload.principal) return `user:${payload.principal}`;
|
|
141
|
+
if (payload.consolePrincipal) {
|
|
142
|
+
if (principalScopeOf(payload.consolePrincipal) !== CONSOLE_PRINCIPAL_SCOPE) {
|
|
143
|
+
throw new Error("a console principal is console:<subject>");
|
|
144
|
+
}
|
|
145
|
+
return payload.consolePrincipal;
|
|
146
|
+
}
|
|
147
|
+
if (!/^[0-9a-f]{64}$/.test(payload.keyHash ?? "")) throw new Error("keyHash is a lowercase sha256 hex");
|
|
148
|
+
return `key:${payload.keyHash}`;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** The payload that names `subject` again — the inverse of {@link governanceSubject}, for birth seeding. */
|
|
152
|
+
export function governanceSubjectPayload(subject: string): GovernanceSubjectPayload {
|
|
153
|
+
if (subject.startsWith("user:")) return { principal: subject.slice("user:".length) };
|
|
154
|
+
if (subject.startsWith("key:")) return { keyHash: subject.slice("key:".length) };
|
|
155
|
+
if (principalScopeOf(subject) === CONSOLE_PRINCIPAL_SCOPE) return { consolePrincipal: subject };
|
|
156
|
+
throw new Error(`'${subject}' is not a governance subject`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function requirePrincipalOfScope(principal: string, scope: string): void {
|
|
160
|
+
if (principalScopeOf(principal) !== requireProviderScope(scope)) {
|
|
161
|
+
throw new Error(`principal-not-in-scope: '${principal}' is not a '${scope}:<subject>' principal`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const enrollmentPayload = z
|
|
166
|
+
.object({
|
|
167
|
+
/** The principal's scope. The enroller is checked on `principalScope:<scope>`, so the plan refuses
|
|
168
|
+
* a principal outside it: an enroller of one scope can never mint another scope's principal. */
|
|
169
|
+
scope: providerScopeField,
|
|
170
|
+
principal: z.string().min(1),
|
|
171
|
+
/** sha256 hex of the device's Ed25519 public key. */
|
|
172
|
+
keyHash: sha256Hex,
|
|
173
|
+
})
|
|
174
|
+
.strict()
|
|
175
|
+
.refine((p) => principalScopeOf(p.principal) === p.scope, {
|
|
176
|
+
message: "principal must be <scope>:<subject> of the named scope",
|
|
177
|
+
path: ["principal"],
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* `enrollDevice { scope, principal, keyHash }` — an enroller of `scope` writes
|
|
182
|
+
* `identity:<principal>#signer@key:<keyHash>`: the device-bound session of an enrolled scope. The enroller
|
|
183
|
+
* verified the provider's ID token off the ledger (its OIDC `nonce` must be `keyHash`, and it is
|
|
184
|
+
* accepted once), so nothing of the provider lands here. `grantedBy` records the enroller.
|
|
185
|
+
*/
|
|
186
|
+
export const enrollDevice = directive("enrollDevice")
|
|
187
|
+
.ensures(RelationTuple)
|
|
188
|
+
.payload(enrollmentPayload)
|
|
189
|
+
.plan((p, ctx) => {
|
|
190
|
+
requirePrincipalOfScope(p.principal, p.scope);
|
|
191
|
+
return writeTuple({
|
|
192
|
+
object: signerObject(p.principal),
|
|
193
|
+
relation: SIGNER_RELATION,
|
|
194
|
+
subject: `key:${p.keyHash}`,
|
|
195
|
+
grantedBy: ctx.principal().asAttribution(),
|
|
196
|
+
grantedAt: String(ctx.clock().physical),
|
|
197
|
+
});
|
|
198
|
+
})
|
|
199
|
+
.requires(PRINCIPAL_SCOPE_ENROLLER_RELATION, {
|
|
200
|
+
objectFrom: { recordType: PRINCIPAL_SCOPE_OBJECT_TYPE, idField: "scope" },
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* `revokeDevice { scope, principal, keyHash }` — an enroller of `scope` revokes one key of one of its
|
|
205
|
+
* scope's principals (remove-wins; later writes by that key are refused at their position). A principal
|
|
206
|
+
* always revokes its own keys itself with `revokeSigner`.
|
|
207
|
+
*/
|
|
208
|
+
export const revokeDevice = directive("revokeDevice")
|
|
209
|
+
.ensures(RelationTuple)
|
|
210
|
+
.payload(enrollmentPayload)
|
|
211
|
+
.plan((p, ctx) => {
|
|
212
|
+
requirePrincipalOfScope(p.principal, p.scope);
|
|
213
|
+
const at = String(ctx.clock().physical);
|
|
214
|
+
return removeTuple({
|
|
215
|
+
object: signerObject(p.principal),
|
|
216
|
+
relation: SIGNER_RELATION,
|
|
217
|
+
subject: `key:${p.keyHash}`,
|
|
218
|
+
grantedBy: ctx.principal().asAttribution(),
|
|
219
|
+
grantedAt: at,
|
|
220
|
+
revokedBy: ctx.principal().asAttribution(),
|
|
221
|
+
revokedAt: at,
|
|
222
|
+
});
|
|
223
|
+
})
|
|
224
|
+
.requires(PRINCIPAL_SCOPE_ENROLLER_RELATION, {
|
|
225
|
+
objectFrom: { recordType: PRINCIPAL_SCOPE_OBJECT_TYPE, idField: "scope" },
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* The founding signer of a SOVEREIGN principal, certified by its own root key (D22). The directive
|
|
230
|
+
* authenticates with `provider`, so the kernel's ordinary rule already pins the captured principal to
|
|
231
|
+
* that sovereign scope; the `nomos:selfCertifyingPrincipal` marker adds the one self-certification
|
|
232
|
+
* rule — the signing key's sha256 is the principal's subject, and needs no prior signer — and the plan
|
|
233
|
+
* refuses any `keyHash` that is not that subject. The tuple it writes is
|
|
234
|
+
* `identity:<scope>:<keyHash>#signer@key:<keyHash>`.
|
|
235
|
+
*
|
|
236
|
+
* One directive per sovereign scope; `id` defaults to `certifySovereignPrincipal`.
|
|
237
|
+
*/
|
|
238
|
+
export function sovereignSelfCertification(
|
|
239
|
+
provider: SovereignProviderRef,
|
|
240
|
+
id = "certifySovereignPrincipal",
|
|
241
|
+
): RequirableDirective<{ keyHash: string }> {
|
|
242
|
+
if (!isAuthenticationProvider(provider) || provider.kind !== "sovereign") {
|
|
243
|
+
throw new Error("sovereignSelfCertification takes a sovereign provider declared with authenticationProvider");
|
|
244
|
+
}
|
|
245
|
+
const scope = provider.scope;
|
|
246
|
+
return authenticatesWith(
|
|
247
|
+
directive(id)
|
|
248
|
+
.ensures(RelationTuple)
|
|
249
|
+
.payload(z.object({ keyHash: sha256Hex }).strict())
|
|
250
|
+
.plan((p, ctx) => {
|
|
251
|
+
const me = ctx.principal().asAuthoritySubject<string>("certify my sovereign identity with its own root key");
|
|
252
|
+
const principal = endorsementOf(me)?.principal ?? "";
|
|
253
|
+
if (principal !== `${scope}:${p.keyHash}`) {
|
|
254
|
+
throw new Error("sovereign-principal-is-its-root-key-hash");
|
|
255
|
+
}
|
|
256
|
+
return writeTuple({
|
|
257
|
+
object: signerObject(principal),
|
|
258
|
+
relation: SIGNER_RELATION,
|
|
259
|
+
subject: `key:${p.keyHash}`,
|
|
260
|
+
grantedBy: ctx.principal().asAttribution(),
|
|
261
|
+
grantedAt: String(ctx.clock().physical),
|
|
262
|
+
});
|
|
263
|
+
})
|
|
264
|
+
.selfCertifyingPrincipal(),
|
|
265
|
+
provider,
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/** Every tuple of one relation name, across objects — the enroller seeding read. */
|
|
270
|
+
export const relationTuplesByRelation = query("relationTuplesByRelation")
|
|
271
|
+
.key("relation")
|
|
272
|
+
.returns(RelationTuple);
|
|
273
|
+
|
|
274
|
+
/** One inherited enroller grant: the scope and the subject holding it. */
|
|
275
|
+
export interface InheritedEnroller {
|
|
276
|
+
readonly scope: string;
|
|
277
|
+
readonly subject: string;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* ENROLLER INHERITANCE (D22, as D15 for `operator`): the parent's CURRENT active
|
|
282
|
+
* `principalScope:<scope>#enroller` tuples, read by the birthing plan and seated on the child by one
|
|
283
|
+
* `grantEnroller` genesis step each — copied once at birth, never a live dependency on the parent.
|
|
284
|
+
* Sorted by (scope, subject) so the recipe is a pure function of the tuple set.
|
|
285
|
+
*/
|
|
286
|
+
export function readInheritedEnrollers(): readonly InheritedEnroller[] {
|
|
287
|
+
const rows = readFrameworkDeclaredRows(relationTuplesByRelation, RelationTuple, {
|
|
288
|
+
relation: PRINCIPAL_SCOPE_ENROLLER_RELATION,
|
|
289
|
+
});
|
|
290
|
+
const prefix = `${PRINCIPAL_SCOPE_OBJECT_TYPE}:`;
|
|
291
|
+
const out: InheritedEnroller[] = [];
|
|
292
|
+
for (const row of rows) {
|
|
293
|
+
if (row.relation !== PRINCIPAL_SCOPE_ENROLLER_RELATION || !row.object?.startsWith(prefix)) continue;
|
|
294
|
+
const scope = row.object.slice(prefix.length);
|
|
295
|
+
const subjects = row.subjects as Record<string, { status?: string }> | undefined;
|
|
296
|
+
for (const [subject, leaf] of Object.entries(subjects ?? {})) {
|
|
297
|
+
if (leaf?.status === "active") out.push({ scope, subject });
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return out.sort((a, b) =>
|
|
301
|
+
a.scope < b.scope ? -1 : a.scope > b.scope ? 1 : a.subject < b.subject ? -1 : a.subject > b.subject ? 1 : 0);
|
|
302
|
+
}
|