OXYGENHUB
# cd008acc4eb2 oxygenflow / docs / spec.md
15.4 KiB · Markdown · last changed The specification, renamed from Xenon to OxygenFlow (.flow/pipeline.kdl, flow/provenance/v1, flow-casfs), and a README 1 month ago renderedsource blame history raw
a083cc80 Andy McCall ↶ 1
# OxygenFlow (flow) — Deterministic Execution & Provenance Pipeline Specification
2
3
| | |
4
|---|---|
5
| **Format version** | 1 |
6
| **Date** | 2026-09-28 |
7
| **Status** | Draft 0.1 |
8
| **Target VCS** | Oxygen (oxy) Draft 0.8i |
9
| **Audience** | Implementers, Security Architects, and Systems Engineers |
10
11
12
The key words MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY are to be
13
interpreted as described in RFC 2119.
14
15
## 1. Overview and Core Invariants
16
17
OxygenFlow (flow) is a content-addressed, hermetic execution engine, runner system,
18
and pipeline language designed natively for the Oxygen (oxy) version control
19
system.
20
21
Existing runner engines (GitHub Actions, GitLab CI, Forgejo Runner) suffer from
22
structural flaws:
23
1. Workspace Bloat: Full clones, index unpacks, and checkout scans dominate I/O.
24
2. String Injection: Shell interpolation within untyped YAML files produces
25
   expression injection and command execution exploits.
26
3. Decoupled Supply Chain: Attestations (SLSA, in-toto, Cosign) exist outside
27
   the VCS, relying on external registries rather than native repository trust.
28
4. Coarse Caching: Opaque tarballs keyed by arbitrary string hashes fail to
29
   leverage commutative history or granular dependency graphs.
30
31
OxygenFlow solves these liabilities through direct integration with Oxygen:
32
- Zero-Copy Workspaces: Jobs mount workspaces directly from Oxygen's FastCDC-
33
  chunked, BLAKE3-addressed Content-Addressable Store (CAS) using Copy-on-Write
34
  (COW) overlays.
35
- Commutative History & Impact Trees: Pipelines evaluate over change closures
36
  rather than linear snapshot sequences. Commuting changes automatically reuse
37
  cached execution receipts without redundant re-execution.
38
- Micro-Engine Sandboxing: Jobs run inside isolated environments (WASM, gVisor,
39
  or MicroVMs) with strict, deny-by-default capabilities and no ambient
40
  network egress.
41
- Native Cryptographic Provenance: Provenance and execution receipts are
42
  generated outside the untrusted guest, encoded as deterministic CBOR, and
43
  signed using composite Ed25519 + ML-DSA-65 keys as native Oxygen Attest
44
  objects governed by in-repository Policy rules.
45
46
## 2. Threat Model and Security Architecture
47
48
### 2.1 Adversaries
49
- Untrusted Proposal Author: Submits code to an open repository containing
50
  malicious build configurations intended to escape the runner, exfiltrate
51
  secrets, or corrupt shared worker caches.
52
- Malicious Dependency / Upstream: Third-party dependencies invoked during
53
  build time attempting out-of-band network calls or host file modification.
54
- Compromised Runner / Malicious Worker: An execution node attempting to
55
  forge successful build receipts or inject backdoors into published artifacts.
56
57
### 2.2 Security Invariants
58
- I1 Deny-by-Default Execution: Sandboxes possess no network interfaces
59
  (excluding loopback when requested) and no host filesystem access unless
60
  explicitly granted in policy-signed configuration.
61
- I2 Injection-Free Invocation: Configuration parsing directly yields an argv
62
  string vector executed via execve(). Shell interpretation (/bin/sh -c) does
63
  not exist.
64
- I3 Host-Enforced Provenance: The running payload cannot author, inspect, or
65
  alter its own provenance statement. Provenance is emitted solely by the
66
  isolation hypervisor boundary.
67
- I4 Cryptographic Identity & Authorization: Runners execute using an Oxygen
68
  Identity whose KeyId is enrolled as a delegate in the repository's Policy.
69
  Unenrolled runners cannot publish recognized attestations or advance gates.
