Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

nex

I'm doing a (free) reproducible build system/distro (just a hobby, won't be big and professional like Guix or Nix) for Linux.

Jokes aside: I love the idea of an immutable, reproducible OS, but not the "strange" build/configuration languages that come with Nix and Guix. Build scripts are yaml and shell here. I also don't buy the Holy Full Source Bootstrap and its 357-byte root program: whatever route you take, you end up trusting the source of the normal GNU toolchain, so nex bootstraps from whatever host toolchain you have and rebuilds it with itself until the outputs converge to host-independent checksums. Converge from N diverse hosts (different compilers, versions, distros) and a trusting-trust backdoor would need to survive every lineage and produce identical poisoned bytes from all of them. No binary is trusted that N diverse lineages did not independently reproduce. Same trust boundary, minus years of ceremony.

A package

package:
  slug: libxcrypt
  namespace: libs/system
  version: 4.4.37
  checksum: sha256:fb8aece…      # written by tooling, sealed at merge

sources:
- url: https://…/libxcrypt-4.4.37.tar.xz
  sha256: 8a5f42a3…

dependencies:
- manifest: blob:3f2a91c…        # git blob ID = the dependency's identity
  path: pkg/libs/system/glibc.yaml
  use: bundle:dev

build:
  environment: blob:88c02e…
  script: |
    ./configure --prefix=/usr
    make && make DESTDIR="${OUT_DIR}" install

The repo is git (SHA-256 object format). A manifest's identity is its blob; since a dependency's blob covers its dependencies' blobs, a manifest transitively pins its entire input closure down to the bootstrap. The checksum binds that closure to the build's output:

plan     = H(manifest without the checksum field)     # computable before building
checksum = H(plan ‖ output)                           # same checksum ⇒ same build, forever

Maintainer builds locally and commits the checksum; CI rebuilds and must reproduce it. Merge is the seal: every merge is a two-builder reproducibility proof, and git history is the trust root. Binary stores (zub, think ostree for build outputs) are untrusted caches:

$ nex build pkg/libs/system/libxcrypt.yaml    # no cache? same bytes, built locally

A system

assembly:
  slug: nex-systemd
  checksum: sha256:0be371…       # H(plan ‖ boot tree hash): same model, sealed the same way

members:
- manifest: blob:9dd1c04…
  path: pkg/core/init/systemd.yaml
  use: bundle:minimal

substitutions:                    # CVE fix under existing binaries, no world rebuild
- needs: /usr/lib/libcrypt.so.2
  manifest: blob:aa02f1…
  reason: NEX-SA-2026-1143
  evidence: [claim:sha256:e3ab90…]

An assembly is a manifest one level up: compose instead of compile. Installed closures are capsules, hard-linked trees from the store: shared files stored once, two versions of one library coexisting in different trees. Every "runs against something it wasn't built against" edge is evidence-gated and auditable. Embedded targets flatten to a single rootfs image, a pure function of the assembly's blob:

$ nex compose assemblies/nex-systemd.yaml && nex deploy    # atomic swap, old tree kept

Status

Early; the spec is further along than the code. Bootstrap converges to identical checksums on my machine and a VM. That's N=2; the plan is for N to grow until the claim above means something.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages