stagex/repros
14
4
Fork
You've already forked repros
2
A deterministic, minimal, immutable, and security-focused Linux distribution specifically designed for reproducing builds of software containers.
  • Shell 66.8%
  • Dockerfile 28%
  • Makefile 5.2%
2026年06月07日 16:02:48 -07:00
.repros Format .repros/config.yml correctly 2025年02月10日 14:35:39 -08:00
dist dist/: reproduced repros and committing first repro'd digest 2025年02月10日 14:35:49 -08:00
src bump guest kernel 2026年05月27日 11:44:48 -07:00
.editorconfig feat: add .editorconfig 2025年06月24日 03:41:19 -07:00
.gitignore Working end to end local/baremetal boot w/ guest 2024年10月01日 20:03:09 -07:00
Makefile harden ReprOS build VM startup and logging 2026年05月06日 18:32:54 -07:00
README.md Adding release procedure to README 2025年02月10日 14:35:50 -08:00

ReprOS

git://codeberg.org:stagex/repros | matrix://#stagex:matrix.org | ircs://irc.oftc.net:6697#stagex


A deterministic, minimal, immutable, and security-focused Linux distribution specifically designed for reproducing builds of software containers.

It functions as a standalone Git Remote you (or a CI system of your choice) can push to. A Git Post-Receive hook then spins up a one-time-use Virtual Machine and proceeds to run your desired build commands inside that VM. Hashes of any resulting artifacts are passed back to the host OS where they will be signed with a private key held in an attached smartcard.

This means theoretically the only attack surface is the Hypervisor (qemu), OpenSSH, and Git. These are things that rarely need to be updated for security issues that could impact this use case, allowing ReprOS servers to be very low maintenance.

Building

  1. Reproduce the latest ReprOS release
make reproduce
  1. Add your ssh public key(s) to the "config" directory
mkdir -p config/ssh
ssh-add -L > config/ssh/authorized_keys
  1. Shallow rebuild ReprOS image to include your public keys
make

Installation

You will want to choose one of the following paths depending on if you have physical access to your system, or it is a remote dedicated server.

Local

  1. Write ReprOS to an SD card
dd if=out/repros.img of=/dev/mmcblk0 bs=1M conv=fsync status=progress
  1. (Optional) Permanently Write Protect the SD Card with sdtool
sdtool permlock /dev/mmcblk0
  1. Boot SD card on build server and obtain IP address from network

Note: Not all hardware supports boot from SD card, and a USB-to-SD adapter

Remote

  1. Boot target server to vendor supplied "rescue" live-boot image

    This process will vary wildly from one provider to the next so seek out their documentation for this.

    Generally there will be some option in the administration panel to boot to a predefined rescue image, or else there may be a KVM-over-IP service that allows you to specify an ISO image of your choosing to live-boot from.

  2. Transfer repros image to remote server

scp out/repros.img root@${SERVER_IP}:
  1. Identify primary boot disk on remote server
ssh root@${SERVER_IP} lsblk
  1. Install repros to primary boot disk
ssh root@${SERVER_IP} "dd if=repros.img of=/dev/${BOOT_DISK} conv=fsync status=progress"
  1. Reboot remote machine into repros

Note: be sure to manually disable any "rescue mode" if not done automatically

ssh root@${SERVER_IP} reboot

Usage

  1. Verify connectivity
ssh git@${SERVER_IP} uptime
  1. Test ReprOS by reproducing ReprOS itself
git remote add repros git@${SERVER_IP}:repros
git push repros main
  1. Test ReprOS with your own repository

Note: be sure to adjust config to your actual needs!

cd target-repo
mkdir .repros
echo <<-EOF > .repros/config.yml
 build:
 command: make
 sign:
 files:
 - out/some_binary
 format: raw
 method: ssh
 storage:
 method: git
 location: git@codeberg.org:some-org/repros-sigs.git
 path: /project-name
EOF
git remote add repros git@${SERVER_IP}:repros
git push repros main

Additional Commands & Git Flow

This section describes extra commands you can run on the ReprOS host beyond just pushing code. It also explains how the Git commands trigger the ephemeral build process.