70
71
## 3. The OxygenFlow Configuration Language (.flow)
72
73
Pipelines are declared in KDL syntax within .flow/pipeline.kdl at the
74
repository root. KDL provides strict typing, structured nesting, and rejects
75
arbitrary text macro expansion.
76
77
### 3.1 Pipeline Specification Schema
78
79
```kdl
80
schema-version 1
81
82
// Define the hermetic execution boundary
83
sandbox "rust-builder" {
84
    runtime "microvm"       // Options: "wasm" | "gvisor" | "microvm"
85
    rootfs "cas://blob/9b5c2a1e8f3d4e7a6b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a"
86
    memory-limit "4GiB"
87
    cpu-limit 4
88
    network "isolated"      // Options: "isolated" | "loopback" | "egress"
89
}
90
91
// Job evaluated based on Oxygen change closure
92
job "compile-core" {
93
    sandbox "rust-builder"
94
95
    // Commutation boundary: runs only if change closure touches these paths
96
    scope "crates/oxy-core/**" "crates/oxy-server/**" "Cargo.*"
97
98
    // Zero-copy workspace mount backed by Oxygen CAS
99
    mount {
100
        source "oxy://workspace"
101
        target "/src"
102
        include "crates/oxy-core" "crates/oxy-server" "Cargo.toml" "Cargo.lock"
103
        readonly #true
104
    }
105
106
    // Ephemeral scratch space
107
    mount {
108
        source "ephemeral://tmpfs"
109
        target "/src/target"
110
        size "8GiB"
111
    }
112
113
    env {
114
        RUSTFLAGS "-Dwarnings"
115
        CARGO_INCREMENTAL "0"
116
    }
117
118
    // Direct argv execution vector (no subshell)
119
    exec "cargo" "build" "--release" "--package" "oxy-core"
120
121
    output {
122
        artifact "oxy-core-lib" {
123
            path "/src/target/release/liboxy_core.rlib"
124
            format "blob"
125
        }
126
    }
127
}
128
129
job "unit-tests" {
130
    sandbox "rust-builder"
131
    depends-on "compile-core"
132
133
    mount {
134
        source "oxy://workspace"
135
        target "/src"
136
        readonly #true
137
    }
138
139
    mount {
140
        source "artifact://compile-core/oxy-core-lib"
141
        target "/src/target/release/liboxy_core.rlib"
142
    }
143
144
    exec "cargo" "test" "--release" "--package" "oxy-core"
145
}
146
147
publish "release-provenance" {
148
    depends-on "unit-tests"
149
150
    attest {
151
        kind "provenance"
152
        bind-ref "bookmarks/main"
153
        include-artifacts "compile-core/oxy-core-lib"
154
    }
155
}
156
157
158
### 3.2 Canonical Compilation
159
Upon commit, .flow/pipeline.kdl is validated and compiled into a deterministic
160
CBOR job-graph blob. Runners evaluate the canonical CBOR to prevent syntax or
161
parser ambiguities across varying client platforms.
162
163
## 4. Sandbox Execution Engine
164
165
OxygenFlow implements three distinct isolation tiers depending on the workload:
166
167
### 4.1 Level 0: WASM Component Sandbox
168
- Intended for static linters, formatters, doc generators, and policy checks.
169
- Runs on a standard WebAssembly System Interface (WASI) runtime.
170
- Startup latency: < 5 ms.
171
- Zero host I/O; virtualized file system presented in-memory.
172
173
### 4.2 Level 1: Intercepted Syscall Isolation (gVisor / Landlock + seccomp-bpf)
174
- Intended for standard compilation and hermetic test suites.
175
- Emulates or filters Linux system call interfaces in user space.
176
- Blocks access to raw network sockets, real-time hardware clocks, and device
177
  nodes.
178
- Memory and execution CPU quotas are strictly bounded via cgroups v2.
179
180
### 4.3 Level 2: MicroVM Isolation (Firecracker / Cloud-Hypervisor)
181
- Intended for kernel tests, multi-container integration, and untrusted code.
182
- Ephemeral Linux microVM booting in < 80 ms.
183
- The root filesystem is presented as a read-only virtio-block device mapped
184
  directly to FastCDC chunks stored in Oxygen's CAS.
185
- Guest VM memory is cleared upon termination.
186
187
## 5. Content-Addressable Storage (CAS) & Zero-Copy Mounting
188
189
OxygenFlow runners bypass traditional clone operations. Repositories are accessed
190
directly via the local object store (.oxy/objects/) or streamed on demand
191
using Oxygen's wire protocol.
192
193
### 5.1 FUSE Overlay Mounting (flow-casfs)
194
1. The runner receives a task targeting an Oxygen State ObjectRef (a sorted
195
   list of maximal heads).
196
2. The nearest Checkpoint is resolved. Uncommitted changes between the
197
   checkpoint and heads are replayed into a virtual tree in-memory.
198
3. The virtual tree is exposed to the sandbox via flow-casfs:
199
   - File reads resolve chunks using the FastCDC gear table (32 KiB to 256 KiB,
200
     mean 64 KiB) pinned in Oxygen Spec Section 13.2.
201
   - Missing chunks are fetched lazily using the POST /objects protocol.
202
   - To prevent FUSE context-switch bottlenecks on many small reads, flow-casfs aggressively mmaps chunk data and utilizes host page caching.
203
   - All guest mutations are diverted to a scratch tmpfs layer; base objects
204
     remain immutable.
205
206
### 5.2 Artifact Capture
207
1. At task completion, flow-casfs scans the paths declared in the output block.
208
2. Modified outputs are chunked with FastCDC, hashed via BLAKE3-256, and
209
   written as canonical Blob and Chunk objects.
210
3. Output ObjectRefs are stored directly in the Oxygen repository.
211
212
## 6. Commutative Execution & Change Caching
213
214
In Oxygen, changes that do not share scopes (referenced atoms, placements, or
215
nodes) commute. OxygenFlow exploits this invariant to provide granular caching.
216
217
### 6.1 Execution Receipt Object
218
Every successful or failed job run emits an immutable Receipt:
219
220
```cbor
221
Receipt {
222
  version        [0]: 1
223
  job_name       [1]: text
224
  pipeline_hash  [2]: ObjectRef
225
  scope_tree_hash [3]: ObjectRef     // BLAKE3 tree hash of the materialized scope
226
  inputs         [4]: [ObjectRef]   // Artifacts and input files consumed
227
  environment    [5]: ObjectRef     // Hash of rootfs, compiler flags, and argv
228
  outputs        [6]: [ObjectRef]   // Produced artifact blobs
229
  exit_code      [7]: u32
230
  duration_ms    [8]: u64
231
}
232
```
233
234
A Receipt is hashed as an Oxygen object with type name "receipt":
235
ObjectRef = BLAKE3-256("oxy1 receipt " || decimal(len) || 0x00 || body)
236
237
### 6.2 Cache Re-use Invariant
238
Let Scope(J) be the file paths and tree nodes declared by job J.
239
Because changes that do not share scopes commute, we do not need to track lists of ChangeHashes. Instead, we hash the materialized tree of Scope(J).
240
241
If an existing Receipt R exists such that:
242
  R.job_name == J.name &&
243
  R.pipeline_hash == Hash(J) &&
244
  R.scope_tree_hash == TreeHash(Scope(J)) &&
245
  R.environment == CurrentEnvironmentHash
246
247
Then the job execution is bypassed. R.outputs are mapped into downstream
248
dependents immediately as a cached-commuted hit.
249
250
## 7. Native Provenance Specification
251
252
OxygenFlow formalizes build provenance as a native, tamper-evident Oxygen Attest
253
object (kind: "attest"). Provenance is generated exclusively by the runner
254
hypervisor, not the guest payload.
255
256
### 7.1 Provenance Object Schema
257
258
```json
259
Attest {
260
  version [0]: 1
261
  kind    [1]: "attest"
262
  repo    [2]: bytes(16)               // Oxygen Repository ID
263
  hlc     [3]: HLC                     // Hybrid Logical Clock
264
  body    [4]: {
265
    "type": "flow/provenance/v1",
266
    
267
    // Subject artifacts produced by the build
268
    "subjects": [
269
      {
270
        "name": text,
271
        "ref": ObjectRef,              // BLAKE3 hash of output blob
272
        "media_type": text
273
      }
274
    ],
275
276
    // Builder platform and execution identity
277
    "builder": {
278
      "runner_id": KeyId,              // ObjectRef of runner's Oxygen Identity
279
      "isolation_level": text,         // "wasm" | "gvisor" | "microvm"
280
      "hypervisor_image": ObjectRef    // Rootfs blob digest
281
    },
282
283
    // Exact input materials
284
    "materials": {
285
      "state_heads": [ChangeHash],     // Oxygen heads of the state built
286
      "scope_tree_hash": ObjectRef,        // Captures exact state without O(N) array bloat
287
      "inputs": [
288
        {
289
          "name": text,
290
          "ref": ObjectRef             // Content hash of locked dependencies
291
        }
292
      ]
293
    },
294
295
    // Structured execution arguments
296
    "invocation": {
297
      "job": text,
298
      "pipeline_spec": ObjectRef,      // ObjectRef of .flow/pipeline.kdl
299
      "argv": [text],                  // Unmodified execution vector
300
      "env": map<text, text>           // Explicitly whitelisted environment
301
    },
302
303
    // Environment observations
304
    "metadata": {
305
      "started_on": u64,               // Wallclock milliseconds
306
      "finished_on": u64,
307
      "hermetic": bool,                // Verified zero outbound network access
308
      "reproducible": bool
309
    }
310
  }
311
}
312
```
313
314
### 7.2 Composite Signatures
315
All provenance attestations are signed using Oxygen's composite signature
316
construction (Ed25519 and ML-DSA-65):
317
318
```cbor
319
Signature {
320
  key [0]: KeyId
321
  alg [1]: 1                           // 1 = Ed25519 + ML-DSA-65
322
  ed  [2]: bytes(64)                   // Classical signature
323
  ml  [3]: bytes(3309)                 // Post-quantum signature
324
}
325
```
326
327
Both signatures are computed over:
328
  "oxy1 sig attest\0" || KeyId || ObjectRef
329
330
## 8. Policy Integration & Bookmark Gates
331
332
Oxygen repositories enforce branch and bookmark protections via signed Policy
333
objects (Oxygen Spec Section 14.5). OxygenFlow integrates provenance directly into
334
policy evaluation during push validation.
335
336
### 8.1 Policy Gate Definition
337
A Policy rule governing a bookmark MAY demand valid OxygenFlow attestations. To mitigate a compromised authorized worker, high-security repositories can require **Consensus Builds** by setting the threshold > 1. This requires multiple independent runner identities to arrive at the exact same output hashes and both sign it.
338
339
```json
340
PolicyRule {
341
  pattern: "bookmarks/production"
342
  keys: [ KeyId ]
343
  threshold: 1
344
  require: "signed"
345
  allow_conflicts: false
346
  require_attestations: [
347
    {
348
      type: "flow/provenance/v1",
349
      job: "release-provenance",
350
      require_hermetic: true,
351
      signer_roles: [ "official-worker" ]
352
    }
353
  ]
354
}
355
356
### 8.2 Push Verification Sequence (VCS Engine Enforcement)
357
When a push request arrives at an Oxygen server attempting to update a
358
protected bookmark:
359
1. Object Integrity: Validate that all changes, chunks, and blobs exist and match
360
   their BLAKE3 hashes.
