Skip to content

Commit 4479f09

Browse files
committed
feat: harden reproducibility and release validation
1 parent 3c0bcb6 commit 4479f09

31 files changed

Lines changed: 720 additions & 14 deletions

.github/workflows/README.en.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ This directory stores the GitHub Actions workflows. It now includes both continu
77
## Current File
88

99
- `ci.yml`
10-
continuous integration workflow covering tests, build, and `ls` boot verification
10+
continuous integration workflow covering tests, build, `ls` boot verification, and a two-build reproducibility check
1111
- `release.yml`
12-
release workflow that rebuilds images from source and uploads them to GitHub Release on a tag push or manual dispatch, with optional `source_ref` support for manual republish runs
12+
release workflow that rebuilds images from source, uploads them to GitHub Release, and then reads those published assets back for another boot verification; manual republish runs also support an optional `source_ref`

.github/workflows/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
## 当前文件
88

99
- `ci.yml`
10-
持续集成工作流,覆盖单测、构建和 `ls` 启动验证
10+
持续集成工作流,覆盖单测、构建、`ls` 启动验证,以及双次构建可复现性检查
1111
- `release.yml`
12-
发布资产工作流,按 tag 或手动触发,从源码重建镜像并上传到 GitHub Release;手动触发时支持额外指定 `source_ref`
12+
发布资产工作流,按 tag 或手动触发,从源码重建镜像并上传到 GitHub Release;上传后还会把发布资产重新拉回并再次启动验证;手动触发时支持额外指定 `source_ref`

.github/workflows/ci.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,26 @@ jobs:
119119
name: linux-012-macos-ci-artifacts
120120
path: |
121121
out/repo-images
122+
123+
linux-012-reproducibility:
124+
runs-on: ubuntu-22.04
125+
timeout-minutes: 90
126+
127+
steps:
128+
- name: Checkout repository
129+
uses: actions/checkout@v5
130+
131+
- name: Run unit tests
132+
run: python3 -m unittest discover -s tests -v
133+
134+
- name: Build twice and compare image digests
135+
run: python3 rebuild/driver.py check-reproducible-build
136+
137+
- name: Upload reproducibility artifacts
138+
if: always()
139+
uses: actions/upload-artifact@v6
140+
with:
141+
name: linux-012-reproducibility-artifacts
142+
path: |
143+
rebuild/out/images
144+
rebuild/out/logs

.github/workflows/release.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,6 @@ jobs:
9797
images/hdc-0.12.img.xz \
9898
images/manifest.json \
9999
--clobber
100+
101+
- name: Verify release readback against published assets
102+
run: python3 rebuild/driver.py verify-release-readback

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Yaochao
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Makefile

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
.DEFAULT_GOAL := help
2+
3+
.PHONY: help bootstrap-host build run run-window verify verify-userland check-images fetch-release-images repro-check release-readback
4+
5+
help:
6+
@printf '%s\n' \
7+
'Available targets:' \
8+
' bootstrap-host Check Python, QEMU, and Docker on the current host' \
9+
' build Build Linux 0.12 runtime images from source' \
10+
' run Boot QEMU from the committed repo snapshots' \
11+
' run-window Boot QEMU from the committed repo snapshots in a visible window' \
12+
' verify Boot Linux 0.12 and verify that ls succeeds' \
13+
' verify-userland Verify minimal shell built-ins and helper commands' \
14+
' check-images Verify committed repo snapshots against images/manifest.json' \
15+
' fetch-release-images Restore committed repo snapshots from the tagged GitHub Release' \
16+
' repro-check Build twice and verify that image outputs are reproducible' \
17+
' release-readback Re-download release assets and verify they still boot'
18+
19+
bootstrap-host:
20+
./scripts/bootstrap-host.sh
21+
22+
build:
23+
/usr/bin/python3 rebuild/driver.py build
24+
25+
run:
26+
./scripts/run.sh
27+
28+
run-window:
29+
./scripts/run-window.sh
30+
31+
verify:
32+
./scripts/verify.sh
33+
34+
verify-userland:
35+
./scripts/verify-userland.sh
36+
37+
check-images:
38+
./scripts/check-images.sh
39+
40+
fetch-release-images:
41+
./scripts/fetch-release-images.sh
42+
43+
repro-check:
44+
./scripts/check-reproducible-build.sh
45+
46+
release-readback:
47+
./scripts/verify-release-readback.sh

README.en.md

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
[中文 README](./README.md)
44
[Changelog](./CHANGELOG.en.md)
5+
[Third-Party Notes](./THIRD_PARTY.en.md)
56

67
This repository does one specific thing: on a modern host, it builds the two runtime images required to boot Linux 0.12 under QEMU from source and repo-owned manifests, enters the shell, and verifies the result by running `ls`.
78

