From 3c78eb87ab6714c6aef335b95b5ea2b60e3cee8a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Apr 2026 12:44:54 +0000 Subject: [PATCH 1/2] Initial plan From b4d4ee7e76688c6548b58a2abdbdb5f10b7cf90d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Apr 2026 12:52:38 +0000 Subject: [PATCH 2/2] feat: add NLBoot object schemas, examples, and validation Agent-Logs-Url: https://github.com/SourceOS-Linux/sourceos-spec/sessions/dddfea02-e8c7-4d82-8c81-d073b4f7bf69 Co-authored-by: mdheller <21163552+mdheller@users.noreply.github.com> --- CHANGELOG.md | 1 + Makefile | 8 +- docs/adr/0011-nlboot-object-schemas.md | 68 +++++++++++ examples/README.md | 4 + examples/apple_silicon_adapter_evidence.json | 21 ++++ examples/artifact_cache_record.json | 15 +++ examples/boot_proof_record.json | 45 +++++++ examples/nlboot_plan.json | 43 +++++++ openapi.yaml | 110 ++++++++++++++++++ schemas/AppleSiliconAdapterEvidence.json | 101 ++++++++++++++++ schemas/ArtifactCacheRecord.json | 98 ++++++++++++++++ schemas/BootProofRecord.json | 116 +++++++++++++++++++ schemas/NLBootPlan.json | 114 ++++++++++++++++++ schemas/README.md | 13 +++ semantic/hydra.jsonld | 36 ++++++ tools/validate_nlboot_examples.py | 36 ++++++ 16 files changed, 827 insertions(+), 2 deletions(-) create mode 100644 docs/adr/0011-nlboot-object-schemas.md create mode 100644 examples/apple_silicon_adapter_evidence.json create mode 100644 examples/artifact_cache_record.json create mode 100644 examples/boot_proof_record.json create mode 100644 examples/nlboot_plan.json create mode 100644 schemas/AppleSiliconAdapterEvidence.json create mode 100644 schemas/ArtifactCacheRecord.json create mode 100644 schemas/BootProofRecord.json create mode 100644 schemas/NLBootPlan.json create mode 100644 tools/validate_nlboot_examples.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 6656256..1a2e9a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). Thi ## [Unreleased] ### Added +- NLBoot object schemas: `NLBootPlan`, `ArtifactCacheRecord`, `BootProofRecord`, `AppleSiliconAdapterEvidence` with canonical examples and validation (`tools/validate_nlboot_examples.py`) - Compression Commons: `CompressionEvaluation` schema and canonical example (`examples/compressionevaluation.json`) - Truth Plane: `TruthSurface` and `DeltaSurface` schemas + canonical examples (`examples/truth_surface.json`, `examples/delta_surface.json`) - Control-plane: `IncidentEvent` schema for incident lifecycle events diff --git a/Makefile b/Makefile index e62fa34..c05a8ff 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,12 @@ -.PHONY: validate validate-control-plane-examples +.PHONY: validate validate-control-plane-examples validate-nlboot-examples -validate: validate-control-plane-examples +validate: validate-control-plane-examples validate-nlboot-examples @echo "OK: validate" validate-control-plane-examples: python3 -m pip install --user jsonschema >/dev/null python3 tools/validate_control_plane_examples.py + +validate-nlboot-examples: + python3 -m pip install --user jsonschema >/dev/null + python3 tools/validate_nlboot_examples.py diff --git a/docs/adr/0011-nlboot-object-schemas.md b/docs/adr/0011-nlboot-object-schemas.md new file mode 100644 index 0000000..8009007 --- /dev/null +++ b/docs/adr/0011-nlboot-object-schemas.md @@ -0,0 +1,68 @@ +# ADR-0011: NLBoot Object Schemas + +**Date:** 2026-04-30 +**Status:** `Accepted` +**Deciders:** SourceOS-Linux/sourceos-spec maintainers + +--- + +## Context + +The NLBoot system orchestrates Linux boot on Apple Silicon (Asahi) and generic UEFI targets. It manages ordered boot stages, locally cached artifacts, per-boot integrity proofs, and Apple Silicon–specific adapter evidence. + +Without canonical object schemas in this repository, downstream repos risk inventing overlapping structures for boot plans, artifact caching, proof reporting, and Apple Silicon adapter state. The `SourceOS-Linux/sourceos-spec` repository is the normative home for machine-readable contracts consumed by NLBoot, sourceos-boot, Sociosphere, and control-plane surfaces. + +## Decision + +Introduce four new top-level schemas in the Boot / NLBoot family: + +| Schema | URN prefix | Purpose | +|--------|-----------|---------| +| `NLBootPlan` | `urn:srcos:nlboot-plan:` | Ordered boot stage plan for a target device | +| `ArtifactCacheRecord` | `urn:srcos:artifact-cache:` | Content-addressed local artifact cache entry | +| `BootProofRecord` | `urn:srcos:boot-proof:` | Immutable per-boot integrity proof with stage verdicts | +| `AppleSiliconAdapterEvidence` | `urn:srcos:as-adapter-evidence:` | Asahi-compatible Apple Silicon adapter evidence | + +All four schemas follow the standard v2 conventions: `$id` under `https://schemas.srcos.ai/v2/`, `additionalProperties: false`, required `id`/`type`/`specVersion` discriminators, and `description` on every property. + +### Scope of this repository + +This repository owns: +- canonical JSON Schema definitions for the four types +- conforming example payloads +- validation tooling (`tools/validate_nlboot_examples.py`) + +This repository does not own: +- NLBoot runtime boot executor implementation (`SociOS-Linux/nlboot`) +- Apple Silicon boot-chain implementation (`SociOS-Linux/asahi-u-boot`, `SociOS-Linux/asahi-installer`) +- transport bindings or RPC protocol definitions + +## Alternatives considered + +| Alternative | Reason not chosen | +|-------------|------------------| +| Add schemas inside `schemas/control-plane/` | NLBoot objects are boot-plane contracts, not legacy control-plane objects; they belong at the top level | +| Single merged `NLBootEvidence` schema covering all four concerns | Each concern has distinct required fields and lifecycle; splitting keeps schemas compact and independently consumable | +| Re-use existing `AttestationEvidence` for Apple Silicon evidence | `AttestationEvidence` models TPM/IMA measured-boot evidence; Apple Silicon adapter evidence captures Asahi-specific boot picker and m1n1/U-Boot state that does not fit that model | + +## Consequences + +### Positive + +- downstream repos can reference canonical URN-typed NLBoot objects without re-inventing structure +- boot plan, artifact cache, and proof record objects are independently versioned and independently consumable +- Apple Silicon adapter evidence is first-class and auditable, not embedded in ad hoc implementation logs +- all four schemas are immediately validated by `make validate-nlboot-examples` + +### Constraints + +- schemas are intentionally minimal at introduction; fields may be added additively in follow-on PRs +- proof reporting endpoint binding (`policyDecisionRef`, `evidenceRefs`) is normative contract only; enforcement belongs in runtime repos + +## References + +- Issue: SourceOS-Linux/sourceos-spec — "Agent task: add NLBoot object schemas" +- ADR-0008: Local-first release and enrollment contract family +- ADR-2026-04: Contract vs Bootstrap Boundaries +- `schemas/BootSurface.json` — related boot-surface schema +- `schemas/AttestationEvidence.json` — measured-boot attestation evidence diff --git a/examples/README.md b/examples/README.md index de1989a..3db9854 100644 --- a/examples/README.md +++ b/examples/README.md @@ -131,7 +131,10 @@ These examples illustrate the shared object family used by SourceOS artifact bui | `access_profile.json` | AccessProfile | Access profile for SourceOS build operators and agentplane executor obligations | | `agreement.json` | Agreement | Default personal-data agreement | | `agent_session.json` | AgentSession | An executor session running the obfuscation workflow | +| `apple_silicon_adapter_evidence.json` | AppleSiliconAdapterEvidence | Apple Silicon adapter evidence for an M2 device running SourceOS via Asahi | +| `artifact_cache_record.json` | ArtifactCacheRecord | Cached Linux kernel artifact for the M2 demo device | | `asset.json` | PhysicalAsset | Lakehouse asset for curated health observations | +| `boot_proof_record.json` | BootProofRecord | Verified boot proof for SourceOS M2 device via NLBoot Asahi path | | `boot_release_set.json` | BootReleaseSet | SourceOS Recovery Environment boot artifact set for secure recovery/provisioning | | `build_request.json` | BuildRequest | SourceOS Workstation build request with agentplane and Katello refs | | `capability_token.json` | CapabilityToken | Access token scoped to the health dataset export operation | @@ -157,6 +160,7 @@ These examples illustrate the shared object family used by SourceOS artifact bui | `glossary.json` | GlossaryTerm | Glossary term for "Date of Birth" | | `mapping.json` | MappingSpec | A field mapping between two dataset fields | | `memory_entry.json` | MemoryEntry | A learned memory entry from an agent session | +| `nlboot_plan.json` | NLBootPlan | NLBoot boot plan for SourceOS M2 demo device via Asahi path | | `offer.json` | Offer | FogCompute provider offer | | `overlay_bundle.json` | OverlayBundle | Customer branding overlay applied to the workstation flavor | | `policy.json` | Policy | Health export must be obfuscated | diff --git a/examples/apple_silicon_adapter_evidence.json b/examples/apple_silicon_adapter_evidence.json new file mode 100644 index 0000000..f11ee97 --- /dev/null +++ b/examples/apple_silicon_adapter_evidence.json @@ -0,0 +1,21 @@ +{ + "id": "urn:srcos:as-adapter-evidence:m2-adapter-2026-04-30", + "type": "AppleSiliconAdapterEvidence", + "specVersion": "2.0.0", + "deviceRef": "urn:srcos:asset:fedora-asahi-m2", + "capturedAt": "2026-04-30T09:55:00Z", + "chipModel": "M2", + "boardId": "J413AP", + "securityPolicy": "reduced-security", + "localBootStatus": "ok", + "adapterVersion": "0.4.0", + "m1n1Version": "1.4.6", + "uBootVersion": "2024.01-asahi-4", + "bootChainHashes": { + "m1n1": "sha256:7a38f2d1e4b9c3a5d6e8f0b2c4a6d8e0f2b4c6a8d0e2f4b6c8a0d2e4f6b8c0a2", + "u-boot": "sha256:2b4d6f8a0c2e4f6b8a0c2e4f6b8a0c2e4f6b8a0c2e4f6b8a0c2e4f6b8a0c2e4f" + }, + "bootPickerEntryRef": "urn:srcos:boot-entry:m2-demo-sourceos-asahi-installer", + "installerDataRef": "urn:srcos:artifact:m2-demo-asahi-installer-data-sha256-3f9c1f44", + "notes": "Apple Silicon adapter evidence for M2 MacBook Air running SourceOS via Asahi path." +} diff --git a/examples/artifact_cache_record.json b/examples/artifact_cache_record.json new file mode 100644 index 0000000..20db097 --- /dev/null +++ b/examples/artifact_cache_record.json @@ -0,0 +1,15 @@ +{ + "id": "urn:srcos:artifact-cache:kernel-sha256-0f3b6d7f", + "type": "ArtifactCacheRecord", + "specVersion": "2.0.0", + "artifactKind": "kernel", + "contentHash": "sha256:0f3b6d7f1e2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c", + "status": "cached", + "cachedAt": "2026-04-29T18:00:00Z", + "platform": "apple-silicon-asahi", + "sourceUrl": "https://cdn.asahilinux.org/m2/kernel-6.8.0-asahi-20240415.tar.gz", + "sourceRef": "urn:srcos:boot-release-set:m2-demo-recovery-2026-04-26", + "sizeBytes": 12582912, + "expiresAt": "2026-07-29T18:00:00Z", + "notes": "Linux kernel 6.8 with Apple Silicon patches for the M2 demo device." +} diff --git a/examples/boot_proof_record.json b/examples/boot_proof_record.json new file mode 100644 index 0000000..8598473 --- /dev/null +++ b/examples/boot_proof_record.json @@ -0,0 +1,45 @@ +{ + "id": "urn:srcos:boot-proof:m2-sourceos-boot-2026-04-30", + "type": "BootProofRecord", + "specVersion": "2.0.0", + "bootPlanRef": "urn:srcos:nlboot-plan:m2-sourceos-main-2026-04-30", + "deviceRef": "urn:srcos:asset:fedora-asahi-m2", + "outcome": "success", + "bootedAt": "2026-04-30T10:00:00Z", + "stageProofs": [ + { + "stageName": "m1n1", + "artifactRef": "urn:srcos:artifact-cache:m1n1-sha256-7a38f2d1", + "contentHash": "sha256:7a38f2d1e4b9c3a5d6e8f0b2c4a6d8e0f2b4c6a8d0e2f4b6c8a0d2e4f6b8c0a2", + "verdict": "verified", + "notes": null + }, + { + "stageName": "u-boot", + "artifactRef": "urn:srcos:artifact-cache:uboot-sha256-2b4d6f8a", + "contentHash": "sha256:2b4d6f8a0c2e4f6b8a0c2e4f6b8a0c2e4f6b8a0c2e4f6b8a0c2e4f6b8a0c2e4f", + "verdict": "verified", + "notes": null + }, + { + "stageName": "kernel", + "artifactRef": "urn:srcos:artifact-cache:kernel-sha256-0f3b6d7f", + "contentHash": "sha256:0f3b6d7f1e2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c", + "verdict": "verified", + "notes": null + }, + { + "stageName": "initrd", + "artifactRef": "urn:srcos:artifact-cache:initrd-sha256-08f4c82e", + "contentHash": "sha256:08f4c82e9d0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d", + "verdict": "verified", + "notes": null + } + ], + "evidenceRefs": [ + "urn:srcos:attestation:m2-boot-evidence-2026-04-30" + ], + "policyDecisionRef": "urn:srcos:decision:boot-m2-demo-v1-2026-04-30", + "signature": null, + "notes": "Successful verified boot of SourceOS on M2 demo device via NLBoot Asahi path." +} diff --git a/examples/nlboot_plan.json b/examples/nlboot_plan.json new file mode 100644 index 0000000..cdd83f0 --- /dev/null +++ b/examples/nlboot_plan.json @@ -0,0 +1,43 @@ +{ + "id": "urn:srcos:nlboot-plan:m2-sourceos-main-2026-04-30", + "type": "NLBootPlan", + "specVersion": "2.0.0", + "targetDeviceRef": "urn:srcos:asset:fedora-asahi-m2", + "platform": "apple-silicon-asahi", + "status": "active", + "stages": [ + { + "name": "m1n1", + "artifactRef": "urn:srcos:artifact-cache:m1n1-sha256-7a38f2d1", + "contentHash": "sha256:7a38f2d1e4b9c3a5d6e8f0b2c4a6d8e0f2b4c6a8d0e2f4b6c8a0d2e4f6b8c0a2", + "verificationRequired": true, + "notes": "Primary Apple Silicon stage-1 bootloader" + }, + { + "name": "u-boot", + "artifactRef": "urn:srcos:artifact-cache:uboot-sha256-2b4d6f8a", + "contentHash": "sha256:2b4d6f8a0c2e4f6b8a0c2e4f6b8a0c2e4f6b8a0c2e4f6b8a0c2e4f6b8a0c2e4f", + "verificationRequired": true, + "notes": "U-Boot stage for EFI handoff" + }, + { + "name": "kernel", + "artifactRef": "urn:srcos:artifact-cache:kernel-sha256-0f3b6d7f", + "contentHash": "sha256:0f3b6d7f1e2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c", + "verificationRequired": true, + "notes": "Linux kernel with Apple Silicon patches" + }, + { + "name": "initrd", + "artifactRef": "urn:srcos:artifact-cache:initrd-sha256-08f4c82e", + "contentHash": "sha256:08f4c82e9d0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d", + "verificationRequired": true, + "notes": "Initial ramdisk for early userspace" + } + ], + "bootReleaseSetRef": "urn:srcos:boot-release-set:m2-demo-recovery-2026-04-26", + "policyRef": "urn:srcos:policy:boot-recovery-m2-demo-v1", + "activatedAt": "2026-04-30T10:00:00Z", + "createdAt": "2026-04-30T09:00:00Z", + "notes": "Main boot plan for SourceOS M2 demo device using Asahi Linux path." +} diff --git a/openapi.yaml b/openapi.yaml index 8ad1c03..7de26d2 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -32,6 +32,8 @@ tags: description: Workflows, runs, and provenance records - name: Collaboration description: Comments and ratings + - name: Boot + description: NLBoot plans, artifact cache, proof records, and Apple Silicon adapter evidence components: securitySchemes: @@ -524,3 +526,111 @@ paths: description: Request body is valid JSON but fails schema validation. content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } + + /v2/nlboot-plans: + post: + operationId: upsertNLBootPlan + summary: Upsert an NLBootPlan + description: Creates or updates an NLBoot boot plan describing ordered boot stages, artifact refs, and verification policy for a target device. Idempotent on `id`. + tags: [Boot] + requestBody: + required: true + content: + application/json: + schema: { $ref: './schemas/NLBootPlan.json' } + responses: + '200': + description: NLBootPlan created or updated successfully. + '400': + description: Request body is malformed JSON. + content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } + '401': + description: Missing or invalid authentication token. + content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } + '403': + description: Authenticated subject is not permitted to upsert boot plans. + content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } + '422': + description: Request body is valid JSON but fails schema validation. + content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } + + /v2/artifact-cache-records: + post: + operationId: upsertArtifactCacheRecord + summary: Upsert an ArtifactCacheRecord + description: Creates or updates a content-addressed cache entry for a locally-stored NLBoot artifact. Idempotent on `id`. + tags: [Boot] + requestBody: + required: true + content: + application/json: + schema: { $ref: './schemas/ArtifactCacheRecord.json' } + responses: + '200': + description: ArtifactCacheRecord created or updated successfully. + '400': + description: Request body is malformed JSON. + content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } + '401': + description: Missing or invalid authentication token. + content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } + '403': + description: Authenticated subject is not permitted to upsert artifact cache records. + content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } + '422': + description: Request body is valid JSON but fails schema validation. + content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } + + /v2/boot-proof-records: + post: + operationId: recordBootProof + summary: Record a BootProofRecord + description: Persists an immutable boot integrity proof record with per-stage verdicts and attestation evidence refs. Idempotent on `id`. + tags: [Boot] + requestBody: + required: true + content: + application/json: + schema: { $ref: './schemas/BootProofRecord.json' } + responses: + '200': + description: BootProofRecord persisted successfully. + '400': + description: Request body is malformed JSON. + content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } + '401': + description: Missing or invalid authentication token. + content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } + '403': + description: Authenticated subject is not permitted to record boot proofs. + content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } + '422': + description: Request body is valid JSON but fails schema validation. + content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } + + /v2/apple-silicon-adapter-evidence: + post: + operationId: recordAppleSiliconAdapterEvidence + summary: Record AppleSiliconAdapterEvidence + description: Persists evidence collected by the Asahi-compatible Apple Silicon boot adapter, capturing chip identity, security policy, and boot-chain hashes. Idempotent on `id`. + tags: [Boot] + requestBody: + required: true + content: + application/json: + schema: { $ref: './schemas/AppleSiliconAdapterEvidence.json' } + responses: + '200': + description: AppleSiliconAdapterEvidence persisted successfully. + '400': + description: Request body is malformed JSON. + content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } + '401': + description: Missing or invalid authentication token. + content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } + '403': + description: Authenticated subject is not permitted to record Apple Silicon adapter evidence. + content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } + '422': + description: Request body is valid JSON but fails schema validation. + content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } diff --git a/schemas/AppleSiliconAdapterEvidence.json b/schemas/AppleSiliconAdapterEvidence.json new file mode 100644 index 0000000..be378ac --- /dev/null +++ b/schemas/AppleSiliconAdapterEvidence.json @@ -0,0 +1,101 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/AppleSiliconAdapterEvidence.json", + "title": "AppleSiliconAdapterEvidence", + "description": "Evidence collected by the Apple Silicon boot adapter (Asahi-compatible) recording chip identity, security policy, boot-chain stage hashes, and boot-picker state.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "deviceRef", + "capturedAt", + "chipModel", + "securityPolicy", + "localBootStatus" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:as-adapter-evidence:[A-Za-z0-9._~-]+$", + "description": "Stable URN identifier. Pattern: urn:srcos:as-adapter-evidence:" + }, + "type": { + "const": "AppleSiliconAdapterEvidence", + "description": "Discriminator constant — always \"AppleSiliconAdapterEvidence\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "deviceRef": { + "type": "string", + "description": "URN reference to the physical Apple Silicon device." + }, + "capturedAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 date-time when this evidence was collected." + }, + "chipModel": { + "type": "string", + "description": "Apple Silicon chip identifier, e.g. \"M1\", \"M2\", \"M2 Pro\", \"M3\"." + }, + "boardId": { + "type": ["string", "null"], + "description": "Optional hardware board identifier as reported by the firmware." + }, + "securityPolicy": { + "type": "string", + "enum": [ + "full-security", + "reduced-security", + "permissive-security" + ], + "description": "Apple Secure Boot security policy active on the device at collection time." + }, + "localBootStatus": { + "type": "string", + "enum": [ + "ok", + "degraded", + "uninitialized", + "recovery" + ], + "description": "Overall local boot status reported by the adapter." + }, + "adapterVersion": { + "type": ["string", "null"], + "description": "Version of the NLBoot Apple Silicon adapter that collected this evidence." + }, + "m1n1Version": { + "type": ["string", "null"], + "description": "Version of m1n1 present in the boot chain, if known." + }, + "uBootVersion": { + "type": ["string", "null"], + "description": "Version of U-Boot present in the boot chain, if known." + }, + "bootChainHashes": { + "type": "object", + "additionalProperties": { + "type": "string", + "description": "Content digest for the named boot-chain stage, e.g. \"sha256:...\"." + }, + "description": "Map of boot-chain stage name to content digest observed at collection time." + }, + "bootPickerEntryRef": { + "type": ["string", "null"], + "description": "Optional URN reference to the Asahi-compatible boot-picker entry for the target OS install." + }, + "installerDataRef": { + "type": ["string", "null"], + "description": "Optional URN reference to the Asahi installer metadata artifact associated with this device." + }, + "notes": { + "type": ["string", "null"], + "description": "Optional human-readable notes about this evidence record." + } + } +} diff --git a/schemas/ArtifactCacheRecord.json b/schemas/ArtifactCacheRecord.json new file mode 100644 index 0000000..851744f --- /dev/null +++ b/schemas/ArtifactCacheRecord.json @@ -0,0 +1,98 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/ArtifactCacheRecord.json", + "title": "ArtifactCacheRecord", + "description": "A content-addressed cache entry recording a locally-stored NLBoot artifact with its origin, digest, status, and platform binding.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "artifactKind", + "contentHash", + "status", + "cachedAt" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:artifact-cache:[A-Za-z0-9._~-]+$", + "description": "Stable URN identifier. Pattern: urn:srcos:artifact-cache:" + }, + "type": { + "const": "ArtifactCacheRecord", + "description": "Discriminator constant — always \"ArtifactCacheRecord\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "artifactKind": { + "type": "string", + "enum": [ + "kernel", + "initrd", + "bootloader", + "rootfs", + "m1n1", + "u-boot", + "installer-data", + "device-tree", + "other" + ], + "description": "Semantic role of the cached artifact in the boot chain." + }, + "contentHash": { + "type": "string", + "description": "Content-addressed digest of the artifact, e.g. \"sha256:abc123...\"." + }, + "status": { + "type": "string", + "enum": [ + "pending", + "cached", + "evicted", + "corrupted" + ], + "description": "Current status of the cache entry." + }, + "cachedAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 date-time when the artifact was written to the local cache." + }, + "platform": { + "type": ["string", "null"], + "enum": [ + "apple-silicon-asahi", + "generic-uefi", + "generic-bios", + null + ], + "description": "Target platform this artifact is intended for, or null if platform-agnostic." + }, + "sourceUrl": { + "type": ["string", "null"], + "description": "URL from which the artifact was originally fetched, if applicable." + }, + "sourceRef": { + "type": ["string", "null"], + "description": "Optional URN reference to the release set or manifest that produced this artifact." + }, + "sizeBytes": { + "type": ["integer", "null"], + "minimum": 0, + "description": "Size of the cached artifact in bytes." + }, + "expiresAt": { + "type": ["string", "null"], + "format": "date-time", + "description": "Optional ISO 8601 date-time after which this cache entry may be evicted." + }, + "notes": { + "type": ["string", "null"], + "description": "Optional human-readable notes about this cache entry." + } + } +} diff --git a/schemas/BootProofRecord.json b/schemas/BootProofRecord.json new file mode 100644 index 0000000..ccf4348 --- /dev/null +++ b/schemas/BootProofRecord.json @@ -0,0 +1,116 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/BootProofRecord.json", + "title": "BootProofRecord", + "description": "An immutable record proving the integrity and outcome of an NLBoot boot execution, linking the boot plan, per-stage evidence, and attestation refs.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "bootPlanRef", + "deviceRef", + "outcome", + "bootedAt" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:boot-proof:[A-Za-z0-9._~-]+$", + "description": "Stable URN identifier. Pattern: urn:srcos:boot-proof:" + }, + "type": { + "const": "BootProofRecord", + "description": "Discriminator constant — always \"BootProofRecord\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "bootPlanRef": { + "type": "string", + "description": "URN reference to the NLBootPlan that was executed." + }, + "deviceRef": { + "type": "string", + "description": "URN reference to the physical device or asset on which the boot occurred." + }, + "outcome": { + "type": "string", + "enum": [ + "success", + "partial", + "failure", + "aborted" + ], + "description": "Overall outcome of the boot execution." + }, + "bootedAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 date-time when the boot was initiated." + }, + "stageProofs": { + "type": "array", + "description": "Per-stage proof items recording the artifact executed and verification verdict for each stage.", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "stageName", + "artifactRef", + "contentHash", + "verdict" + ], + "properties": { + "stageName": { + "type": "string", + "description": "Name of the boot stage, matching the stage name in the referenced NLBootPlan." + }, + "artifactRef": { + "type": "string", + "description": "URN reference to the artifact that was loaded for this stage." + }, + "contentHash": { + "type": "string", + "description": "Actual content digest observed at execution time, e.g. \"sha256:...\"." + }, + "verdict": { + "type": "string", + "enum": [ + "verified", + "skipped", + "failed", + "tampered" + ], + "description": "Verification verdict for this stage." + }, + "notes": { + "type": ["string", "null"], + "description": "Optional diagnostic notes for this stage." + } + } + } + }, + "evidenceRefs": { + "type": "array", + "items": { + "type": "string" + }, + "description": "URN references to AttestationEvidence objects captured during this boot." + }, + "policyDecisionRef": { + "type": ["string", "null"], + "description": "Optional URN reference to the PolicyDecision that authorized this boot." + }, + "signature": { + "type": ["string", "null"], + "description": "Optional cryptographic signature over the serialized proof record." + }, + "notes": { + "type": ["string", "null"], + "description": "Optional human-readable notes about this boot proof." + } + } +} diff --git a/schemas/NLBootPlan.json b/schemas/NLBootPlan.json new file mode 100644 index 0000000..059c0c5 --- /dev/null +++ b/schemas/NLBootPlan.json @@ -0,0 +1,114 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/NLBootPlan.json", + "title": "NLBootPlan", + "description": "An NLBoot boot plan describing the ordered sequence of boot stages, artifact references, and verification policy for a target device.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "targetDeviceRef", + "platform", + "status", + "stages", + "createdAt" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:nlboot-plan:[A-Za-z0-9._~-]+$", + "description": "Stable URN identifier. Pattern: urn:srcos:nlboot-plan:" + }, + "type": { + "const": "NLBootPlan", + "description": "Discriminator constant — always \"NLBootPlan\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "targetDeviceRef": { + "type": "string", + "description": "URN reference to the physical device or asset this plan targets." + }, + "platform": { + "type": "string", + "enum": [ + "apple-silicon-asahi", + "generic-uefi", + "generic-bios" + ], + "description": "Target platform type that determines bootloader selection and stage ordering." + }, + "status": { + "type": "string", + "enum": [ + "draft", + "active", + "superseded", + "revoked" + ], + "description": "Lifecycle state of the boot plan." + }, + "stages": { + "type": "array", + "minItems": 1, + "description": "Ordered list of boot stages that must be executed to complete the boot sequence.", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "artifactRef", + "contentHash" + ], + "properties": { + "name": { + "type": "string", + "description": "Human-readable stage name, e.g. \"m1n1\", \"u-boot\", \"kernel\"." + }, + "artifactRef": { + "type": "string", + "description": "URN reference to the stage artifact in the artifact cache or release set." + }, + "contentHash": { + "type": "string", + "description": "Content-addressed digest of the stage artifact, e.g. \"sha256:...\"." + }, + "verificationRequired": { + "type": "boolean", + "description": "When true, the boot executor must verify the digest before executing this stage." + }, + "notes": { + "type": ["string", "null"], + "description": "Optional human-readable notes for this stage." + } + } + } + }, + "bootReleaseSetRef": { + "type": ["string", "null"], + "description": "Optional URN reference to the BootReleaseSet that sourced the artifacts for this plan." + }, + "policyRef": { + "type": ["string", "null"], + "description": "Optional URN reference to the policy that governs execution of this boot plan." + }, + "activatedAt": { + "type": ["string", "null"], + "format": "date-time", + "description": "ISO 8601 date-time when this plan was activated on the target device." + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 date-time when this boot plan was created." + }, + "notes": { + "type": ["string", "null"], + "description": "Optional human-readable notes about this boot plan." + } + } +} diff --git a/schemas/README.md b/schemas/README.md index daef0a7..7bd7bb9 100644 --- a/schemas/README.md +++ b/schemas/README.md @@ -54,7 +54,10 @@ These types support: |------|------|-----------| | `AgentSession.json` | AgentSession | `urn:srcos:session:` | | `Agreement.json` | Agreement | `urn:srcos:agreement:` | +| `AppleSiliconAdapterEvidence.json` | AppleSiliconAdapterEvidence | `urn:srcos:as-adapter-evidence:` | +| `ArtifactCacheRecord.json` | ArtifactCacheRecord | `urn:srcos:artifact-cache:` | | `AuthorityLink.json` | AuthorityLink | _(sub-object, no top-level id)_ | +| `BootProofRecord.json` | BootProofRecord | `urn:srcos:boot-proof:` | | `CapabilityToken.json` | CapabilityToken | _(plain `tokenId` string)_ | | `Comment.json` | Comment | `urn:srcos:comment:` | | `Community.json` | Community | `urn:srcos:community:` | @@ -80,6 +83,7 @@ These types support: | `MappingEvidence.json` | MappingEvidence | _(sub-object inside MappingSpec)_ | | `MappingSpec.json` | MappingSpec | `urn:srcos:mapping:` | | `MemoryEntry.json` | MemoryEntry | `urn:srcos:memory:` | +| `NLBootPlan.json` | NLBootPlan | `urn:srcos:nlboot-plan:` | | `ObjectContext.json` | ObjectContext | _(sub-object, no id)_ | | `ObjectSelector.json` | ObjectSelector | _(sub-object inside Policy scope)_ | | `Obligation.json` | Obligation | _(sub-object, no id)_ | @@ -234,6 +238,15 @@ These types support: | `RolloutPolicy` | Audience-based percentage rollout rules for an `ExperimentFlag` | | `ReleaseReceipt` | A verified release record with artifact hashes and gate check results | +### Boot / NLBoot + +| Schema | Description | +|--------|-------------| +| `NLBootPlan` | An NLBoot boot plan describing ordered stages, artifact refs, and verification policy for a device | +| `ArtifactCacheRecord` | A content-addressed cache entry for a locally-stored NLBoot artifact with origin, digest, and status | +| `BootProofRecord` | An immutable record proving boot integrity: plan ref, per-stage verdicts, and attestation evidence refs | +| `AppleSiliconAdapterEvidence` | Evidence from the Asahi-compatible Apple Silicon boot adapter: chip identity, security policy, and boot-chain hashes | + ### Fog Layer | Schema | Description | diff --git a/semantic/hydra.jsonld b/semantic/hydra.jsonld index cb04800..66a4d7b 100644 --- a/semantic/hydra.jsonld +++ b/semantic/hydra.jsonld @@ -61,6 +61,10 @@ "WorkflowNode": "srcos:WorkflowNode", "WorkflowSpec": "srcos:WorkflowSpec", "WorkloadSpec": "srcos:WorkloadSpec", + "NLBootPlan": "srcos:NLBootPlan", + "ArtifactCacheRecord": "srcos:ArtifactCacheRecord", + "BootProofRecord": "srcos:BootProofRecord", + "AppleSiliconAdapterEvidence": "srcos:AppleSiliconAdapterEvidence", "wasGeneratedBy": { "@id": "prov:wasGeneratedBy", "@type": "@id" }, "used": { "@id": "prov:used", "@type": "@id" }, @@ -242,6 +246,38 @@ "hydra:supportedOperation": [ { "hydra:method": "POST", "hydra:title": "recordSessionReceipt", "hydra:description": "Records a SessionReceipt." } ] + }, + { + "@id": "srcos:NLBootPlan", + "hydra:title": "NLBootPlan", + "hydra:description": "An NLBoot boot plan describing ordered boot stages, artifact refs, and verification policy for a target device.", + "hydra:supportedOperation": [ + { "hydra:method": "POST", "hydra:title": "upsertNLBootPlan", "hydra:description": "Creates or updates an NLBootPlan." } + ] + }, + { + "@id": "srcos:ArtifactCacheRecord", + "hydra:title": "ArtifactCacheRecord", + "hydra:description": "A content-addressed cache entry for a locally-stored NLBoot artifact.", + "hydra:supportedOperation": [ + { "hydra:method": "POST", "hydra:title": "upsertArtifactCacheRecord", "hydra:description": "Creates or updates an ArtifactCacheRecord." } + ] + }, + { + "@id": "srcos:BootProofRecord", + "hydra:title": "BootProofRecord", + "hydra:description": "An immutable record proving boot integrity with per-stage verdicts and attestation evidence refs.", + "hydra:supportedOperation": [ + { "hydra:method": "POST", "hydra:title": "recordBootProof", "hydra:description": "Persists a BootProofRecord." } + ] + }, + { + "@id": "srcos:AppleSiliconAdapterEvidence", + "hydra:title": "AppleSiliconAdapterEvidence", + "hydra:description": "Evidence from the Asahi-compatible Apple Silicon boot adapter capturing chip identity, security policy, and boot-chain hashes.", + "hydra:supportedOperation": [ + { "hydra:method": "POST", "hydra:title": "recordAppleSiliconAdapterEvidence", "hydra:description": "Persists an AppleSiliconAdapterEvidence record." } + ] } ] } diff --git a/tools/validate_nlboot_examples.py b/tools/validate_nlboot_examples.py new file mode 100644 index 0000000..b5dea80 --- /dev/null +++ b/tools/validate_nlboot_examples.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +"""Validate NLBoot schema/example pairs.""" +from __future__ import annotations + +import json +from pathlib import Path + +import jsonschema + +ROOT = Path(__file__).resolve().parents[1] +PAIRS = [ + (ROOT / "schemas" / "NLBootPlan.json", ROOT / "examples" / "nlboot_plan.json"), + (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"), +] + + +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) + example = json.loads(example_path.read_text(encoding="utf-8")) + jsonschema.validate(example, schema) + + +def main() -> int: + checks: dict[str, bool] = {} + for schema_path, example_path in PAIRS: + validate_pair(schema_path, example_path) + checks[example_path.name] = True + print(json.dumps({"ok": all(checks.values()), "checks": checks}, indent=2, sort_keys=True)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())