Skip to content

Commit bc84e6e

Browse files
authored
Add NLBoot object schemas and examples
Adds canonical NLBoot schemas, examples, validation tooling, OpenAPI metadata, Hydra metadata, ADR, and catalog updates. Closes #68.
1 parent ab6d441 commit bc84e6e

16 files changed

Lines changed: 827 additions & 2 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). Thi
99
## [Unreleased]
1010

1111
### Added
12+
- NLBoot object schemas: `NLBootPlan`, `ArtifactCacheRecord`, `BootProofRecord`, `AppleSiliconAdapterEvidence` with canonical examples and validation (`tools/validate_nlboot_examples.py`)
1213
- Compression Commons: `CompressionEvaluation` schema and canonical example (`examples/compressionevaluation.json`)
1314
- Truth Plane: `TruthSurface` and `DeltaSurface` schemas + canonical examples (`examples/truth_surface.json`, `examples/delta_surface.json`)
1415
- Control-plane: `IncidentEvent` schema for incident lifecycle events

Makefile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
.PHONY: validate validate-control-plane-examples
1+
.PHONY: validate validate-control-plane-examples validate-nlboot-examples
22

3-
validate: validate-control-plane-examples
3+
validate: validate-control-plane-examples validate-nlboot-examples
44
@echo "OK: validate"
55

66
validate-control-plane-examples:
77
python3 -m pip install --user jsonschema >/dev/null
88
python3 tools/validate_control_plane_examples.py
9+
10+
validate-nlboot-examples:
11+
python3 -m pip install --user jsonschema >/dev/null
12+
python3 tools/validate_nlboot_examples.py
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# ADR-0011: NLBoot Object Schemas
2+
3+
**Date:** 2026-04-30
4+
**Status:** `Accepted`
5+
**Deciders:** SourceOS-Linux/sourceos-spec maintainers
6+
7+
---
8+
9+
## Context
10+
11+
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.
12+
13+
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.
14+
15+
## Decision
16+
17+
Introduce four new top-level schemas in the Boot / NLBoot family:
18+
19+
| Schema | URN prefix | Purpose |
20+
|--------|-----------|---------|
21+
| `NLBootPlan` | `urn:srcos:nlboot-plan:` | Ordered boot stage plan for a target device |
22+
| `ArtifactCacheRecord` | `urn:srcos:artifact-cache:` | Content-addressed local artifact cache entry |
23+
| `BootProofRecord` | `urn:srcos:boot-proof:` | Immutable per-boot integrity proof with stage verdicts |
24+
| `AppleSiliconAdapterEvidence` | `urn:srcos:as-adapter-evidence:` | Asahi-compatible Apple Silicon adapter evidence |
25+
26+
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.
27+
28+
### Scope of this repository
29+
30+
This repository owns:
31+
- canonical JSON Schema definitions for the four types
32+
- conforming example payloads
33+
- validation tooling (`tools/validate_nlboot_examples.py`)
34+
35+
This repository does not own:
36+
- NLBoot runtime boot executor implementation (`SociOS-Linux/nlboot`)
37+
- Apple Silicon boot-chain implementation (`SociOS-Linux/asahi-u-boot`, `SociOS-Linux/asahi-installer`)
38+
- transport bindings or RPC protocol definitions
39+
40+
## Alternatives considered
41+
42+
| Alternative | Reason not chosen |
43+
|-------------|------------------|
44+
| Add schemas inside `schemas/control-plane/` | NLBoot objects are boot-plane contracts, not legacy control-plane objects; they belong at the top level |
45+
| Single merged `NLBootEvidence` schema covering all four concerns | Each concern has distinct required fields and lifecycle; splitting keeps schemas compact and independently consumable |
46+
| 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 |
47+
48+
## Consequences
49+
50+
### Positive
51+
52+
- downstream repos can reference canonical URN-typed NLBoot objects without re-inventing structure
53+
- boot plan, artifact cache, and proof record objects are independently versioned and independently consumable
54+
- Apple Silicon adapter evidence is first-class and auditable, not embedded in ad hoc implementation logs
55+
- all four schemas are immediately validated by `make validate-nlboot-examples`
56+
57+
### Constraints
58+
59+
- schemas are intentionally minimal at introduction; fields may be added additively in follow-on PRs
60+
- proof reporting endpoint binding (`policyDecisionRef`, `evidenceRefs`) is normative contract only; enforcement belongs in runtime repos
61+
62+
## References
63+
64+
- Issue: SourceOS-Linux/sourceos-spec — "Agent task: add NLBoot object schemas"
65+
- ADR-0008: Local-first release and enrollment contract family
66+
- ADR-2026-04: Contract vs Bootstrap Boundaries
67+
- `schemas/BootSurface.json` — related boot-surface schema
68+
- `schemas/AttestationEvidence.json` — measured-boot attestation evidence