@@ -34,7 +35,9 @@ This is not a “download a historical image and boot it” repo. It is a “reb
3435

3536
Current formal release: `v1.0.1`
3637

37-
The repository also includes an automated GitHub Actions release workflow: pushing a `v*` tag, or manually dispatching `.github/workflows/release.yml`, rebuilds the images from source, runs a real boot verification, and uploads `bootimage-0.12-hd`, `hdc-0.12.img.xz`, and `manifest.json` to the matching GitHub Release. Manual dispatch also accepts an optional `source_ref`, which is useful when republishing an existing release from the current `main` branch or another ref.
38+
The root [LICENSE](./LICENSE) covers repo-authored scripts, patches, userland sources, tests, and documentation only. The bundled upstream Linux 0.12 source archive and the generated runtime artifacts have their own upstream-related licensing boundary, documented in [THIRD_PARTY.en.md](./THIRD_PARTY.en.md).
39+
40+
The repository also includes an automated GitHub Actions release workflow: pushing a `v*` tag, or manually dispatching `.github/workflows/release.yml`, rebuilds the images from source, runs a real boot verification, and uploads `bootimage-0.12-hd`, `hdc-0.12.img.xz`, and `manifest.json` to the matching GitHub Release. After upload, the workflow downloads that published asset set back from the release URL and boots it again as a readback validation. Manual dispatch also accepts an optional `source_ref`, which is useful when republishing an existing release from the current `main` branch or another ref.
3841

3942
## Supported Hosts
4043

@@ -97,6 +100,12 @@ Windows CMD:
97100
scripts\bootstrap-host.cmd
98101
```
99102

103+
If you prefer a single top-level entrypoint on macOS / Ubuntu, you can also run:
104+
105+
```sh
106+
make bootstrap-host
107+
```
108+
100109
### 3. Start QEMU From The Bundled Images
101110

102111
If you want to verify the committed snapshots before launch, run:
@@ -281,8 +290,49 @@ Windows CMD:
281290
scripts\verify-userland.cmd
282291
```
283292

293+
If you also want to verify that two full source builds produce byte-identical image outputs, run:
294+
295+
macOS / Ubuntu:
296+
297+
```sh
298+
./scripts/check-reproducible-build.sh
299+
```
300+
301+
or use:
302+
303+
```sh
304+
make repro-check
305+
```
306+
307+
If you want to confirm that the assets published on GitHub Release still boot after being downloaded back into a clean repo snapshot, run:
308+
309+
macOS / Ubuntu:
310+
311+
```sh
312+
./scripts/verify-release-readback.sh
313+
```
314+
315+
or use:
316+
317+
```sh
318+
make release-readback
319+
```
320+
284321
## Common Commands
285322

323+
On macOS / Ubuntu you can also prefer the top-level `Makefile`:
324+
325+
```sh
326+
make help
327+
make build
328+
make run
329+
make verify
330+
make check-images
331+
make fetch-release-images
332+
make repro-check
333+
make release-readback
334+
```
335+
286336
Start QEMU from the committed repo images:
287337

288338
```sh
@@ -301,6 +351,18 @@ Fetch the committed repo image snapshots from the GitHub Release:
301351
python3 rebuild/driver.py fetch-release-images
302352
```
303353

354+
Run two full source builds and compare the SHA-256 digests of `bootimage-0.12-hd`, `hdc-0.12.img`, and `hdc-0.12.img.xz`:
355+
356+
```sh
357+
python3 rebuild/driver.py check-reproducible-build
358+
```
359+
360+
Delete local snapshots, read them back from the release declared in `images/manifest.json`, and boot-verify them:
361+
362+
```sh
363+
python3 rebuild/driver.py verify-release-readback
364+
```
365+
304366
Start QEMU from the committed repo images with a visible window:
305367

