- Shell 66.8%
- Dockerfile 28%
- Makefile 5.2%
| .repros | Format .repros/config.yml correctly | |
| dist | dist/: reproduced repros and committing first repro'd digest | |
| src | bump guest kernel | |
| .editorconfig | feat: add .editorconfig | |
| .gitignore | Working end to end local/baremetal boot w/ guest | |
| Makefile | harden ReprOS build VM startup and logging | |
| README.md | Adding release procedure to README | |
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
- Reproduce the latest ReprOS release
make reproduce
- Add your ssh public key(s) to the "config" directory
mkdir -p config/ssh
ssh-add -L > config/ssh/authorized_keys
- 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
- Write ReprOS to an SD card
dd if=out/repros.img of=/dev/mmcblk0 bs=1M conv=fsync status=progress
- (Optional) Permanently Write Protect the SD Card with
sdtool
sdtool permlock /dev/mmcblk0
- 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
-
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.
-
Transfer repros image to remote server
scp out/repros.img root@${SERVER_IP}:
- Identify primary boot disk on remote server
ssh root@${SERVER_IP} lsblk
- Install repros to primary boot disk
ssh root@${SERVER_IP} "dd if=repros.img of=/dev/${BOOT_DISK} conv=fsync status=progress"
- Reboot remote machine into repros
Note: be sure to manually disable any "rescue mode" if not done automatically
ssh root@${SERVER_IP} reboot
Usage
- Verify connectivity
ssh git@${SERVER_IP} uptime
- Test ReprOS by reproducing ReprOS itself
git remote add repros git@${SERVER_IP}:repros
git push repros main
- 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:
-
Lock is set
A lock file (/home/git/repros.lock) is created to prevent overlapping builds. -
Repo setup on the guest VM
ReprOS usesgit-receive-packorgit-upload-packinside the VM to handle the incoming push. -
Build commands
The.repros/config.ymlfile in your repo tells ReprOS what build steps to run (build.command). -
Signing
If.repros/config.ymlspecifies signing (sign.method: ssh), ReprOS will sign the artifacts using a private key stored on the host. -
Artifact storage
If.repros/config.ymlspecifies astorage.method(e.g.,git), ReprOS can push signatures or artifacts to another Git repo (or a different backend). -
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
- Generate Release Artifacts
make release
This typically cleans your out/ directory, rebuilds repros.img, and writes manifest.txt/release.env to dist/.
- 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
- Anyone (including you) pulls down your branch
git fetch origin <your-branch>
git checkout <your-branch>
- 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
- 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
- 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!