Make it honest and usable for someone who is not the author
build-iso / build (push) Failing after 12s

The README promised ISO downloads from a Releases page that does not and cannot exist here —
the ISO was only ever built by a runner on the author's own forge. Say plainly that you build
it yourself, and why no prebuilt image is published.

Remove the last references to private infrastructure: the entry-point script's usage comment,
the CI runner registration, the nginx template, the install doc's hardcoded user and its
pointer to a private recovery doc, and the ISO publisher metadata.

Add the MIT LICENSE the project needed to be reusable at all, a CHANGELOG, and GitHub CI —
shellcheck, syntax, config validation, and a guard that fails the build if private
infrastructure is ever referenced from this public repo again.
This commit is contained in:
flan
2026-07-13 17:12:34 +00:00
parent bd7f46a260
commit a8080cb43b
9 changed files with 147 additions and 12 deletions
+66
View File
@@ -0,0 +1,66 @@
name: Lint
on:
push:
branches: ["master"]
pull_request:
branches: ["master"]
permissions:
contents: read
jobs:
shell:
name: shellcheck + syntax
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Install shellcheck
run: sudo apt-get update -qq && sudo apt-get install -y -qq shellcheck
- name: Syntax check every shell script
run: |
fail=0
while IFS= read -r f; do
bash -n "$f" || { echo "::error file=$f::bash -n failed"; fail=1; }
done < <(git ls-files '*.sh' 'bootstrap.sh' 'firstboot.sh' 'configs/firstboot-once')
exit $fail
- name: shellcheck
run: |
# firstboot-once has no .sh extension; site.env is not a script.
shellcheck --severity=warning \
bootstrap.sh firstboot.sh iso/build.sh configs/firstboot-once
config:
name: archinstall config
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: archinstall.json is valid JSON
run: jq -e . configs/archinstall.json > /dev/null
- name: Every @@BASE@@ placeholder resolves
run: |
# bootstrap.sh substitutes @@BASE@@ into the custom-commands before handing the
# config to archinstall. If a placeholder survived into a fetch URL, an install
# would curl a literal "@@BASE@@" and fail on the target machine, not here.
sed 's|@@BASE@@|https://example.test|g' configs/archinstall.json | jq -e . > /dev/null
if grep -q '@@BASE@@' <(sed 's|@@BASE@@|https://example.test|g' configs/archinstall.json); then
echo "::error::an @@BASE@@ placeholder survived substitution"; exit 1
fi
- name: No private infrastructure leaked into a public repo
run: |
# This repo installs machines. A stranger's install must never be pointed at the
# maintainer's forge, and must never be told to clone a repo they cannot read.
# Match the real private domains only — `git.example.com` and friends are the
# placeholders in site.env.example and are supposed to be there. Exclude this
# file, which necessarily contains the very patterns it searches for.
if git grep -nIE 'onetick\.ninja|arch\.fyi|/mnt/Tank' \
-- . ':!.github/workflows/lint.yml' ; then
echo "::error::private infrastructure referenced in a public repo"; exit 1
fi
echo "clean"
+36
View File
@@ -0,0 +1,36 @@
# Changelog
All notable changes to arch-turnkey are documented here.
Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning: [SemVer](https://semver.org).
## [Unreleased]
### Added
- **`site.env` — personal provisioning is now opt-in and out of the repo.** The install runs in
two phases: a generic base (LUKS + btrfs subvolumes + snapper + yay) that works from a fresh
clone with no configuration, and a personal phase (vault unlock → register the new machine's SSH
key with your forge → clone your dotfiles → `yadm bootstrap`) driven by a gitignored `site.env`.
With no `site.env`, firstboot reports what it is skipping and leaves a complete system. See
[docs/SITE.md](docs/SITE.md) and `configs/site.env.example`.
- **`iso/build.sh` bakes `site.env` into a custom ISO**, so an unattended personal install stays a
single boot with no extra typing. Without one it builds a generic installer ISO.
- **`ARCH_TURNKEY_BASE`** — one fetch root feeds `bootstrap.sh`, the archinstall `custom-commands`
(via an `@@BASE@@` placeholder) and the ISO autorun. Defaults to the public GitHub mirror; set it
to install from your own forge instead.
- GitHub CI: shellcheck + `bash -n` on every script, `archinstall.json` JSON validation, a check
that no `@@BASE@@` placeholder survives substitution, and a guard that fails the build if private
infrastructure is ever referenced from this public repo.
- MIT `LICENSE`. Without one, an "install script for everyone" was legally unusable by anyone.
### Fixed
- **The installer only worked for its author.** `bootstrap.sh` and the archinstall
`custom-commands` fetched from one specific private Gitea, and `firstboot.sh` cloned a **private**
dotfiles repo from it. Anyone else cloning this got an installer that could not work and that
pointed them at a repository they cannot read.
- **The README advertised ISO downloads from a Releases page that did not, and could not, exist.**
It now tells you to build the ISO with `iso/build.sh` and explains why no prebuilt image is
published.
- Docs no longer reference the maintainer's forge, private dotfiles, or personal username:
`docs/CI.md` uses a generic forge URL, `docs/nginx-redirect.conf` is an explicit template,
`docs/INSTALL.md` no longer hardcodes a user or point at a private recovery doc, and the ISO
publisher metadata matches the identity the repo is actually published under.
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 sudolulo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+11 -3
View File
@@ -65,14 +65,22 @@ A thin custom Arch ISO auto-runs the bootstrap on boot — flash a USB, boot, wa
away. Thin means it pulls the current `bootstrap.sh` from git at boot, so the ISO
never goes stale.
**Download the latest** from this repo's **Releases** (auto-built monthly — see
[docs/CI.md](docs/CI.md)), or build locally:
Build it yourself (~10 min):
```
sudo pacman -S archiso
sudo iso/build.sh # ~10 min, ISO in iso/out/
sudo iso/build.sh # ISO lands in iso/out/
```
No prebuilt ISO is published here — an Arch ISO is ~1 GB and goes stale the moment
upstream moves, so building it locally against the current archiso is both smaller and
more correct than downloading a months-old image. [docs/CI.md](docs/CI.md) shows how to
automate the build if you want it on a schedule.
To make the ISO provision *your* machine unattended — dotfiles, secrets, packages — drop a
`site.env` at `iso/site.env` before building; `build.sh` bakes it in. See
[docs/SITE.md](docs/SITE.md).
## Layout
```
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# One-line ISO entrypoint. From the Arch live ISO:
# curl -fsSL arch.onetick.ninja | bash
# curl -fsSL https://raw.githubusercontent.com/sudolulo/arch-turnkey/master/bootstrap.sh | bash
# Installs archinstall, pulls the config, launches the guided install, then reboots.
set -euo pipefail
+1 -1
View File
@@ -19,7 +19,7 @@ Building an ISO needs `mkarchiso`, which needs **root + loop devices**, so a
2. **Register a runner** (`act_runner`) that can run privileged containers, with a
label matching `runs-on: archlinux` in the workflow. On a Docker host:
```
act_runner register --instance https://git.onetick.ninja \
act_runner register --instance https://your-forge.example \
--token <from Gitea: Settings > Actions > Runners> \
--labels archlinux:docker://archlinux:latest --name iso-builder
act_runner daemon
+5 -3
View File
@@ -11,7 +11,8 @@ manual base-install fallback if archinstall ever chokes.
| 2. Configure | **firstboot** + **yadm bootstrap** | packages per class, services, dotfiles, snapshots |
| 3. Data (optional) | **restic** | files restored from Backblaze B2 |
Personal config + secrets live in the private dotfiles repo (yadm). This repo is
Personal config + secrets live in your own dotfiles repo (yadm), wired up via a gitignored
`site.env` — see [SITE.md](SITE.md). This repo is
the installer only — no secrets, safe to be public.
## Phase 1 — archinstall (the GUI path)
@@ -65,7 +66,8 @@ Reboot into the configured session.
## Phase 3 — restore data (optional)
See the private dotfiles `~/RECOVERY.md` for restic restore from B2.
Restoring data is out of scope for this repo — it belongs with whatever backup tooling your
dotfiles set up (the author uses restic to B2, documented in their own private dotfiles).
## Manual base install (fallback)
@@ -97,7 +99,7 @@ arch-chroot /mnt
# loader entry options (encrypt hook uses cryptdevice=, not rd.luks.name):
# cryptdevice=UUID=<UUID of sda2>:cryptroot root=/dev/mapper/cryptroot rootflags=subvol=@ rw
systemctl enable NetworkManager
passwd; useradd -m -G wheel -s /bin/zsh flan; passwd flan
passwd; useradd -m -G wheel -s /bin/zsh <user>; passwd <user>
# then: curl firstboot into /usr/local/bin
exit && reboot
```
+5 -3
View File
@@ -1,7 +1,9 @@
# Short-URL redirect so the ISO one-liner becomes:
# curl -fsSL onetick.ninja/arch | bash
# Optional: a short-URL redirect, so the ISO one-liner becomes
# curl -fsSL example.com/arch | bash
# instead of the full raw.githubusercontent.com URL.
#
# Add inside the server block for onetick.ninja on the nginx box, then reload:
# This is a template for your own nginx box — replace example.com with your domain.
# Add inside that domain's server block, then reload:
# nginx -t && systemctl reload nginx
location = /arch {
+1 -1
View File
@@ -33,7 +33,7 @@ LABEL="TURNKEY_$(date +%Y%m)" # date-stamped ISO9660 volume label, injected
sed -i \
-e 's/^iso_name=.*/iso_name="arch-turnkey"/' \
-e "s/^iso_label=.*/iso_label=\"$LABEL\"/" \
-e 's/^iso_publisher=.*/iso_publisher="flan <https:\/\/github.com\/sudolulo\/arch-turnkey>"/' \
-e 's/^iso_publisher=.*/iso_publisher="sudolulo <https:\/\/github.com\/sudolulo\/arch-turnkey>"/' \
-e 's/^iso_application=.*/iso_application="arch-turnkey installer"/' \
"$PROFILE/profiledef.sh"