306368
```sh
@@ -321,7 +383,7 @@ python3 rebuild/driver.py build-and-run-repo-images-window
321383

322384
## Continuous Integration
323385

324-
The repository now includes the GitHub Actions workflow [ci.yml](/Users/infoxmed-01/ai/workspace/linux-012/.github/workflows/ci.yml). On pushes to `main` and pull requests targeting `main`, it runs two kinds of jobs:
386+
The repository now includes the GitHub Actions workflow [ci.yml](/Users/infoxmed-01/ai/workspace/linux-012/.github/workflows/ci.yml). On pushes to `main` and pull requests targeting `main`, it runs four kinds of jobs:
325387

326388
- full `ubuntu-22.04` pipeline:
327389
`python3 -m unittest discover -s tests -v`
@@ -341,8 +403,11 @@ The repository now includes the GitHub Actions workflow [ci.yml](/Users/infoxmed
341403
automatic unpack of the repo-managed disk snapshot
342404
`python3 tools/qemu_driver.py verify --dry-run`
343405
`python3 tools/qemu_driver.py run-window --dry-run`
406+
- `ubuntu-22.04` reproducibility check:
407+
`python3 -m unittest discover -s tests -v`
408+
`python3 rebuild/driver.py check-reproducible-build`
344409

345-
On failure it uploads Ubuntu artifacts from `out/verify` and `rebuild/out/logs`, plus the Windows and macOS smoke artifacts from `out/repo-images`.
410+
On failure it uploads Ubuntu boot-verification artifacts from `out/verify` and `rebuild/out/logs`, reproducibility artifacts from `rebuild/out/images` and `rebuild/out/logs`, plus the Windows and macOS smoke artifacts from `out/repo-images`.
346411

347412
Build the images explicitly:
348413

@@ -443,6 +508,8 @@ The current standalone userland binaries are:
443508
- The boot image is shorter than 1.44MB, so the driver pads it into a full floppy image before launch
444509
- `scripts/check-images.*` verifies the repo-managed snapshots against `images/manifest.json`
445510
- `scripts/fetch-release-images.*` re-downloads the repo-managed snapshots from the GitHub Release referenced by `images/manifest.json`
511+
- `scripts/check-reproducible-build.*` runs two full builds and compares image digests to verify reproducibility
512+
- `scripts/verify-release-readback.*` reads the current snapshots back from the release URL and boot-verifies them
446513
- `scripts/run.*` uses the committed snapshots in `images/` by default and unpacks the hard disk image into `out/repo-images/`
447514
- `scripts/run-window.*` uses the committed snapshots in `images/`, unpacks the hard disk image into `out/repo-images/`, and opens a visible QEMU window
448515
- `scripts/build-and-run.*` rebuilds from source and refreshes `images/`
@@ -472,3 +539,4 @@ This project does not try to:
472539

473540
- `vendor/src/linux-0.12.tar.gz` comes from the kernel.org historic Linux 0.12 source archive
474541
- Runtime images are not downloaded from third parties; they are built locally from repo-owned sources, patches, and manifests
542+
- The licensing and provenance boundary is documented in [THIRD_PARTY.en.md](./THIRD_PARTY.en.md)

README.md

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
[English README](./README.en.md)
44
[变更日志](./CHANGELOG.md)
5+
[第三方来源与许可](./THIRD_PARTY.md)
56

67
这个仓库的目标很直接:在现代宿主机上,从源码和仓库内清单出发,构建出 Linux 0.12 运行所需的两张 QEMU 镜像,启动进入 shell,并成功执行 `ls`
78

@@ -34,7 +35,9 @@
3435

3536
当前正式发布版本:`v1.0.1`
3637

37-
仓库还带有自动发布资产的 GitHub Actions 工作流:推送 `v*` tag,或者手动触发 `.github/workflows/release.yml`,都会从源码重建镜像、执行一次真实启动验证,并把 `bootimage-0.12-hd``hdc-0.12.img.xz``manifest.json` 上传到对应的 GitHub Release。手动触发时还可以额外指定 `source_ref`,用于从当前 `main` 或其他 ref 重新发布某个已有 release 的资产。
38+
根目录 [LICENSE](./LICENSE) 只覆盖仓库自行编写的脚本、补丁、用户态源码、测试和文档。随仓库保留的上游 Linux 0.12 源码归档,以及由它参与生成的镜像产物,边界说明见 [THIRD_PARTY.md](./THIRD_PARTY.md)
39+
40+
仓库还带有自动发布资产的 GitHub Actions 工作流:推送 `v*` tag,或者手动触发 `.github/workflows/release.yml`,都会从源码重建镜像、执行一次真实启动验证,并把 `bootimage-0.12-hd``hdc-0.12.img.xz``manifest.json` 上传到对应的 GitHub Release。上传完成后,工作流还会按 release 链接重新拉回这组资产,再启动一次 QEMU 做回读验证。手动触发时还可以额外指定 `source_ref`,用于从当前 `main` 或其他 ref 重新发布某个已有 release 的资产。
3841

3942
## 支持的宿主机
4043

@@ -97,6 +100,12 @@ Windows CMD:
97100
scripts\bootstrap-host.cmd
98101
```
99102

103+
如果你在 macOS / Ubuntu 上更喜欢统一的顶层入口,也可以直接运行:
104+
105+
```sh
106+
make bootstrap-host
107+
```
108+
100109
### 3. 直接启动仓库内置镜像
101110

