diff --git a/README.md b/README.md index ae5a4e6..90cd61a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,21 @@ +
+ + + # RunnerSlice -A systemd-native manager for self-hosted GitHub Actions runners. +**A systemd-native manager for self-hosted GitHub Actions runners.** + +[Installation](docs/installation.md) · +[Operations](docs/operations.md) · +[Threat model](docs/threat-model.md) · +[Verification](docs/verification.md) + +[![check](https://github.com/swarea/runner-slice/actions/workflows/check.yml/badge.svg?branch=main)](https://github.com/swarea/runner-slice/actions/workflows/check.yml?query=branch%3Amain) +![status: public alpha](https://img.shields.io/badge/status-public%20alpha-0f6b7d) +[![MIT](https://img.shields.io/badge/licence-MIT-1c1e22)](LICENSE) + +
RunnerSlice runs persistent, repository-scoped GitHub Actions runners on a Linux host you already operate. Each runner has its own Unix account and @@ -11,7 +26,8 @@ the running host, that the boundary and limits are what you declared. It is Bash and systemd. It has no daemon, no database, no Kubernetes and no web server. -> **Status: public alpha (0.1.0-dev). There is no release or tag yet.** +> **Status: public alpha (0.1.0-dev). Development has ended at this stage. +> There is no release or tag.** > > - **Every push and pull request** runs shellcheck and every drill on > GitHub-hosted runners (the `check` workflow). The drills exercise each @@ -94,6 +110,22 @@ need to bound and verify what CI can take from it. ## How it works +```text + one host + ┌─────────────────────────────────────────────────┐ + │ ci.slice CPUQuota, MemoryMax, TasksMax │ + │ IPAddressDeny (optional) │ + │ ┌───────────────────┐ ┌───────────────────┐ │ + │ │ runner-app │ │ runner-web │ │ + │ │ own account, root │ │ own account, root │ │ + │ │ peers' roots, all │ │ peers' roots, all │ │ + │ │ homes, Docker │ │ homes, Docker │ │ + │ │ socket: masked │ │ socket: masked │ │ + │ └───────────────────┘ └───────────────────┘ │ + └─────────────────────────────────────────────────┘ + plan / apply / retire change it; check reads it back +``` + ```text /etc/runner-slice/fabric.conf slice limits, prefixes, masks for the whole host /etc/runner-slice/runner-release.conf the actions/runner release to install, by SHA-256 @@ -124,8 +156,8 @@ what has been verified. ## Getting started -1. Read [Installation](docs/installation.md): requirements, and how to - install from a checkout until the first release exists. +1. Read [Installation](docs/installation.md): requirements, and how to build + the archive from a commit and install it. No release is published. 2. Write the inventory ([Configuration](docs/configuration.md)), then follow [Operations](docs/operations.md) from `plan` to the first registered runner. 3. Run `sudo runner-slice check` after every change and every reboot. diff --git a/SECURITY.md b/SECURITY.md index 4122660..edd4f9c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -19,8 +19,9 @@ operator has to do. ## Supported versions -There is no release yet. Until there is, fixes land on `main` only. Once -there is, only the latest release receives fixes. +There is no release. RunnerSlice is a public alpha whose development has +ended. A report is still read, and a confirmed fix lands on `main`, which is +the only supported version. ## In scope diff --git a/docs/assets/README.md b/docs/assets/README.md new file mode 100644 index 0000000..347e74a --- /dev/null +++ b/docs/assets/README.md @@ -0,0 +1,11 @@ +# Assets + +`mark.png` is the repository mark the README displays at 96×96. +`mark-source.png` is the card it is cut from: `swarea-cyan-deep-0f6b7d`, +from the `ground-f7f7f6` set. + +The shape follows +[the organization's mark rule](https://github.com/swarea/.github/blob/main/docs/repository-mark.md): +512 × 512, ground `#f7f7f6`, and a 75px corner radius. The colour is +`make-mark.html`'s draw of this card. The corner's alpha channel is identical +to the other swarea marks, which is the check the rule asks for. diff --git a/docs/assets/mark-source.png b/docs/assets/mark-source.png new file mode 100755 index 0000000..6e00b64 Binary files /dev/null and b/docs/assets/mark-source.png differ diff --git a/docs/assets/mark.png b/docs/assets/mark.png new file mode 100644 index 0000000..dbfbc69 Binary files /dev/null and b/docs/assets/mark.png differ diff --git a/docs/compatibility.md b/docs/compatibility.md index 504bd2c..6219dcd 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -8,7 +8,7 @@ actually been verified, and at what level ([verification.md](verification.md)). | Distribution | Architecture | systemd | Status | |---|---|---|---| -| Ubuntu 24.04 | x86_64 | 255 | **Planned** for the first verification VM. Not yet verified. | +| Ubuntu 24.04 | x86_64 | 255 | **Not verified.** Preflight accepts it; no x86_64 host has run RunnerSlice. | | Ubuntu 24.04 | aarch64 | 255 | **Verified** on a disposable VM (Lima, Apple Virtualization), at RUNTIME VERIFIED and REBOOT VERIFIED. See [acceptance/2026-10-arm64.md](acceptance/2026-10-arm64.md). The lifecycle was run with two real GitHub runners, ending in deregistration and retirement. One VM; no other aarch64 host verified. | | Ubuntu 22.04 | aarch64 | 249 | The code RunnerSlice was extracted from has run here in production (see [field-report.md](field-report.md)). **This code** has not been run there. Not supported. | | Any other distribution | | | Refused by preflight. | diff --git a/docs/contract.md b/docs/contract.md index f3b82b8..141e29e 100644 --- a/docs/contract.md +++ b/docs/contract.md @@ -186,6 +186,11 @@ run against one recorded commit. The version follows the evidence. No stage is skipped to reach a number. +**Development ended at Alpha on 2026-10-17.** The Beta and 1.0 rows define +what those stages would have required. They are kept as definitions, and no +work towards them is planned. The project is a public alpha, at +`0.1.0-dev`, with no release or tag. + ## Open decisions (owner) Decided: @@ -197,7 +202,4 @@ Decided: - on 2026-10-16: public visibility. Hosted CI for a public repository needs no paid minutes. -Still open, each a separate approval: - -- **the first release and tag**; -- **an x86_64 verification host**, and its cost. +Not pursued: a release or tag, and an x86_64 verification host. diff --git a/docs/field-report.md b/docs/field-report.md index 9d0f45f..be9eca5 100644 --- a/docs/field-report.md +++ b/docs/field-report.md @@ -54,8 +54,8 @@ repository names, network details and account identifiers are left out. finished along a critical path of 14.8 minutes, against 17.9 minutes run one after another. Jobs running at the same time each took 1.4 to 1.8 times as long as alone. - - One sample is not a performance result. A 7-day before-and-after - comparison is planned, and nothing more is claimed until it exists. + - One sample is not a performance result, and no longer comparison is + recorded here. Nothing more is claimed. - This experience is why pools exist in RunnerSlice. - **What did not fit.** The mobile-app repository's Android build needed x86_64-only tools under emulation: 18 to 26 times slower per core on diff --git a/docs/installation.md b/docs/installation.md index 6c5b2a9..d4f4f56 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -25,7 +25,7 @@ Which combinations have actually been verified is recorded in ## Get the release archive -There is no published release yet. Build the archive from a commit you have +No release is published. Build the archive from a commit you have reviewed: ```sh @@ -37,8 +37,8 @@ bash scripts/release.sh --out ../dist --snapshot # -dev versions need --snapsh ``` The build is reproducible: the same commit gives the same bytes and the same -`runner-slice-.tar.gz.sha256`. When releases are published, verify the -download against the published checksum: +`runner-slice-.tar.gz.sha256`. To check an archive someone else +built, rebuild it from the same commit and compare the checksum: ```sh sha256sum -c runner-slice-.tar.gz.sha256 diff --git a/docs/threat-model.md b/docs/threat-model.md index 7b79e52..c9ad022 100644 --- a/docs/threat-model.md +++ b/docs/threat-model.md @@ -107,8 +107,10 @@ inventory and the library, then reads the host: unknown CPU quota format. The fixtures in the drills encode what systemd is expected to print. Each of -those assumptions is listed in [verification.md](verification.md) and has to be -observed on a real host before it counts. +those assumptions is listed in [verification.md](verification.md) with what a +real Ubuntu 24.04 aarch64 host with systemd 255 showed. Two of them were wrong +until that host corrected them: the archive's modes and how `RestrictNamespaces` +is printed. On any other host they are still assumptions. ## Handling of registration diff --git a/docs/verification.md b/docs/verification.md index 025da0c..cc66ec8 100644 --- a/docs/verification.md +++ b/docs/verification.md @@ -143,21 +143,11 @@ Each run records: ### Environments -Creating either environment needs owner approval, and so does any cost. - - **ARM64:** an Ubuntu 24.04 aarch64 VM on the maintainer's Apple-silicon - laptop. - - Candidate tools are UTM or Lima with Apple's Virtualization framework, - 2 vCPU and 4 GiB. - - Before relying on it, check: systemd PID 1 and cgroup v2 with the - `cpu`, `memory` and `pids` controllers; outbound access to GitHub; - reboot behaviour; and the laptop's free memory while it runs. -- **x86_64:** a short-lived Ubuntu 24.04 x86_64 cloud VM. - - About 2 vCPU and 4 GiB, created for the run and deleted after it. - - It must be in an account or project separate from production, with no - access to production networks. - - The provider, cost cap, run time and deletion procedure are decided before - it is created. + laptop: Lima with Apple's Virtualization framework, 2 vCPU, 3 GiB, NAT, no + shared folders. It was used for every real-host result above. It was + deleted on 2026-10-17, after its results were recorded. +- **x86_64:** none. No x86_64 host has run RunnerSlice, and none is planned. ### Dogfood @@ -169,9 +159,8 @@ retired when the acceptance ended. and runs `tests/run.sh` on the VM's runners. - **Each run records** the commit, the tree, and the runner that ran it. - **These results never appear as checks on RunnerSlice pull requests.** A - non-sensitive summary goes into the release record. + non-sensitive summary is in the acceptance record. -The README may say RunnerSlice is validated on runners it manages only after -a dogfood run and the lifecycle acceptance have both been recorded for one -commit. The dogfood runners are retired when the acceptance ends. That -retirement is item 15. +Both were recorded on the ARM64 VM. The dogfood runners were retired when the +acceptance ended (item 15), and the dogfood repository is archived, with its +run history kept.