SSH Key Management

Add a key

ssh git@${SERVER_IP} ssh_key_add "<SSH-PUBLIC-KEY-LINE>"

Verifies the key is valid, then appends it to the authorized_keys file in /config/ssh/.

Delete a key

ssh git@${SERVER_IP} ssh_key_del <search_term>

Removes lines from authorized_keys that match <search_term>.

List keys

ssh git@${SERVER_IP} ssh_key_list

Shows both the local public keys in /config/ssh/*.pub and the authorized keys in /config/ssh/authorized_keys.

System & Health Commands

Health Check

ssh git@${SERVER_IP} health

Returns success if ReprOS is up and accepting commands.

Uptime

ssh git@${SERVER_IP} uptime

Shows the system's current uptime.

Reboot

ssh git@${SERVER_IP} reboot

Forces an immediate reboot of the ReprOS host.

Unlock

ssh git@${SERVER_IP} unlock

Removes the /home/git/repros.lock file (in case a build was interrupted and left the system locked).

VM Controls

VM Reset

ssh git@${SERVER_IP} vm_reset

Sends a system_reset command to the ephemeral VM via the QEMU monitor.

VM Status

ssh git@${SERVER_IP} vm_status

Displays the QEMU monitor status (info status) and attempts to run uptime in the guest VM (ssh root@guest uptime) for a quick health check.

Git Flow

When you run git push to ReprOS (using git@${SERVER_IP}:<repo>), the following happens:

  1. Lock is set
    A lock file (/home/git/repros.lock) is created to prevent overlapping builds.

  2. Repo setup on the guest VM
    ReprOS uses git-receive-pack or git-upload-pack inside the VM to handle the incoming push.

  3. Build commands
    The .repros/config.yml file in your repo tells ReprOS what build steps to run (build.command).

  4. Signing
    If .repros/config.yml specifies signing (sign.method: ssh), ReprOS will sign the artifacts using a private key stored on the host.

  5. Artifact storage
    If .repros/config.yml specifies a storage.method (e.g., git), ReprOS can push signatures or artifacts to another Git repo (or a different backend).

  6. VM reset/cleanup
    Once the build is done, the VM can be reset or destroyed. The environment is ephemeral, ensuring each build is isolated.

ReprOS Release Flow

Below is a suggested sequence for creating a new ReprOS release, verifying it, and then having multiple people reproduce it (including installing and testing on actual ReprOS nodes).


1. Create a Release Locally

  1. Generate Release Artifacts
make release

This typically cleans your out/ directory, rebuilds repros.img, and writes manifest.txt/release.env to dist/.

  1. Commit the Final dist/ Files
git add dist/manifest.txt dist/release.env
git commit -m "Add final manifest and release.env for new release"
git push origin <your-branch>

2. Verify with make reproduce

  1. Anyone (including you) pulls down your branch
git fetch origin <your-branch>
git checkout <your-branch>
  1. Run the Reproducibility Check
make reproduce

This re-builds repros.img from scratch and compares the resulting hash against dist/manifest.txt. If they match, the release is confirmed reproducible for that commit.

3. Prepare to Install & Push to a ReprOS Node

  1. Add Your SSH Key If you want your newly built image to include your key for testing:
mkdir -p config/ssh
ssh-add -L >> config/ssh/authorized_keys

Then run a shallow build (or just make) to incorporate that into repros.img. 2. Follow the Installation Instructions Above

4. Use Repros to Build Itself

  1. Create a .repros/config.yml
    In your local repo, point to the offical signature store (e.g., a Git repo of signatures) and reference the final artifact you want to sign. You will have to add your SSH key as a deploy key to the repo.
cd target-repo
mkdir .repros
echo <<-EOF > .repros/config.yml
 build:
 command: make
 sign:
 files:
 - out/some_binary
 format: raw
 method: ssh
 storage:
 method: git
 location: git@codeberg.org:some-org/repros-sigs.git
 path: /project-name
EOF
git remote add repros git@${SERVER_IP}:repros
git push repros main

If there are multiple signatures under the same commit/sign-file-hash directory, we can merge the release branch!

Sponsors