361
2. Attestation Resolution: Verify that an Attest object of type
362
   "flow/provenance/v1" is present, referencing the exact heads of the new
363
   State.
364
3. Identity Verification: Validate that the attestation's composite signature
365
   resolves to a KeyId listed as an authorized delegate of the repository
366
   policy roots.
367
4. Invariant Checking: Confirm that the provenance statement records
368
   "hermetic: true" and exit code 0.
369
5. Atomic Update: If validation fails at any point, the entire push is refused
370
   with ok = false.
371
372
## 9. Zero-Environment Secret Brokering
373
374
OxygenFlow forbids the injection of raw secret strings into process environment
375
tables to eliminate accidental leaking via child process dumping, procfs
376
reads, and verbose compiler logging.
377
378
### 9.1 Ephemeral Secret Broker
379
1. If a job requires a credential (e.g., signing key, cloud deployment token),
380
   it declares a secret mount:
381
     secret "deploy-token" {
382
         vault-ref "infra/tokens/prod"
383
         mount-path "/run/secrets/token"
384
     }
385
2. The runner negotiates a short-lived token lease from the configured vault.
386
3. The secret is mounted onto an ephemeral, in-memory ramfs location inside
387
   the sandbox with access mode 0400, owned exclusively by the worker process.
388
4. Upon process termination, the memory pages are zeroized and the token is
389
   marked for immediate revocation at the vault.
390
391
## 10. Conformance and Verification Requirements
392
393
A conforming OxygenFlow implementation MUST pass the following tests:
394
395
1. Injection Immunity: Attempting to supply unescaped shell metacharacters
396
   (; && | ` $() \n) in any job field MUST pass those characters as literal
397
   bytes to argv; subshells MUST NOT be spawned.
398
2. FastCDC Determinism: Chunks produced by artifact extraction MUST match
399
   the gear table cuts and BLAKE3 hashes generated by Oxygen's core chunker.
400
3. Commutation Hit Invariance: For any two commuting changes A and B, running
401
   a pipeline on State(A, B) MUST reuse cached receipts generated on State(A)
402
   for any job whose scope does not intersect the touched paths of B.
403
4. Non-Downgrade Attestation: An attestation missing the ML-DSA-65 component
404
   MUST be rejected by policy verification.
405
5. Hermetic Network Isolation: Jobs configured with network "isolated" MUST
406
   have outgoing TCP SYN and UDP packets dropped at the hypervisor boundary.