102111
如果你想先检查仓库快照是否完整,可以运行:
@@ -281,8 +290,49 @@ Windows CMD:
281290
scripts\verify-userland.cmd
282291
```
283292

293+
如果你还想验证“连续两次源码构建产物完全一致”,可以运行:
294+
295+
macOS / Ubuntu:
296+
297+
```sh
298+
./scripts/check-reproducible-build.sh
299+
```
300+
301+
或者直接使用:
302+
303+
```sh
304+
make repro-check
305+
```
306+
307+
如果你想验证 GitHub Release 上发布出去的快照重新拉回后仍然能启动并执行 `ls`,可以运行:
308+
309+
macOS / Ubuntu:
310+
311+
```sh
312+
./scripts/verify-release-readback.sh
313+
```
314+
315+
或者直接使用:
316+
317+
```sh
318+
make release-readback
319+
```
320+
284321
## 常用命令
285322

323+
在 macOS / Ubuntu 上,也可以优先使用顶层 `Makefile`
324+
325+
```sh
326+
make help
327+
make build
328+
make run
329+
make verify
330+
make check-images
331+
make fetch-release-images
332+
make repro-check
333+
make release-readback
334+
```
335+
286336
直接启动仓库内置镜像:
287337

288338
```sh
@@ -301,6 +351,18 @@ python3 rebuild/driver.py check-repo-images
301351
python3 rebuild/driver.py fetch-release-images
302352
```
303353

354+
连续做两次源码构建并比较 `bootimage-0.12-hd``hdc-0.12.img``hdc-0.12.img.xz` 的 SHA-256:
355+
356+
```sh
357+
python3 rebuild/driver.py check-reproducible-build
358+
```
359+
360+
删除本地快照、按 `images/manifest.json` 从 release 回读,再启动验证:
361+
362+
```sh
363+
python3 rebuild/driver.py verify-release-readback
364+
```
365+
304366
直接弹出可见的 QEMU 窗口:
305367

306368
```sh
@@ -321,7 +383,7 @@ python3 rebuild/driver.py build-and-run-repo-images-window
321383

322384
## 持续集成
323385

324-
仓库现在包含 GitHub Actions 工作流 [ci.yml](/Users/infoxmed-01/ai/workspace/linux-012/.github/workflows/ci.yml)。它会在推送到 `main` 或对 `main` 发起 Pull Request 时执行两类任务
386+
仓库现在包含 GitHub Actions 工作流 [ci.yml](/Users/infoxmed-01/ai/workspace/linux-012/.github/workflows/ci.yml)。它会在推送到 `main` 或对 `main` 发起 Pull Request 时执行四类任务
325387

326388
- `ubuntu-22.04` 完整链路:
327389
`python3 -m unittest discover -s tests -v`
@@ -341,8 +403,11 @@ python3 rebuild/driver.py build-and-run-repo-images-window
341403
基于仓库快照自动解包系统镜像
342404
`python3 tools/qemu_driver.py verify --dry-run`
343405
`python3 tools/qemu_driver.py run-window --dry-run`
406+
- `ubuntu-22.04` 可复现性检查:
407+
`python3 -m unittest discover -s tests -v`
408+
`python3 rebuild/driver.py check-reproducible-build`
344409

345-
失败时会上传 Ubuntu `out/verify``rebuild/out/logs`,以及 Windows 和 macOS 的 `out/repo-images` 作为排查产物。
410+
失败时会上传 Ubuntu 启动验证产物 `out/verify``rebuild/out/logs`,可复现性检查产物 `rebuild/out/images``rebuild/out/logs`,以及 Windows 和 macOS 的 `out/repo-images` 作为排查产物。
346411

347412
显式构建镜像:
348413

@@ -443,6 +508,8 @@ python3 rebuild/driver.py run
443508
- 启动镜像本身不足 1.44MB,驱动会在启动前补齐成标准软盘镜像
444509
- `scripts/check-images.*` 会按 `images/manifest.json` 校验仓库快照
445510
- `scripts/fetch-release-images.*` 会从 `images/manifest.json` 指向的 GitHub Release 重新拉取仓库快照
511+
- `scripts/check-reproducible-build.*` 会连续构建两次并比较镜像摘要,验证构建可复现性
512+
- `scripts/verify-release-readback.*` 会从 release 回读当前快照,再启动 QEMU 验证
446513
- `scripts/run.*` 默认直接使用仓库里的 `images/` 快照,并在 `out/repo-images/` 里自动解包系统镜像
447514
- `scripts/run-window.*` 默认直接使用仓库里的 `images/` 快照,并在 `out/repo-images/` 里自动解包系统镜像后弹出可见的 QEMU 窗口
448515
- `scripts/build-and-run.*` 会重编源码并刷新 `images/`
@@ -472,3 +539,4 @@ python3 rebuild/driver.py run
472539

473540
- `vendor/src/linux-0.12.tar.gz` 来自 kernel.org 的 Linux 0.12 历史源码归档
474541
- 运行镜像不来自第三方下载,而是由仓库内源码、补丁和清单在本地构建生成
542+
- 许可边界、第三方来源和生成产物注意事项见 [THIRD_PARTY.md](./THIRD_PARTY.md)

0 commit comments

Comments
 (0)