diff --git a/examples/README.md b/examples/README.md index 3db9854..f91cf85 100644 --- a/examples/README.md +++ b/examples/README.md @@ -77,16 +77,28 @@ These examples illustrate artifact-versus-baseline evaluation using existing Sou --- +## Recent additions — Release and build lifecycle examples + +These examples illustrate the release/build lifecycle schemas added in this slice: + +| File | Schema type | Description | +|------|------------|-------------| +| `release_set.json` | ReleaseSet | Assigned M2 demo release set with source Git ref, target, profile refs, and boot artifact refs | +| `fingerprint.json` | Fingerprint | Post-apply device observation proving the realized state matches the assigned release set | +| `config_source.json` | ConfigSource | Git-backed configuration source pinned to a specific commit, consumed by NLBoot/sourceos-boot | +| `token_door.json` | TokenDoor | One-time recovery-access token door bound to the M2 demo device and release set | +| `git_ref_build.json` | GitRefBuild | Build record linking the main-branch Git commit to OCI and ostree output artifacts | + +--- + ## Recent additions — Control-plane lifecycle and boot provisioning examples These examples illustrate the local-first control-plane lifecycle and secure boot/recovery family: | File | Schema type | Description | |------|------------|-------------| -| `release_set.json` | ReleaseSet | Assigned M2 demo release set with source Git ref, target, profile refs, and boot artifact refs | | `boot_release_set.json` | BootReleaseSet | SourceOS Recovery Environment boot artifact set linked to the assigned ReleaseSet | | `enrollment_token.json` | EnrollmentToken | One-time recovery authorization token scoped to the M2 demo device and BootReleaseSet | -| `fingerprint.json` | Fingerprint | Post-apply device observation proving the realized state matches the assigned release set | --- diff --git a/examples/config_source.json b/examples/config_source.json new file mode 100644 index 0000000..b953bf6 --- /dev/null +++ b/examples/config_source.json @@ -0,0 +1,15 @@ +{ + "id": "urn:srcos:config-source:sourceos-main-boot-config-2026-04-26", + "type": "ConfigSource", + "specVersion": "2.0.0", + "sourceKind": "git", + "uri": "https://github.com/SourceOS-Linux/sourceos-boot-config", + "gitRef": "refs/heads/main", + "gitCommit": "9f49e42af46d84c189b6313f5c8962c6ecd5076b", + "contentHash": "sha256:4e2b2e2c6a843f8b8cf38f7b47c8f875f1f9e4c4206e1f8e9c9f0ec9a0f7a001", + "inlineContent": null, + "authRef": null, + "status": "active", + "createdAt": "2026-04-26T14:00:00Z", + "notes": "Primary boot configuration source for SourceOS M2 demo, pinned to the main branch at the demo commit." +} diff --git a/examples/fingerprint.json b/examples/fingerprint.json index c80bc53..9c8e296 100644 --- a/examples/fingerprint.json +++ b/examples/fingerprint.json @@ -1,25 +1,26 @@ { - "fingerprint_id": "urn:srcos:fingerprint:m2-local-demo-2026-04-26T1418Z", + "id": "urn:srcos:fingerprint:m2-local-demo-2026-04-26T1418Z", + "type": "Fingerprint", + "specVersion": "2.0.0", "subject": { - "kind": "device", - "id": "urn:srcos:device:m2-local-demo" + "subjectKind": "device", + "subjectRef": "urn:srcos:asset:m2-local-demo" }, - "release_set_ref": "urn:srcos:release-set:m2-demo-2026-04-26", - "experience_profile_ref": "urn:srcos:experience-profile:mac-like-gnome-demo", - "isolation_profile_ref": "urn:srcos:isolation-profile:standard-container-demo", - "observed_at": "2026-04-26T14:18:00Z", + "releaseSetRef": "urn:srcos:release-set:m2-demo-2026-04-26", + "experienceProfileRef": "urn:srcos:experience-profile:mac-like-gnome-demo", + "isolationProfileRef": "urn:srcos:isolation-profile:standard-container-demo", + "observedAt": "2026-04-26T14:18:00Z", "integrity": { - "boot_release_set_ref": "urn:srcos:boot-release-set:m2-demo-recovery-2026-04-26", - "image_ref": "oci://registry.example.invalid/sourceos/m2-system@sha256:8b3f06c9090ccf926fe6ddc6f3b4f49a13d4b8bb4cb4f5cf78e2d12e31b55aa1", - "store_closure_hash": "sha256-4e2b2e2c6a843f8b8cf38f7b47c8f875f1f9e4c4206e1f8e9c9f0ec9a0f7a001", - "boot_entry_label": "SourceOS Recovery Demo" + "bootReleaseSetRef": "urn:srcos:boot-release-set:m2-demo-recovery-2026-04-26", + "imageRef": "oci://registry.example.invalid/sourceos/m2-system@sha256:8b3f06c9090ccf926fe6ddc6f3b4f49a13d4b8bb4cb4f5cf78e2d12e31b55aa1", + "storeClosureHash": "sha256-4e2b2e2c6a843f8b8cf38f7b47c8f875f1f9e4c4206e1f8e9c9f0ec9a0f7a001", + "bootEntryLabel": "SourceOS Recovery Demo" }, - "compliance": { - "status": "compliant", - "notes": "Observed state matches assigned release set, closure hash, and boot recovery reference." - }, - "evidence_refs": [ + "complianceStatus": "compliant", + "complianceNotes": "Observed state matches assigned release set, closure hash, and boot recovery reference.", + "evidenceRefs": [ "urn:srcos:prov:m2-demo-apply-2026-04-26", "urn:srcos:release-receipt:m2-demo-2026-04-26" - ] + ], + "notes": null } diff --git a/examples/git_ref_build.json b/examples/git_ref_build.json new file mode 100644 index 0000000..c8debea --- /dev/null +++ b/examples/git_ref_build.json @@ -0,0 +1,27 @@ +{ + "id": "urn:srcos:git-ref-build:m2-demo-main-2026-04-26", + "type": "GitRefBuild", + "specVersion": "2.0.0", + "repoUri": "https://github.com/SourceOS-Linux/sourceos", + "gitRef": "refs/heads/main", + "gitCommit": "9f49e42af46d84c189b6313f5c8962c6ecd5076b", + "outputs": [ + { + "outputKind": "oci", + "artifactRef": "oci://registry.example.invalid/sourceos/m2-system@sha256:8b3f06c9090ccf926fe6ddc6f3b4f49a13d4b8bb4cb4f5cf78e2d12e31b55aa1", + "contentHash": "sha256:8b3f06c9090ccf926fe6ddc6f3b4f49a13d4b8bb4cb4f5cf78e2d12e31b55aa1" + }, + { + "outputKind": "ostree", + "artifactRef": "urn:srcos:artifact:m2-demo-ostree-sha256-4e2b2e2c", + "contentHash": "sha256:4e2b2e2c6a843f8b8cf38f7b47c8f875f1f9e4c4206e1f8e9c9f0ec9a0f7a001" + } + ], + "releaseSetRef": "urn:srcos:release-set:m2-demo-2026-04-26", + "configSourceRef": "urn:srcos:config-source:sourceos-main-boot-config-2026-04-26", + "triggeredBy": "urn:srcos:party:sourceos-ci-bot", + "triggeredAt": "2026-04-26T13:00:00Z", + "completedAt": "2026-04-26T14:10:00Z", + "status": "succeeded", + "notes": "M2 demo build from main branch. Produced OCI image and ostree commit for the local-first demo release." +} diff --git a/examples/release_set.json b/examples/release_set.json index 1cd9613..54bc538 100644 --- a/examples/release_set.json +++ b/examples/release_set.json @@ -1,24 +1,27 @@ { - "release_set_id": "urn:srcos:release-set:m2-demo-2026-04-26", - "release_version": "2026.04.26-demo.1", + "id": "urn:srcos:release-set:m2-demo-2026-04-26", + "type": "ReleaseSet", + "specVersion": "2.0.0", + "releaseVersion": "2026.04.26-demo.1", "status": "assigned", "source": { - "git_ref": "refs/heads/main", - "git_commit": "9f49e42af46d84c189b6313f5c8962c6ecd5076b" + "gitRef": "refs/heads/main", + "gitCommit": "9f49e42af46d84c189b6313f5c8962c6ecd5076b", + "gitRefBuildRef": "urn:srcos:git-ref-build:m2-demo-main-2026-04-26" }, "targets": [ { - "target_kind": "device", - "target_id": "urn:srcos:device:m2-local-demo" + "targetKind": "device", + "targetRef": "urn:srcos:asset:m2-local-demo" } ], - "experience_profile_ref": "urn:srcos:experience-profile:mac-like-gnome-demo", - "isolation_profile_ref": "urn:srcos:isolation-profile:standard-container-demo", + "experienceProfileRef": "urn:srcos:experience-profile:mac-like-gnome-demo", + "isolationProfileRef": "urn:srcos:isolation-profile:standard-container-demo", "artifacts": { - "store_closure_hash": "sha256-4e2b2e2c6a843f8b8cf38f7b47c8f875f1f9e4c4206e1f8e9c9f0ec9a0f7a001", - "image_ref": "oci://registry.example.invalid/sourceos/m2-system@sha256:8b3f06c9090ccf926fe6ddc6f3b4f49a13d4b8bb4cb4f5cf78e2d12e31b55aa1", - "boot_release_set_ref": "urn:srcos:boot-release-set:m2-demo-recovery-2026-04-26" + "storeClosureHash": "sha256-4e2b2e2c6a843f8b8cf38f7b47c8f875f1f9e4c4206e1f8e9c9f0ec9a0f7a001", + "imageRef": "oci://registry.example.invalid/sourceos/m2-system@sha256:8b3f06c9090ccf926fe6ddc6f3b4f49a13d4b8bb4cb4f5cf78e2d12e31b55aa1", + "bootReleaseSetRef": "urn:srcos:boot-release-set:m2-demo-recovery-2026-04-26" }, - "created_at": "2026-04-26T14:15:00Z", + "createdAt": "2026-04-26T14:15:00Z", "notes": "Local-first M2 demo release assignment produced by the SourceOS control plane." } diff --git a/examples/token_door.json b/examples/token_door.json new file mode 100644 index 0000000..e138634 --- /dev/null +++ b/examples/token_door.json @@ -0,0 +1,16 @@ +{ + "id": "urn:srcos:token-door:m2-demo-recovery-entry-2026-04-26", + "type": "TokenDoor", + "specVersion": "2.0.0", + "doorName": "boot-recovery-entry", + "requiredTokenKind": "recovery-access", + "boundDeviceRef": "urn:srcos:asset:m2-local-demo", + "boundReleaseSetRef": "urn:srcos:release-set:m2-demo-2026-04-26", + "policyRef": "urn:srcos:policy:boot-recovery-m2-demo-v1", + "maxPresentations": 1, + "presentationCount": 0, + "expiresAt": "2026-04-27T14:15:00Z", + "status": "open", + "createdAt": "2026-04-26T14:15:00Z", + "notes": "One-time recovery access door for the M2 demo device, valid for 24 hours. Issued alongside the EnrollmentToken." +} diff --git a/schemas/ConfigSource.json b/schemas/ConfigSource.json new file mode 100644 index 0000000..cf9848f --- /dev/null +++ b/schemas/ConfigSource.json @@ -0,0 +1,85 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/ConfigSource.json", + "title": "ConfigSource", + "description": "A typed reference to an external or inline configuration source consumed by NLBoot, sourceos-boot, or the control plane, specifying its kind, location, and optional integrity binding.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "sourceKind", + "status", + "createdAt" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:config-source:[A-Za-z0-9._~-]+$", + "description": "Stable URN identifier. Pattern: urn:srcos:config-source:" + }, + "type": { + "const": "ConfigSource", + "description": "Discriminator constant — always \"ConfigSource\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "sourceKind": { + "type": "string", + "enum": [ + "git", + "http", + "oci", + "inline", + "bundle" + ], + "description": "Transport mechanism or storage format: git repository, HTTP/HTTPS URL, OCI artifact, inline JSON/YAML, or an opaque bundle ref." + }, + "uri": { + "type": ["string", "null"], + "description": "URI of the configuration source. Required for git, http, and oci kinds." + }, + "gitRef": { + "type": ["string", "null"], + "description": "Git ref to check out when sourceKind is \"git\", e.g. \"refs/heads/main\" or \"refs/tags/v1.2.3\"." + }, + "gitCommit": { + "type": ["string", "null"], + "description": "Pinned Git commit SHA. When present, the consumer must check out this exact commit." + }, + "contentHash": { + "type": ["string", "null"], + "description": "Content-addressed digest of the config payload, e.g. \"sha256:...\". Used for integrity verification." + }, + "inlineContent": { + "type": ["object", "null"], + "additionalProperties": true, + "description": "Inline configuration payload when sourceKind is \"inline\". Must be a valid JSON object." + }, + "authRef": { + "type": ["string", "null"], + "description": "Optional URN reference to a CapabilityToken or credential object required to fetch this source." + }, + "status": { + "type": "string", + "enum": [ + "active", + "deprecated", + "revoked" + ], + "description": "Lifecycle state of the config source." + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 date-time when this config source record was created." + }, + "notes": { + "type": ["string", "null"], + "description": "Optional human-readable notes about this config source." + } + } +} diff --git a/schemas/Fingerprint.json b/schemas/Fingerprint.json new file mode 100644 index 0000000..85236c4 --- /dev/null +++ b/schemas/Fingerprint.json @@ -0,0 +1,108 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/Fingerprint.json", + "title": "Fingerprint", + "description": "A point-in-time observation of a device's realized state, capturing integrity evidence and compliance status relative to an assigned ReleaseSet.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "subject", + "observedAt", + "complianceStatus" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:fingerprint:[A-Za-z0-9._~-]+$", + "description": "Stable URN identifier. Pattern: urn:srcos:fingerprint:" + }, + "type": { + "const": "Fingerprint", + "description": "Discriminator constant — always \"Fingerprint\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "subject": { + "type": "object", + "additionalProperties": false, + "required": ["subjectKind", "subjectRef"], + "properties": { + "subjectKind": { + "type": "string", + "enum": ["device", "vm", "container"], + "description": "Kind of the entity whose state was fingerprinted." + }, + "subjectRef": { + "type": "string", + "description": "URN reference to the device, VM, or container that was fingerprinted." + } + }, + "description": "The entity whose realized state this fingerprint captures." + }, + "releaseSetRef": { + "type": ["string", "null"], + "description": "Optional URN reference to the ReleaseSet against which compliance was evaluated." + }, + "experienceProfileRef": { + "type": ["string", "null"], + "description": "Optional URN reference to the ExperienceProfile observed on the device." + }, + "isolationProfileRef": { + "type": ["string", "null"], + "description": "Optional URN reference to the IsolationProfile observed on the device." + }, + "observedAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 date-time when the observation was taken." + }, + "integrity": { + "type": ["object", "null"], + "additionalProperties": false, + "properties": { + "bootReleaseSetRef": { + "type": ["string", "null"], + "description": "URN reference to the BootReleaseSet whose artifacts were observed as active." + }, + "imageRef": { + "type": ["string", "null"], + "description": "OCI image reference observed as the running system image." + }, + "storeClosureHash": { + "type": ["string", "null"], + "description": "Content-addressed hash of the Nix/ostree store closure observed on the device." + }, + "bootEntryLabel": { + "type": ["string", "null"], + "description": "Human-readable label of the active boot entry observed in the boot loader." + } + }, + "description": "Integrity evidence collected during the observation." + }, + "complianceStatus": { + "type": "string", + "enum": ["compliant", "non-compliant", "unknown"], + "description": "Overall compliance verdict: compliant if the observed state matches the assigned release set, non-compliant if drift was detected, or unknown if evaluation was incomplete." + }, + "complianceNotes": { + "type": ["string", "null"], + "description": "Optional human-readable explanation of the compliance verdict." + }, + "evidenceRefs": { + "type": "array", + "items": { + "type": "string" + }, + "description": "URN references to ProvenanceRecord, ReleaseReceipt, or other evidence objects supporting this fingerprint." + }, + "notes": { + "type": ["string", "null"], + "description": "Optional human-readable notes about this fingerprint." + } + } +} diff --git a/schemas/GitRefBuild.json b/schemas/GitRefBuild.json new file mode 100644 index 0000000..4b65243 --- /dev/null +++ b/schemas/GitRefBuild.json @@ -0,0 +1,118 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/GitRefBuild.json", + "title": "GitRefBuild", + "description": "A build record produced from a specific Git ref, capturing the resolved commit, output artifacts, and status. Consumed by release tooling, Homebrew taps, and the SourceOS control plane to link release sets back to their source provenance.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "repoUri", + "gitRef", + "gitCommit", + "status", + "triggeredAt" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:git-ref-build:[A-Za-z0-9._~-]+$", + "description": "Stable URN identifier. Pattern: urn:srcos:git-ref-build:" + }, + "type": { + "const": "GitRefBuild", + "description": "Discriminator constant — always \"GitRefBuild\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "repoUri": { + "type": "string", + "description": "URI of the source Git repository, e.g. \"https://github.com/SourceOS-Linux/sourceos\"." + }, + "gitRef": { + "type": "string", + "description": "Git ref that triggered the build, e.g. \"refs/heads/main\" or \"refs/tags/v2026.04.26\"." + }, + "gitCommit": { + "type": "string", + "description": "Full SHA-1 or SHA-256 Git commit hash resolved from gitRef at build time." + }, + "outputs": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["outputKind", "artifactRef"], + "properties": { + "outputKind": { + "type": "string", + "enum": [ + "iso", + "pxe", + "raw", + "qcow2", + "ami", + "bootc", + "ostree", + "oci", + "bundle", + "homebrew-bottle", + "other" + ], + "description": "Kind of build output artifact." + }, + "artifactRef": { + "type": "string", + "description": "URN or URL reference to the produced artifact." + }, + "contentHash": { + "type": ["string", "null"], + "description": "Content-addressed digest of the artifact, e.g. \"sha256:...\"." + } + } + }, + "description": "List of artifacts produced by this build." + }, + "releaseSetRef": { + "type": ["string", "null"], + "description": "Optional URN reference to the ReleaseSet created from this build." + }, + "configSourceRef": { + "type": ["string", "null"], + "description": "Optional URN reference to the ConfigSource that provided build configuration." + }, + "triggeredBy": { + "type": ["string", "null"], + "description": "Optional subject or actor ref (URN or email) that triggered the build." + }, + "triggeredAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 date-time when the build was triggered." + }, + "completedAt": { + "type": ["string", "null"], + "format": "date-time", + "description": "ISO 8601 date-time when the build completed, or null if still in progress." + }, + "status": { + "type": "string", + "enum": [ + "pending", + "running", + "succeeded", + "failed", + "cancelled" + ], + "description": "Current status of the build." + }, + "notes": { + "type": ["string", "null"], + "description": "Optional human-readable notes about this build." + } + } +} diff --git a/schemas/README.md b/schemas/README.md index 7bd7bb9..ef7064d 100644 --- a/schemas/README.md +++ b/schemas/README.md @@ -4,6 +4,27 @@ This directory contains the JSON Schema (draft 2020-12) files that make up the S --- +## Recent additions — Release and build lifecycle + +The release/build lifecycle slice adds the following top-level schemas: + +| File | Type | URN prefix | +|------|------|-----------| +| `ReleaseSet.json` | ReleaseSet | `urn:srcos:release-set:` | +| `Fingerprint.json` | Fingerprint | `urn:srcos:fingerprint:` | +| `ConfigSource.json` | ConfigSource | `urn:srcos:config-source:` | +| `TokenDoor.json` | TokenDoor | `urn:srcos:token-door:` | +| `GitRefBuild.json` | GitRefBuild | `urn:srcos:git-ref-build:` | + +These types support: +- canonical assignment of software + boot artifacts to target devices (`ReleaseSet`) +- point-in-time device state observation and compliance reporting (`Fingerprint`) +- typed configuration source references consumed by NLBoot and sourceos-boot (`ConfigSource`) +- token-gated access control gates for boot/provisioning phases (`TokenDoor`) +- build provenance records linking Git commits to release artifacts (`GitRefBuild`) + +--- + ## Recent additions — Workstation Contract Family The workstation contract family adds the following top-level schemas: @@ -61,6 +82,7 @@ These types support: | `CapabilityToken.json` | CapabilityToken | _(plain `tokenId` string)_ | | `Comment.json` | Comment | `urn:srcos:comment:` | | `Community.json` | Community | `urn:srcos:community:` | +| `ConfigSource.json` | ConfigSource | `urn:srcos:config-source:` | | `Connector.json` | Connector | `urn:srcos:connector:` | | `ContentRef.json` | ContentRef | _(digest-based content reference)_ | | `DataRef.json` | DataRef | _(sub-object, no top-level id)_ | @@ -75,7 +97,9 @@ These types support: | `ExecutionSurface.json` | ExecutionSurface | _(sub-object inside AgentSession)_ | | `ExperimentFlag.json` | ExperimentFlag | `urn:srcos:flag:` | | `Field.json` | Field | `urn:srcos:field:` | +| `Fingerprint.json` | Fingerprint | `urn:srcos:fingerprint:` | | `FrustrationSignal.json` | FrustrationSignal | `urn:srcos:frustration:` | +| `GitRefBuild.json` | GitRefBuild | `urn:srcos:git-ref-build:` | | `GlossaryTerm.json` | GlossaryTerm | `urn:srcos:glossary:` | | `LauncherAction.json` | LauncherAction | `urn:srcos:launcher-action:` | | `LauncherProvider.json` | LauncherProvider | `urn:srcos:launcher-provider:` | @@ -99,7 +123,9 @@ These types support: | `ProvenanceRecord.json` | ProvenanceRecord | `urn:srcos:prov:` | | `QualityMetric.json` | QualityMetric | _(sub-object inside Field.quality)_ | | `Rating.json` | Rating | `urn:srcos:rating:` | +| `ReleaseManifest.json` | ReleaseManifest | `urn:srcos:release:` | | `ReleaseReceipt.json` | ReleaseReceipt | `urn:srcos:release-receipt:` | +| `ReleaseSet.json` | ReleaseSet | `urn:srcos:release-set:` | | `ReplicationPolicy.json` | ReplicationPolicy | _(top-level policy object)_ | | `RolloutPolicy.json` | RolloutPolicy | `urn:srcos:rollout:` | | `Rule.json` | Rule | _(sub-object inside Policy)_ | @@ -115,6 +141,7 @@ These types support: | `TelemetryEvent.json` | TelemetryEvent | `urn:srcos:telemetry:` | | `Topic.json` | Topic | `urn:srcos:topic:` | | `TopicEnvelope.json` | TopicEnvelope | `urn:srcos:topic-entry:` | +| `TokenDoor.json` | TokenDoor | `urn:srcos:token-door:` | | `Trigger.json` | Trigger | _(sub-object inside WorkflowSpec)_ | | `TruthSurface.json` | TruthSurface | `urn:srcos:truth-surface:` | | `UsageReceipt.json` | UsageReceipt | `urn:srcos:receipt:usage:` | diff --git a/schemas/ReleaseSet.json b/schemas/ReleaseSet.json new file mode 100644 index 0000000..9d26e63 --- /dev/null +++ b/schemas/ReleaseSet.json @@ -0,0 +1,121 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/ReleaseSet.json", + "title": "ReleaseSet", + "description": "An assigned release set describing the canonical software and boot artifacts that should be realized on one or more target devices at a given release version.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "releaseVersion", + "status", + "createdAt" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:release-set:[A-Za-z0-9._~-]+$", + "description": "Stable URN identifier. Pattern: urn:srcos:release-set:" + }, + "type": { + "const": "ReleaseSet", + "description": "Discriminator constant — always \"ReleaseSet\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "releaseVersion": { + "type": "string", + "description": "Human-readable release version string, e.g. \"2026.04.26-demo.1\"." + }, + "status": { + "type": "string", + "enum": [ + "draft", + "assigned", + "active", + "superseded", + "revoked" + ], + "description": "Lifecycle state of the release set." + }, + "source": { + "type": ["object", "null"], + "additionalProperties": false, + "properties": { + "gitRef": { + "type": "string", + "description": "Git ref from which this release was built, e.g. \"refs/heads/main\"." + }, + "gitCommit": { + "type": "string", + "description": "Full SHA-1 or SHA-256 Git commit hash that produced this release." + }, + "gitRefBuildRef": { + "type": ["string", "null"], + "description": "Optional URN reference to the GitRefBuild record for this release." + } + }, + "description": "Source Git provenance for this release set." + }, + "targets": { + "type": "array", + "description": "List of target devices or device groups this release set is assigned to.", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["targetKind", "targetRef"], + "properties": { + "targetKind": { + "type": "string", + "enum": ["device", "device-group", "fleet"], + "description": "Kind of the target: a single device, a named device group, or a fleet." + }, + "targetRef": { + "type": "string", + "description": "URN reference to the target device, group, or fleet." + } + } + } + }, + "experienceProfileRef": { + "type": ["string", "null"], + "description": "Optional URN reference to the ExperienceProfile defining the desktop/UX posture for this release." + }, + "isolationProfileRef": { + "type": ["string", "null"], + "description": "Optional URN reference to the IsolationProfile defining the container and namespace boundaries for this release." + }, + "artifacts": { + "type": ["object", "null"], + "additionalProperties": false, + "properties": { + "storeClosureHash": { + "type": ["string", "null"], + "description": "Content-addressed hash of the Nix/ostree store closure, e.g. \"sha256-...\"." + }, + "imageRef": { + "type": ["string", "null"], + "description": "OCI image reference for the system image, e.g. \"oci://registry.example/sourceos/system@sha256:...\"." + }, + "bootReleaseSetRef": { + "type": ["string", "null"], + "description": "Optional URN reference to the BootReleaseSet containing boot artifacts for this release." + } + }, + "description": "Key artifact references for the release set." + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 date-time when this release set was created." + }, + "notes": { + "type": ["string", "null"], + "description": "Optional human-readable notes about this release set." + } + } +} diff --git a/schemas/TokenDoor.json b/schemas/TokenDoor.json new file mode 100644 index 0000000..b952e64 --- /dev/null +++ b/schemas/TokenDoor.json @@ -0,0 +1,87 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/TokenDoor.json", + "title": "TokenDoor", + "description": "A token-gated access control gate that authorises a subject to cross a named boundary (e.g. a boot phase, provisioning step, or control-plane surface) when it presents a valid CapabilityToken.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "doorName", + "requiredTokenKind", + "status", + "createdAt" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:token-door:[A-Za-z0-9._~-]+$", + "description": "Stable URN identifier. Pattern: urn:srcos:token-door:" + }, + "type": { + "const": "TokenDoor", + "description": "Discriminator constant — always \"TokenDoor\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "doorName": { + "type": "string", + "description": "Human-readable name of the gate, e.g. \"boot-recovery-entry\" or \"provisioning-write\"." + }, + "requiredTokenKind": { + "type": "string", + "description": "The CapabilityToken kind or scope string that a presenter must carry, e.g. \"recovery-access\" or \"provisioning-write\"." + }, + "boundDeviceRef": { + "type": ["string", "null"], + "description": "Optional URN reference to the device or fleet this door is bound to. Null means any subject may present." + }, + "boundReleaseSetRef": { + "type": ["string", "null"], + "description": "Optional URN reference to the ReleaseSet that gates passage; the presenter's token must have been issued for this release." + }, + "policyRef": { + "type": ["string", "null"], + "description": "Optional URN reference to a Policy that further constrains access." + }, + "maxPresentations": { + "type": ["integer", "null"], + "minimum": 1, + "description": "Maximum number of times a valid token may be presented before the door is closed. Null means unlimited." + }, + "presentationCount": { + "type": "integer", + "minimum": 0, + "description": "Number of times a valid token has been successfully presented so far.", + "default": 0 + }, + "expiresAt": { + "type": ["string", "null"], + "format": "date-time", + "description": "Optional ISO 8601 date-time after which the door closes regardless of token validity." + }, + "status": { + "type": "string", + "enum": [ + "open", + "closed", + "revoked", + "expired" + ], + "description": "Current state of the door: open (accepting presentations), closed (quota met or manually closed), revoked, or expired." + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 date-time when this token door was created." + }, + "notes": { + "type": ["string", "null"], + "description": "Optional human-readable notes about this token door." + } + } +} diff --git a/tools/validate_control_plane_examples.py b/tools/validate_control_plane_examples.py index df7f2d8..25160cf 100644 --- a/tools/validate_control_plane_examples.py +++ b/tools/validate_control_plane_examples.py @@ -8,8 +8,6 @@ ROOT = Path(__file__).resolve().parents[1] PAIRS = [ - (ROOT / "schemas" / "control-plane" / "ReleaseSet.json", ROOT / "examples" / "release_set.json"), - (ROOT / "schemas" / "control-plane" / "Fingerprint.json", ROOT / "examples" / "fingerprint.json"), (ROOT / "schemas" / "control-plane" / "BootReleaseSet.json", ROOT / "examples" / "boot_release_set.json"), (ROOT / "schemas" / "control-plane" / "EnrollmentToken.json", ROOT / "examples" / "enrollment_token.json"), ] @@ -19,7 +17,7 @@ def validate_pair(schema_path: Path, example_path: Path) -> None: schema = json.loads(schema_path.read_text(encoding="utf-8")) jsonschema.validators.validator_for(schema).check_schema(schema) legacy_ref = schema.get("allOf", [{}])[0].get("$ref") - validation_schema_path = schema_path.with_name(legacy_ref) if legacy_ref else schema_path + validation_schema_path = (schema_path.parent / legacy_ref).resolve() if legacy_ref else schema_path validation_schema = json.loads(validation_schema_path.read_text(encoding="utf-8")) example = json.loads(example_path.read_text(encoding="utf-8")) jsonschema.validate(example, validation_schema) diff --git a/tools/validate_nlboot_examples.py b/tools/validate_nlboot_examples.py index b5dea80..4124435 100644 --- a/tools/validate_nlboot_examples.py +++ b/tools/validate_nlboot_examples.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Validate NLBoot schema/example pairs.""" +"""Validate NLBoot and release/build lifecycle schema/example pairs.""" from __future__ import annotations import json @@ -13,6 +13,12 @@ (ROOT / "schemas" / "ArtifactCacheRecord.json", ROOT / "examples" / "artifact_cache_record.json"), (ROOT / "schemas" / "BootProofRecord.json", ROOT / "examples" / "boot_proof_record.json"), (ROOT / "schemas" / "AppleSiliconAdapterEvidence.json", ROOT / "examples" / "apple_silicon_adapter_evidence.json"), + # Release and build lifecycle objects + (ROOT / "schemas" / "ReleaseSet.json", ROOT / "examples" / "release_set.json"), + (ROOT / "schemas" / "Fingerprint.json", ROOT / "examples" / "fingerprint.json"), + (ROOT / "schemas" / "ConfigSource.json", ROOT / "examples" / "config_source.json"), + (ROOT / "schemas" / "TokenDoor.json", ROOT / "examples" / "token_door.json"), + (ROOT / "schemas" / "GitRefBuild.json", ROOT / "examples" / "git_ref_build.json"), ]