examples/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,10 @@ These examples illustrate the shared object family used by SourceOS artifact bui
131131
| `access_profile.json` | AccessProfile | Access profile for SourceOS build operators and agentplane executor obligations |
132132
| `agreement.json` | Agreement | Default personal-data agreement |
133133
| `agent_session.json` | AgentSession | An executor session running the obfuscation workflow |
134+
| `apple_silicon_adapter_evidence.json` | AppleSiliconAdapterEvidence | Apple Silicon adapter evidence for an M2 device running SourceOS via Asahi |
135+
| `artifact_cache_record.json` | ArtifactCacheRecord | Cached Linux kernel artifact for the M2 demo device |
134136
| `asset.json` | PhysicalAsset | Lakehouse asset for curated health observations |
137+
| `boot_proof_record.json` | BootProofRecord | Verified boot proof for SourceOS M2 device via NLBoot Asahi path |
135138
| `boot_release_set.json` | BootReleaseSet | SourceOS Recovery Environment boot artifact set for secure recovery/provisioning |
136139
| `build_request.json` | BuildRequest | SourceOS Workstation build request with agentplane and Katello refs |
137140
| `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
157160
| `glossary.json` | GlossaryTerm | Glossary term for "Date of Birth" |
158161
| `mapping.json` | MappingSpec | A field mapping between two dataset fields |
159162
| `memory_entry.json` | MemoryEntry | A learned memory entry from an agent session |
163+
| `nlboot_plan.json` | NLBootPlan | NLBoot boot plan for SourceOS M2 demo device via Asahi path |
160164
| `offer.json` | Offer | FogCompute provider offer |
161165
| `overlay_bundle.json` | OverlayBundle | Customer branding overlay applied to the workstation flavor |
162166
| `policy.json` | Policy | Health export must be obfuscated |
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"id": "urn:srcos:as-adapter-evidence:m2-adapter-2026-04-30",
3+
"type": "AppleSiliconAdapterEvidence",
4+
"specVersion": "2.0.0",
5+
"deviceRef": "urn:srcos:asset:fedora-asahi-m2",
6+
"capturedAt": "2026-04-30T09:55:00Z",
7+
"chipModel": "M2",
8+
"boardId": "J413AP",
9+
"securityPolicy": "reduced-security",
10+
"localBootStatus": "ok",
11+
"adapterVersion": "0.4.0",
12+
"m1n1Version": "1.4.6",
13+
"uBootVersion": "2024.01-asahi-4",
14+
"bootChainHashes": {
15+
"m1n1": "sha256:7a38f2d1e4b9c3a5d6e8f0b2c4a6d8e0f2b4c6a8d0e2f4b6c8a0d2e4f6b8c0a2",
16+
"u-boot": "sha256:2b4d6f8a0c2e4f6b8a0c2e4f6b8a0c2e4f6b8a0c2e4f6b8a0c2e4f6b8a0c2e4f"
17+
},
18+
"bootPickerEntryRef": "urn:srcos:boot-entry:m2-demo-sourceos-asahi-installer",
19+
"installerDataRef": "urn:srcos:artifact:m2-demo-asahi-installer-data-sha256-3f9c1f44",
20+
"notes": "Apple Silicon adapter evidence for M2 MacBook Air running SourceOS via Asahi path."
21+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"id": "urn:srcos:artifact-cache:kernel-sha256-0f3b6d7f",
3+
"type": "ArtifactCacheRecord",
4+
"specVersion": "2.0.0",
5+
"artifactKind": "kernel",
6+
"contentHash": "sha256:0f3b6d7f1e2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c",
7+
"status": "cached",
8+
"cachedAt": "2026-04-29T18:00:00Z",
9+
"platform": "apple-silicon-asahi",
10+
"sourceUrl": "https://cdn.asahilinux.org/m2/kernel-6.8.0-asahi-20240415.tar.gz",
11+
"sourceRef": "urn:srcos:boot-release-set:m2-demo-recovery-2026-04-26",
12+
"sizeBytes": 12582912,
13+
"expiresAt": "2026-07-29T18:00:00Z",
14+
"notes": "Linux kernel 6.8 with Apple Silicon patches for the M2 demo device."
15+
}

examples/boot_proof_record.json

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"id": "urn:srcos:boot-proof:m2-sourceos-boot-2026-04-30",
3+
"type": "BootProofRecord",
4+
"specVersion": "2.0.0",
5+
"bootPlanRef": "urn:srcos:nlboot-plan:m2-sourceos-main-2026-04-30",
6+
"deviceRef": "urn:srcos:asset:fedora-asahi-m2",
7+
"outcome": "success",
8+
"bootedAt": "2026-04-30T10:00:00Z",
9+
"stageProofs": [
10+
{
11+
"stageName": "m1n1",
12+
"artifactRef": "urn:srcos:artifact-cache:m1n1-sha256-7a38f2d1",
13+
"contentHash": "sha256:7a38f2d1e4b9c3a5d6e8f0b2c4a6d8e0f2b4c6a8d0e2f4b6c8a0d2e4f6b8c0a2",
14+
"verdict": "verified",
15+
"notes": null
16+
},
17+
{
18+
"stageName": "u-boot",
19+
"artifactRef": "urn:srcos:artifact-cache:uboot-sha256-2b4d6f8a",
20+
"contentHash": "sha256:2b4d6f8a0c2e4f6b8a0c2e4f6b8a0c2e4f6b8a0c2e4f6b8a0c2e4f6b8a0c2e4f",
21+
"verdict": "verified",
22+
"notes": null
23+
},
24+
{
25+
"stageName": "kernel",
26+
"artifactRef": "urn:srcos:artifact-cache:kernel-sha256-0f3b6d7f",
27+
"contentHash": "sha256:0f3b6d7f1e2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c",
28+
"verdict": "verified",
29+
"notes": null
30+
},
31+
{
32+
"stageName": "initrd",
33+
"artifactRef": "urn:srcos:artifact-cache:initrd-sha256-08f4c82e",
34+
"contentHash": "sha256:08f4c82e9d0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
35+
"verdict": "verified",
36+
"notes": null
37+
}
38+
],
39+
"evidenceRefs": [
40+
"urn:srcos:attestation:m2-boot-evidence-2026-04-30"
41+
],
42+
"policyDecisionRef": "urn:srcos:decision:boot-m2-demo-v1-2026-04-30",
43+
"signature": null,
44+
"notes": "Successful verified boot of SourceOS on M2 demo device via NLBoot Asahi path."
45+
}

examples/nlboot_plan.json

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"id": "urn:srcos:nlboot-plan:m2-sourceos-main-2026-04-30",
3+
"type": "NLBootPlan",
4+
"specVersion": "2.0.0",
5+
"targetDeviceRef": "urn:srcos:asset:fedora-asahi-m2",
6+
"platform": "apple-silicon-asahi",
7+
"status": "active",
8+
"stages": [
9+
{
10+
"name": "m1n1",
11+
"artifactRef": "urn:srcos:artifact-cache:m1n1-sha256-7a38f2d1",
12+
"contentHash": "sha256:7a38f2d1e4b9c3a5d6e8f0b2c4a6d8e0f2b4c6a8d0e2f4b6c8a0d2e4f6b8c0a2",
13+
"verificationRequired": true,
14+
"notes": "Primary Apple Silicon stage-1 bootloader"
15+
},
16+
{
17+
"name": "u-boot",
18+
"artifactRef": "urn:srcos:artifact-cache:uboot-sha256-2b4d6f8a",
19+
"contentHash": "sha256:2b4d6f8a0c2e4f6b8a0c2e4f6b8a0c2e4f6b8a0c2e4f6b8a0c2e4f6b8a0c2e4f",
20+
"verificationRequired": true,
21+
"notes": "U-Boot stage for EFI handoff"
22+
},
23+
{
24+
"name": "kernel",
25+
"artifactRef": "urn:srcos:artifact-cache:kernel-sha256-0f3b6d7f",
26+
"contentHash": "sha256:0f3b6d7f1e2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c",
27+
"verificationRequired": true,
28+
"notes": "Linux kernel with Apple Silicon patches"
29+
},
30+
{
31+
"name": "initrd",
32+
"artifactRef": "urn:srcos:artifact-cache:initrd-sha256-08f4c82e",
33+
"contentHash": "sha256:08f4c82e9d0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
34+
"verificationRequired": true,
35+
"notes": "Initial ramdisk for early userspace"
36+
}
37+
],
38+
"bootReleaseSetRef": "urn:srcos:boot-release-set:m2-demo-recovery-2026-04-26",
39+
"policyRef": "urn:srcos:policy:boot-recovery-m2-demo-v1",
40+
"activatedAt": "2026-04-30T10:00:00Z",
41+
"createdAt": "2026-04-30T09:00:00Z",
42+
"notes": "Main boot plan for SourceOS M2 demo device using Asahi Linux path."
43+
}

openapi.yaml

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ tags:
3232
description: Workflows, runs, and provenance records
3333
- name: Collaboration
3434
description: Comments and ratings
35+
- name: Boot
36+
description: NLBoot plans, artifact cache, proof records, and Apple Silicon adapter evidence
3537

3638
components:
3739
securitySchemes:
@@ -524,3 +526,111 @@ paths:
524526
description: Request body is valid JSON but fails schema validation.
525527
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
526528

529+
530+
/v2/nlboot-plans:
531+
post:
532+
operationId: upsertNLBootPlan
533+
summary: Upsert an NLBootPlan
534+
description: Creates or updates an NLBoot boot plan describing ordered boot stages, artifact refs, and verification policy for a target device. Idempotent on `id`.
535+
tags: [Boot]
536+
requestBody:
537+
required: true
538+
content:
539+
application/json:
540+
schema: { $ref: './schemas/NLBootPlan.json' }
541+
responses:
542+
'200':
543+
description: NLBootPlan created or updated successfully.
544+
'400':
545+
description: Request body is malformed JSON.
546+
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
547+
'401':
548+
description: Missing or invalid authentication token.
549+
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
550+
'403':
551+
description: Authenticated subject is not permitted to upsert boot plans.
552+
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
553+
'422':
554+
description: Request body is valid JSON but fails schema validation.
555+
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
556+
557+
/v2/artifact-cache-records:
558+
post:
559+
operationId: upsertArtifactCacheRecord
560+
summary: Upsert an ArtifactCacheRecord
561+
description: Creates or updates a content-addressed cache entry for a locally-stored NLBoot artifact. Idempotent on `id`.
562+
tags: [Boot]
563+
requestBody:
564+
required: true
565+
content:
566+
application/json:
567+
schema: { $ref: './schemas/ArtifactCacheRecord.json' }
568+
responses:
569+
'200':
570+
description: ArtifactCacheRecord created or updated successfully.
571+
'400':
572+
description: Request body is malformed JSON.
573+
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
574+
'401':
575+
description: Missing or invalid authentication token.
576+
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
577+
'403':
578+
description: Authenticated subject is not permitted to upsert artifact cache records.
579+
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
580+
'422':
581+
description: Request body is valid JSON but fails schema validation.
582+
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
583+
584+
/v2/boot-proof-records:
585+
post:
586+
operationId: recordBootProof
587+
summary: Record a BootProofRecord
588+
description: Persists an immutable boot integrity proof record with per-stage verdicts and attestation evidence refs. Idempotent on `id`.
589+
tags: [Boot]
590+
requestBody:
591+
required: true
592+
content:
593+
application/json:
594+
schema: { $ref: './schemas/BootProofRecord.json' }
595+
responses:
596+
'200':
597+
description: BootProofRecord persisted successfully.
598+
'400':
599+
description: Request body is malformed JSON.
600+
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
601+
'401':
602+
description: Missing or invalid authentication token.
603+
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
604+
'403':
605+
description: Authenticated subject is not permitted to record boot proofs.
606+
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
607+
'422':
608+
description: Request body is valid JSON but fails schema validation.
609+
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
610+
611+
/v2/apple-silicon-adapter-evidence:
612+
post:
613+
operationId: recordAppleSiliconAdapterEvidence
614+
summary: Record AppleSiliconAdapterEvidence
615+
description: Persists evidence collected by the Asahi-compatible Apple Silicon boot adapter, capturing chip identity, security policy, and boot-chain hashes. Idempotent on `id`.
616+
tags: [Boot]
617+
requestBody:
618+
required: true
619+
content:
620+
application/json:
621+
schema: { $ref: './schemas/AppleSiliconAdapterEvidence.json' }
622+
responses:
623+
'200':
624+
description: AppleSiliconAdapterEvidence persisted successfully.
625+
'400':
626+
description: Request body is malformed JSON.
627+
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
628+
'401':
629+
description: Missing or invalid authentication token.
630+
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
631+
'403':
632+
description: Authenticated subject is not permitted to record Apple Silicon adapter evidence.
633+
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
634+
'422':
635+
description: Request body is valid JSON but fails schema validation.
636+
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }

0 commit comments

Comments
 (0)