diff --git a/.forgejo/workflows/python-pywal.yml b/.forgejo/workflows/python-pywal.yml deleted file mode 100644 index f5f7d61..0000000 --- a/.forgejo/workflows/python-pywal.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Build and publish python-pywal - -# python-pywal was dropped from Arch's [extra] repo (AUR-only now), but the ISO -# needs the `wal` binary (bread-theme extracts the wallpaper palette with it). -# BOS keeps an in-house PKGBUILD and publishes to the [breadway] repo — same -# pattern as calamares / bibata / powerlevel10k / yay-bin. -on: - push: - paths: - - 'packaging/python-pywal/**' - workflow_dispatch: - -jobs: - python-pywal: - runs-on: [self-hosted, hestia] - container: - image: archlinux:latest - steps: - - name: Build and publish - env: - PUBLISH_TOKEN: ${{ secrets.REGISTRY_TOKEN }} - run: | - set -euo pipefail - pacman -Syu --noconfirm base-devel git \ - python python-build python-installer python-wheel python-setuptools imagemagick - useradd -m builder - git config --global --add safe.directory '*' - # Clone the ref that triggered this run (not the default branch) — - # same as the other packaging workflows. - git clone --depth 1 --branch "${GITHUB_REF_NAME}" \ - "https://git.breadway.dev/${GITHUB_REPOSITORY}.git" /home/builder/src - chown -R builder:builder /home/builder/src - su builder -c "cd /home/builder/src/packaging/python-pywal && makepkg -f --noconfirm" - PKG=$(find /home/builder/src/packaging/python-pywal -name '*.pkg.tar.zst' | head -1) - curl -fsS -X PUT \ - -H "Authorization: token ${PUBLISH_TOKEN}" \ - -H "Content-Type: application/octet-stream" \ - --data-binary "@${PKG}" \ - "https://git.breadway.dev/api/packages/Breadway/arch/os" diff --git a/.forgejo/workflows/signed-repo.yml b/.forgejo/workflows/signed-repo.yml index caa5d15..3ef8a65 100644 --- a/.forgejo/workflows/signed-repo.yml +++ b/.forgejo/workflows/signed-repo.yml @@ -21,7 +21,6 @@ on: - Build and publish bibata-cursor-theme - Build and publish powerlevel10k - Build and publish yay-bin - - Build and publish python-pywal types: [completed] concurrency: diff --git a/DESIGN.md b/DESIGN.md index 6a075a8..31b22f8 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -16,7 +16,7 @@ taken as current: | Work on `dev`; origin = GitHub | Single-trunk `main`; `stable` is a CI marker. `origin` = Forgejo, `github` = GitHub. | | `[breadway]` provides bakery/breadbar/bos-settings | `[breadway]` is breadlock + AUR republishes. Desktop apps are bakery. **Not shipped:** breadcast, breadarr. | | NVIDIA / A/B / Secure Boot / LUKS2 | NVIDIA proprietary is **unsupported**. A/B root swapping is **not implemented**. Secure Boot is **Setup Mode only** (self-signed `sbctl`). Disk encryption is **LUKS1** because GRUB cannot unlock LUKS2+Argon2id. | -| `SigLevel = Required` on `[breadway]` | **Yes, as of the signed repo.** `[breadway]` points at `https://dl.breadway.dev/arch` where `scripts/ci-publish-signed-repo.sh` detach-signs every `.pkg.tar.zst` and the db with the BOS release key (`56203B86…`, `KEYS.asc`). That key is trusted in the pacman keyring at build time, on the live medium, and on the installed target. | +| `SigLevel = Required` on `[breadway]` | **No.** Forgejo's Arch registry has no pacman-compatible db signatures. `SigLevel = Never` is TLS only; flipping Required without a signed db breaks installs. `KEYS.asc` signs ISO SHA256SUMS, not the pacman repo. | --- diff --git a/README.md b/README.md index 22b0108..1a833b6 100644 --- a/README.md +++ b/README.md @@ -174,10 +174,10 @@ dedicated release-signing key (not reused from anything else): 5620 3B86 A110 695A E7F3 1093 4AF3 323D 678E B5E2 ``` -The public half is committed at [`KEYS.asc`](KEYS.asc). The same key signs -the ISO checksums **and** the `[breadway]` pacman repo — every package and -the db at `https://dl.breadway.dev/arch` carry a `.sig` from it, and that -section is `SigLevel = Required` (see +The public half is committed at [`KEYS.asc`](KEYS.asc). That key signs +**ISO checksums only** — it does not sign the `[breadway]` pacman repo +(Forgejo's Arch registry has no pacman-compatible db signatures; that +section stays `SigLevel = Never` until a signed repo exists — see [docs/signed-repo.md](docs/signed-repo.md)). To verify a download: ```sh @@ -381,9 +381,8 @@ until `dl.breadway.dev/arch` exists). - **Snapshots assume btrfs**: the snapper/grub-btrfs tooling expects the default btrfs subvolume layout the installer creates. Recovery is the GRUB snapshots submenu, not `snapper rollback` — [docs/hardware.md](docs/hardware.md). -- **`[breadway]` signatures**: `SigLevel = Required` — the signed repo at - `dl.breadway.dev/arch` is live (db + every package `.sig`ned with the BOS - release key). See [docs/signed-repo.md](docs/signed-repo.md). +- **`[breadway]` signatures**: `SigLevel = Never` until a signed repo is + stood up at `dl.breadway.dev/arch`. See [docs/signed-repo.md](docs/signed-repo.md). ## Recovery diff --git a/build-local.sh b/build-local.sh index 4b95661..e360d42 100755 --- a/build-local.sh +++ b/build-local.sh @@ -25,19 +25,14 @@ OUT="${OUT:-$REPO/out}" STAGE=/tmp/bos-iso-stage rm -rf "$STAGE" && cp -a "$REPO/iso" "$STAGE" -# [breadway] now points at the signed public repo https://dl.breadway.dev/arch -# (SigLevel = Required) — no Forgejo-registry URL rewrite needed anymore. -# -# Trust the [breadway] repo key in *this* build host's pacman keyring so -# `pacstrap` can verify [breadway] packages while assembling the airootfs. -# The same key is baked into the image at etc/pacman.d/breadway-repo.asc and -# re-trusted on the live medium / installed target (calamares/post-install.sh). -BREADWAY_KEY_FPR="56203B86A110695AE7F310934AF3323D678EB5E2" -BREADWAY_KEY_SRC="$REPO/iso/airootfs/etc/pacman.d/breadway-repo.asc" -if ! pacman-key --list-keys "$BREADWAY_KEY_FPR" &>/dev/null; then - echo "=== trusting [breadway] repo key ($BREADWAY_KEY_FPR) in the host pacman keyring ===" - pacman-key --add "$BREADWAY_KEY_SRC" - pacman-key --lsign-key "$BREADWAY_KEY_FPR" +# Rewrite the [breadway] pacman repo URL to the fastest reachable address. +# CI_BUILD=1 — container runs on hestia with --network=host; localhost:3002 is direct +# default — building on hermes; git.breadway.dev is flaky from there, use Tailscale +# Only ever rewrites the staged copy, never the committed pacman.conf. +if [ "${CI_BUILD:-0}" = "1" ]; then + sed -i 's#https://git.breadway.dev/api/packages/Breadway/arch/os#http://localhost:3002/api/packages/Breadway/arch/os#' "$STAGE/pacman.conf" +else + sed -i 's#https://git.breadway.dev/api/packages/Breadway/arch/os#http://100.66.238.26:3002/api/packages/Breadway/arch/os#' "$STAGE/pacman.conf" fi if [ "${FAST_BUILD:-0}" = "1" ]; then diff --git a/docs/signed-repo.md b/docs/signed-repo.md index bda8656..02b5340 100644 --- a/docs/signed-repo.md +++ b/docs/signed-repo.md @@ -1,20 +1,18 @@ # Signed `[breadway]` repo -**Status: live.** The ISO's `[breadway]` section is `SigLevel = Required` -and points at `https://dl.breadway.dev/arch/$arch`, where every -`.pkg.tar.zst` and the db carry a detached `.sig` from the BOS release key -(`56203B86…`, `KEYS.asc`, `releases@breadway.dev`). That key is trusted in -the pacman keyring at build time (`build-local.sh`), on the live medium -(`iso/airootfs/root/customize_airootfs.sh`), and on the installed target -(`iso/airootfs/etc/calamares/post-install.sh`). +Today the ISO's `[Breadway.os.git.breadway.dev]` section is +`SigLevel = Never`. That is TLS-only integrity: packages come from Forgejo's +Arch registry, which does **not** serve pacman-compatible database +signatures. `KEYS.asc` signs **ISO `SHA256SUMS`** and, once published, the +`dl.breadway.dev/arch` database. It is **not** imported as a pacman repo key +on the ISO yet. Do not flip `SigLevel` to `Required` on that section until +a signed repo exists and has been verified; Required without signatures +breaks the ISO and every installed system. -Forgejo publishing is unchanged: `package.yml` / packaging workflows still -PUT unsigned `.pkg.tar.zst` to Forgejo's Arch registry. The signed tree at -`dl.breadway.dev/arch` is rebuilt from that registry by -`.forgejo/workflows/signed-repo.yml` + `scripts/ci-publish-signed-repo.sh`. - -The rest of this doc is the original stand-up / verification procedure, -kept for reference and for re-verifying after key rotation. +The signed repo belongs at `https://dl.breadway.dev/arch`, not on Forgejo's +registry. Forgejo publishing stays as it is (`package.yml` / packaging +workflows PUT unsigned `.pkg.tar.zst` so existing Never installs keep +working). ## Stand up `dl.breadway.dev/arch` @@ -49,7 +47,7 @@ On disk: `/srv/breadway-dl/arch/x86_64/` (nginx already serves The job collects the current ISO `[breadway]` set from the Forgejo Arch registry (breadlock + calamares, zen-browser-bin, bibata-cursor-theme-bin, -zsh-theme-powerlevel10k, yay-bin, python-pywal). Leftover bakery-channel pacman packages +zsh-theme-powerlevel10k, yay-bin). Leftover bakery-channel pacman packages still sitting in that registry are **not** copied. Optional `BREADWAY_PKG_DIR` on the runner overrides individual files. @@ -76,7 +74,7 @@ Pacman fetches `
.db` + `
.db.sig` from `Server`. ## Dispatch the workflow Forgejo UI: **Actions → "Publish signed [breadway] repo" → Run workflow**. -Select `main`. +Select this branch (`feature/signed-repo`) until it is on `main`. API (`workflow_dispatch`): @@ -85,11 +83,13 @@ curl -fsS -X POST \ -H "Authorization: token ${RELEASE_TOKEN}" \ -H "Content-Type: application/json" \ "https://git.breadway.dev/api/v1/repos/Breadway/bos/actions/workflows/signed-repo.yml/dispatches" \ - -d '{"ref":"main"}' + -d '{"ref":"feature/signed-repo"}' ``` +After merge, use `"ref":"main"`. + It also runs after the in-repo AUR republish workflows complete -(`calamares` / `bibata` / `powerlevel10k` / `yay-bin` / `python-pywal`). breadlock lives in +(`calamares` / `bibata` / `powerlevel10k` / `yay-bin`). breadlock lives in another repo; that job can fire this one with `repository_dispatch` event `publish-signed-repo` (or dispatch from the UI after a breadlock tag). @@ -141,29 +141,15 @@ stays; Never installs keep working. The signed tree is rebuilt by the bos workflow above (registry fetch + sign + `repo-add -s`), not by writing `/srv` from breadlock's container. -## The ISO flip (done) +## After the signed repo exists -All three steps have landed: +Only after `https://dl.breadway.dev/arch/x86_64/breadway.db.sig` HEADs 200 +and the verify commands above succeed: -1. **Key trusted.** The public key is committed at - `iso/airootfs/etc/pacman.d/breadway-repo.asc`. `build-local.sh` - `pacman-key --add` + `--lsign-key`s it into the build host keyring; - `customize_airootfs.sh` does the same in the airootfs; - `calamares/post-install.sh` re-does it in the target chroot. -2. **`Server`** in `iso/pacman.conf` and `iso/airootfs/etc/pacman.conf` - points at `https://dl.breadway.dev/arch/$arch`, section renamed to - `[breadway]` (matching `breadway.db`). -3. **`SigLevel = Required`** on that section. +1. Import `KEYS.asc` into the ISO keyring (`pacman-key --add` + `--lsign-key`). +2. Point `[breadway]` `Server` at `https://dl.breadway.dev/arch/$arch`. +3. Only then flip that section to `SigLevel = Required`. -### Re-verify after any build - -In a VM booted from a fresh ISO: - -```sh -sudo pacman -Sy # must fetch breadway.db + .sig, no signature error -sudo pacman -Si breadlock # lists the [breadway] section -sudo pacman -S --noconfirm yay-bin # installs with no key prompt -``` - -Then run the installer and, on the installed system, `sudo pacman -Sy` -again — the target keyring must already trust `56203B86…`. +Do not do those three steps against Forgejo's registry. See +`iso/pacman.conf` and `iso/airootfs/etc/pacman.conf`. This branch does +**not** change either file. diff --git a/iso/airootfs/etc/calamares/modules/welcome.conf b/iso/airootfs/etc/calamares/modules/welcome.conf index c31ea71..33bf7ad 100644 --- a/iso/airootfs/etc/calamares/modules/welcome.conf +++ b/iso/airootfs/etc/calamares/modules/welcome.conf @@ -3,19 +3,9 @@ showSupportUrl: false showKnownIssuesUrl: false showReleaseNotesUrl: false -# 3.4.2 schema: `check` is shown; only `required` blocks Next. Internet is -# informational so offline installs proceed. Do not probe archlinux.org. requirements: requiredStorage: 20 requiredRam: 2.0 - internetCheckUrl: "https://breadway.dev" - check: - - storage - - ram - - power - - internet - - root - required: - - storage - - ram - - root + checkInternet: true + checkPower: true + internetCheckUrl: "https://archlinux.org" diff --git a/iso/airootfs/etc/calamares/post-install.sh b/iso/airootfs/etc/calamares/post-install.sh index d7df9be..5817f2e 100644 --- a/iso/airootfs/etc/calamares/post-install.sh +++ b/iso/airootfs/etc/calamares/post-install.sh @@ -8,6 +8,8 @@ # Best-effort: do NOT use `set -e`; a single failure here must not abort the rest. set -uo pipefail +MAIN_USER="$(getent passwd 1000 | cut -d: -f1 || true)" + # Whether Calamares encrypted the root partition (LUKS) — checked once here, # used below to conditionally wire mkinitcpio's encrypt hook and GRUB's # cryptodisk support. `lsblk TYPE` reports "crypt" for a cryptsetup-opened @@ -31,14 +33,6 @@ rm -f /usr/local/bin/bos-live-setup /usr/local/bin/bos-launch-calamares rm -f /etc/sudoers.d/99-bos-live userdel -r liveuser 2>/dev/null || true -# Live ISO creates liveuser as UID 1000; Calamares then creates the real -# account as 1001. Capture AFTER userdel so Snapper ALLOW_USERS and skel -# copy the installed user, not the deleted live account. -MAIN_USER="$(getent passwd 1000 | cut -d: -f1 || true)" -if [[ -z "$MAIN_USER" || "$MAIN_USER" == "liveuser" ]]; then - MAIN_USER="$(getent passwd | awk -F: '$3 >= 1000 && $3 < 60000 && $1 != "liveuser" { print $1; exit }')" -fi - # unpackfs copies the entire live squashfs onto the target. Remove live-only # packages (Calamares + archiso boot chain + memtest/EFI-shell payloads) so # they do not stay on disk forever. pacman -Rs (not -Rns) keeps /etc configs @@ -73,23 +67,15 @@ passwd -l root || true # over to the target (unpackfs may skip it / perms differ), leaving the installed # system unable to verify package signatures — the first `pacman -Syu` then dies # with "keyring is not writable / required key missing". Initialise it here so a -# fresh install can update out of the box. archlinux-keyring verifies official -# Arch packages; the BOS release key (56203B86…, shipped at -# /etc/pacman.d/breadway-repo.asc) verifies the signed [breadway] repo at -# dl.breadway.dev/arch — SigLevel = Required there, every package and the db -# carry a .sig from it. +# fresh install can update out of the box. archlinux-keyring is already present +# and is the only keyring populated — it verifies official Arch packages. +# [breadway] stays SigLevel=Never (Forgejo does not serve pacman-compatible +# db signatures). Do not import KEYS.asc here: that key signs ISO SHA256SUMS, +# not the pacman repo; treating it as a repo key would be a lie. # --------------------------------------------------------------------------- -BREADWAY_KEY_FPR="56203B86A110695AE7F310934AF3323D678EB5E2" if command -v pacman-key &>/dev/null; then pacman-key --init || echo "WARN: pacman-key --init failed" pacman-key --populate archlinux || echo "WARN: pacman-key --populate failed" - if [[ -f /etc/pacman.d/breadway-repo.asc ]]; then - pacman-key --add /etc/pacman.d/breadway-repo.asc \ - && pacman-key --lsign-key "$BREADWAY_KEY_FPR" \ - || echo "WARN: could not trust the [breadway] repo key — pacman -Sy will fail on [breadway]" - else - echo "WARN: /etc/pacman.d/breadway-repo.asc missing — [breadway] (SigLevel=Required) will not verify" - fi fi # --------------------------------------------------------------------------- diff --git a/iso/airootfs/etc/pacman.conf b/iso/airootfs/etc/pacman.conf index 2f53c10..4e4435e 100644 --- a/iso/airootfs/etc/pacman.conf +++ b/iso/airootfs/etc/pacman.conf @@ -32,17 +32,18 @@ Include = /etc/pacman.d/mirrorlist # are NOT here; they are bakery-baked into /usr/local at ISO build time. # # Packages are published to the Forgejo Arch registry (group "os") by the -# .forgejo/workflows/*.yml workflows; scripts/ci-publish-signed-repo.sh then -# collects them, detach-signs each .pkg.tar.zst with the BOS release key -# (releases@breadway.dev), runs `repo-add -s`, and publishes the signed db -# at https://dl.breadway.dev/arch/$arch (signed-repo.yml). +# .forgejo/workflows/*.yml workflows in this repo (and breadlock's). # -# SigLevel = Required: every package AND the db carry a .sig from key -# 56203B86A110695AE7F310934AF3323D678EB5E2 — the same key committed as -# KEYS.asc / etc/pacman.d/breadway-repo.asc, imported into the pacman -# keyring at build time (build-local.sh), on the live medium, and on the -# installed target (calamares/post-install.sh). +# Forgejo's Arch package registry does not serve pacman-compatible db +# signatures. SigLevel = Never is TLS-only integrity: the connection is +# HTTPS (or rewritten to hestia's localhost:3002 in CI). breadlock (PAM) +# rides this repo. Do NOT flip to SigLevel = Required unless a signed db +# has been verified to work — Required without signatures breaks the ISO +# and every install that uses [breadway]. KEYS.asc is the ISO SHA256SUMS +# signing key, not a pacman repo key. # ----------------------------------------------------------------------- -[breadway] -SigLevel = Required -Server = https://dl.breadway.dev/arch/$arch +# The section name must match Forgejo's served db filename +# ({owner}.{group}.{domain}.db) — pacman fetches "
.db" from Server. +[Breadway.os.git.breadway.dev] +SigLevel = Never +Server = https://git.breadway.dev/api/packages/Breadway/arch/os/$arch diff --git a/iso/airootfs/etc/pacman.d/breadway-repo.asc b/iso/airootfs/etc/pacman.d/breadway-repo.asc deleted file mode 100644 index fe380fd..0000000 --- a/iso/airootfs/etc/pacman.d/breadway-repo.asc +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- - -mDMEakhwGhYJKwYBBAHaRw8BAQdA/sZ/GYec5M2MD+w20mVF5tMUhGji210Dg7zL -TAhNsg60WUJPUyBSZWxlYXNlIFNpZ25pbmcgKGdpdC5icmVhZHdheS5kZXYvQnJl -YWR3YXkvYm9zIHJlbGVhc2VzIG9ubHkpIDxyZWxlYXNlc0BicmVhZHdheS5kZXY+ -iJYEExYKAD4WIQRWIDuGoRBpWufzEJNK8zI9Z4614gUCakhwGgIbIwUJA8JnAAUL -CQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRBK8zI9Z4614ggYAQDP8FTZ14i9YPKD -ARvZuP5QaYOUFhQ8uyG0CowXKy9O0AEAqYfjnvyJI3N651pVFSNUXyP16w1kMPSs -K0g3CLsztQ+4OARqSHAaEgorBgEEAZdVAQUBAQdAuJFuy2GHz5m9wXTm/PdSpLE9 -gERwHOLyM1OFuttrJW4DAQgHiH4EGBYKACYWIQRWIDuGoRBpWufzEJNK8zI9Z461 -4gUCakhwGgIbDAUJA8JnAAAKCRBK8zI9Z4614nzLAP9grcIFsAAeCyVKhziHmpXq -E0Hm6FfIr4sdEf63HZkyfwD/XeKeWfb3EWvVsloJrZZ9tDmR67iK52Hwl82wfFAU -cAo= -=Mrh1 ------END PGP PUBLIC KEY BLOCK----- diff --git a/iso/airootfs/etc/skel/.config/bread/modules/external-monitors.lua b/iso/airootfs/etc/skel/.config/bread/modules/external-monitors.lua deleted file mode 100644 index 27a276c..0000000 --- a/iso/airootfs/etc/skel/.config/bread/modules/external-monitors.lua +++ /dev/null @@ -1,228 +0,0 @@ --- external-monitors — behave like a normal laptop desktop --- --- Plug in any display (HDMI, DisplayPort, USB-C dock, a random TV) and --- the session just works. No output names to edit. --- --- • the laptop panel stays at its preferred (native) mode --- • each external uses its preferred mode and refresh --- • new screens clone the laptop (set ARRANGE = "extend" to sit to the right) --- • closing the lid does not sleep while an external is on --- • unplug everything and the laptop is the only display again --- --- Drop-in: copy to ~/.config/bread/modules/ and `bread reload`. - -local M = bread.module({ - name = "external-monitors", - version = "1.0.0", - after = { "bread.monitors" }, -}) - --- "mirror" = every external clones the laptop (presentations, TVs) --- "extend" = extra desktop to the right -local ARRANGE = "mirror" -local SCALE = "auto" - -local INTERNAL_RE = "^eDP" -local INHIBITOR = "/tmp/bread-lid-inhibitor.pid" - -local function inhibit_lid() - if bread.fs.exists(INHIBITOR) then return end - bread.exec( - "bash -c 'systemd-inhibit --what=handle-lid-switch --who=bread " - .. "--why=external-display sleep infinity & echo $! > " - .. INHIBITOR - .. "'" - ) -end - -local function release_lid() - bread.exec( - "bash -c 'kill $(cat " .. INHIBITOR .. " 2>/dev/null) 2>/dev/null; rm -f " .. INHIBITOR .. "'" - ) -end - -local function is_internal(name) - return type(name) == "string" and name:match(INTERNAL_RE) ~= nil -end - -local function drm_status(name) - for card = 0, 5 do - local raw = bread.fs.read(string.format("/sys/class/drm/card%d-%s/status", card, name)) - if raw then - return raw:match("^%s*(%S+)") - end - end - return nil -end - -local function drm_first_mode(name) - for card = 0, 5 do - local raw = bread.fs.read(string.format("/sys/class/drm/card%d-%s/modes", card, name)) - if raw then - local w, h = raw:match("(%d+)x(%d+)") - if w then - return tonumber(w), tonumber(h) - end - end - end - return 1920, 1080 -end - -local function list_connectors() - local names = {} - local ok, out = bread.exec_capture("ls /sys/class/drm", { timeout_ms = 500 }) - if not ok or not out then - return names - end - for ent in out:gmatch("[^%s]+") do - local name = ent:match("^card%d+%-(.+)$") - if name and not name:match("^Writeback") then - names[#names + 1] = name - end - end - table.sort(names) - return names -end - -local function connected() - local internal, externals = nil, {} - for _, name in ipairs(list_connectors()) do - if drm_status(name) == "connected" then - if is_internal(name) then - internal = internal or name - else - externals[#externals + 1] = name - end - end - end - return internal or "eDP-1", externals -end - --- BOS Hyprland talks Lua (`hl.monitor`). Stock Hyprland uses the --- `monitor=` keyword. Try eval first, then keyword. -local function apply_monitor(opts) - local extra = "" - if opts.mirror and opts.mirror ~= "" then - extra = string.format(", mirror = %q", opts.mirror) - end - local expr = string.format( - "hl.monitor({ output = %q, mode = %q, position = %q, scale = %q%s })", - opts.output, - opts.mode or "preferred", - opts.position or "0x0", - opts.scale or SCALE, - extra - ) - local resp = bread.hyprland.eval(expr) - if type(resp) == "string" and resp:match("error") then - local spec = string.format( - "%s, %s, %s, %s", - opts.output, - opts.mode or "preferred", - opts.position or "0x0", - opts.scale or SCALE - ) - if opts.mirror and opts.mirror ~= "" then - spec = spec .. ", mirror, " .. opts.mirror - end - bread.hyprland.keyword("monitor", spec) - end -end - -local function apply(internal, externals) - apply_monitor({ - output = internal, - mode = "preferred", - position = "0x0", - scale = SCALE, - }) - - if ARRANGE == "mirror" then - for _, name in ipairs(externals) do - apply_monitor({ - output = name, - mode = "preferred", - position = "0x0", - scale = SCALE, - mirror = internal, - }) - end - return - end - - local x = select(1, drm_first_mode(internal)) or 1920 - for _, name in ipairs(externals) do - apply_monitor({ - output = name, - mode = "preferred", - position = x .. "x0", - scale = SCALE, - }) - local w = select(1, drm_first_mode(name)) or 1920 - x = x + w - end -end - -function M.on_load() - local last = nil - local applied = false - - local function evaluate() - local internal, externals = connected() - local sig = internal .. "|" .. table.concat(externals, ",") - if sig == last then - return - end - last = sig - - if #externals == 0 then - if applied then - apply_monitor({ - output = internal, - mode = "preferred", - position = "0x0", - scale = SCALE, - }) - release_lid() - applied = false - end - return - end - - apply(internal, externals) - inhibit_lid() - applied = true - bread.log("[external-monitors] " .. internal .. " + " .. table.concat(externals, ", ")) - end - - local settle = bread.debounce(1500, evaluate) - - bread.on("bread.hyprland.monitor.connected", function(event) - local name = event.data and event.data.name - if name and not is_internal(name) then - bread.notify("Display connected: " .. name, { urgency = "low" }) - end - settle() - end) - - bread.on("bread.hyprland.monitor.disconnected", function() - settle() - end) - - bread.on("bread.device.**", function(event) - local sub = event.data and event.data.subsystem - if sub == "drm" then - settle() - end - end) - - bread.hyprland.on_raw("configreloaded", function() - last = nil - evaluate() - end) - - bread.every(3000, evaluate) - settle() -end - -return M diff --git a/iso/airootfs/etc/skel/.config/hypr/autostart.json b/iso/airootfs/etc/skel/.config/hypr/autostart.json index be2b4ac..ee66107 100644 --- a/iso/airootfs/etc/skel/.config/hypr/autostart.json +++ b/iso/airootfs/etc/skel/.config/hypr/autostart.json @@ -7,7 +7,6 @@ { "command": "breadhelp --autostart", "label": "BOS Help (first-run onboarding)", "enabled": true }, { "command": "bash -c 'command -v breadpaper >/dev/null && exec breadpaper listen'", "label": "Wallpaper command bus (breadpaper listen)", "enabled": true }, { "command": "bash -c 'command -v breadshot >/dev/null && exec breadshot listen'", "label": "Screenshot command bus (breadshot listen)", "enabled": true }, - { "command": "bash -c 'command -v breadlock >/dev/null && exec breadlock listen'", "label": "Lock command bus (breadlock listen)", "enabled": true }, { "command": "bash -c 'command -v breadbox >/dev/null && exec breadbox listen'", "label": "Launcher command bus (breadbox listen)", "enabled": true }, { "command": "bash -c 'command -v breadhelp >/dev/null && exec breadhelp listen'", "label": "Help command bus (breadhelp listen)", "enabled": true }, { "command": "bash -c 'command -v breadsearch >/dev/null && exec breadsearch listen'", "label": "Search command bus (breadsearch listen)", "enabled": true }, diff --git a/iso/airootfs/etc/skel/.config/hypr/hyprland.lua b/iso/airootfs/etc/skel/.config/hypr/hyprland.lua index cfa488b..565da5b 100644 --- a/iso/airootfs/etc/skel/.config/hypr/hyprland.lua +++ b/iso/airootfs/etc/skel/.config/hypr/hyprland.lua @@ -63,16 +63,6 @@ end hl.window_rule({ name = "breadhelp", match = { class = "^(com\\.breadway\\.breadhelp)$" }, float = true, size = { 880, 600 } }) hl.window_rule({ name = "bos-netsetup", match = { class = "^(bos-netsetup)$" }, float = true, size = { 700, 560 } }) --- --------------------------------------------------------------------------- --- Layer-shell rules — blur / ignore-alpha / per-namespace motion for the --- bread shell (breadbar island + osd + notif + panel, breadbox launcher, --- breadclip popup). Theme-driven via ~/.config/hypr/layerrules.json (written --- by `bread-theme layerrules` in the bootstrap below), with a hardcoded --- fallback so a missing/broken theme file can never leave the shell --- unblurred. Without these the launcher and popups get no compositor blur. --- --------------------------------------------------------------------------- -pcall(dofile, script_dir .. "ui/rules.lua") - -- --------------------------------------------------------------------------- -- Environment (vendor-neutral; no GPU-specific vars so it works on Intel/AMD). -- --------------------------------------------------------------------------- @@ -86,15 +76,6 @@ hl.env("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1") hl.env("SDL_VIDEODRIVER", "wayland") hl.env("ELECTRON_OZONE_PLATFORM_HINT", "auto") hl.env("_JAVA_AWT_WM_NONREPARENTING", "1") --- GTK4's default renderer (ngl/vulkan on GTK 4.14+) renders transparent --- layer-shell surfaces as opaque black on wlroots — the whole bread shell --- (breadbox launcher, breadclip popup, breadbar, breadhelp, bos-settings) --- goes black-on-black, and it's worse under a VM's virtio-gpu where no real --- GL/Vulkan context is available. cairo (software) always composites --- transparency correctly; the shell is flat colour/text/icons so there's no --- visible perf cost, and idle memory drops (~40%, no Mesa driver resident). --- Set GSK_RENDERER=gl in the session to override for a GPU-heavy GTK4 app. -hl.env("GSK_RENDERER", "cairo") -- Optional NVIDIA env from bos-nvidia-setup. Mesa machines have no file. -- bos-nvidia-setup: optional proprietary env; no-op when the file is absent @@ -147,12 +128,6 @@ hl.on("hyprland.start", function() -- Generate the shared bread GUI stylesheet first, so breadbar/breadbox/ -- bos-settings load it on start (they also live-reload if it changes). "bread-theme generate", - -- Write ~/.config/hypr/layerrules.json from the active shell theme's - -- [compositor] table. scripts/ui/rules.lua (loaded above) already ran - -- with the hardcoded fallback; this refreshes the JSON for the next - -- `hyprctl reload` / theme switch. Harmless if bread-theme lacks the - -- verb on an older build. - "sh -c 'bread-theme layerrules 2>/dev/null || true'", -- Global dark theme: GTK4/libadwaita + GTK3 theme + icon + cursor. "gsettings set org.gnome.desktop.interface color-scheme prefer-dark", "gsettings set org.gnome.desktop.interface gtk-theme Adwaita-dark", @@ -162,9 +137,9 @@ hl.on("hyprland.start", function() -- Clipboard history is breadclipd, a bakery-managed systemd --user -- service (auto-started from /usr/lib/systemd/user — see -- build-local.sh's service bake) rather than an exec-once here. - -- Prefer bread-polkit if it is on PATH (not baked; lockfile does not - -- ship it). Otherwise the ISO's polkit-gnome agent. command -v so a - -- missing binary does not leave the session without an auth agent. + -- Prefer bread-polkit when bakery has published it; otherwise the + -- ISO's polkit-gnome agent. command -v so a missing binary does not + -- leave the session without an auth agent. "sh -c 'if command -v bread-polkit >/dev/null; then exec bread-polkit; else exec /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1; fi'", "awww-daemon", -- Set the default wallpaper once the daemon is up (retry until ready). @@ -219,7 +194,6 @@ hl.on("hyprland.start", function() "breadhelp --autostart", "bash -c 'command -v breadpaper >/dev/null && exec breadpaper listen'", "bash -c 'command -v breadshot >/dev/null && exec breadshot listen'", - "bash -c 'command -v breadlock >/dev/null && exec breadlock listen'", "bash -c 'command -v breadbox >/dev/null && exec breadbox listen'", "bash -c 'command -v breadhelp >/dev/null && exec breadhelp listen'", "bash -c 'command -v breadsearch >/dev/null && exec breadsearch listen'", diff --git a/iso/airootfs/etc/skel/.config/hypr/scripts/system/autostart.lua b/iso/airootfs/etc/skel/.config/hypr/scripts/system/autostart.lua index 63e364f..46f4970 100644 --- a/iso/airootfs/etc/skel/.config/hypr/scripts/system/autostart.lua +++ b/iso/airootfs/etc/skel/.config/hypr/scripts/system/autostart.lua @@ -22,7 +22,6 @@ local DEFAULT_EXTRA = { { command = "breadhelp --autostart", enabled = true }, { command = "bash -c 'command -v breadpaper >/dev/null && exec breadpaper listen'", enabled = true }, { command = "bash -c 'command -v breadshot >/dev/null && exec breadshot listen'", enabled = true }, - { command = "bash -c 'command -v breadlock >/dev/null && exec breadlock listen'", enabled = true }, { command = "bash -c 'command -v breadbox >/dev/null && exec breadbox listen'", enabled = true }, { command = "bash -c 'command -v breadhelp >/dev/null && exec breadhelp listen'", enabled = true }, { command = "bash -c 'command -v breadsearch >/dev/null && exec breadsearch listen'", enabled = true }, diff --git a/iso/airootfs/etc/skel/.config/hypr/scripts/ui/rules.lua b/iso/airootfs/etc/skel/.config/hypr/scripts/ui/rules.lua deleted file mode 100644 index 79e0a2f..0000000 --- a/iso/airootfs/etc/skel/.config/hypr/scripts/ui/rules.lua +++ /dev/null @@ -1,136 +0,0 @@ --- scripts/ui/rules.lua — layer-shell (compositor) rules for the bread shell. --- --- Blur / ignore-alpha / per-namespace motion for breadbar (island + osd + --- notif + panel + dismiss), the breadbox launcher, and the breadclip popup. --- Window rules (float/centre for onboarding popups) live in hyprland.lua; --- this file is layer rules only. --- --- Theme-driven (bos-ui-demos THEME_SYSTEM_PLAN.md §9): `bread-theme --- layerrules` writes ~/.config/hypr/layerrules.json from the active shell --- theme's [compositor] table — blur / ignore_alpha / blur_popups / --- animation / no_anim, keyed by layer-shell namespace. That table owns --- *appearance* only; placement / workspace / focus are never touched here. --- If the JSON is missing, unreadable, malformed, or anything goes wrong --- while parsing it, apply_hardcoded_layer_rules() runs instead — the exact --- set this file hardcoded before the theme system existed — so a broken or --- absent theme file can never disable compositor blur. - -local LAYERRULES_JSON = os.getenv("HOME") .. "/.config/hypr/layerrules.json" - -local function apply_hardcoded_layer_rules() - hl.layer_rule({ - name = "breadbar-island", - match = { namespace = "^breadbar$" }, - blur = true, - ignore_alpha = 0.2, - blur_popups = true, - animation = "slide top", - }) - - hl.layer_rule({ - name = "breadbar-osd", - match = { namespace = "^breadbar-osd$" }, - blur = true, - ignore_alpha = 0.2, - animation = "slide bottom", - }) - - hl.layer_rule({ - name = "breadbar-notif", - match = { namespace = "^breadbar-notif$" }, - blur = true, - ignore_alpha = 0.2, - animation = "slide right", - }) - - hl.layer_rule({ - name = "breadbar-panel", - match = { namespace = "^breadbar-panel$" }, - blur = true, - ignore_alpha = 0.2, - animation = "slide right", - }) - - hl.layer_rule({ - name = "breadbar-dismiss", - match = { namespace = "^breadbar-dismiss$" }, - no_anim = true, - }) - - hl.layer_rule({ - match = "breadbox", - blur = true, - ignore_alpha = 0.2, - }) -end - --- Parses ~/.config/hypr/layerrules.json into a plain array of per-namespace --- rule tables, sorted by namespace for a deterministic emission order. --- Returns nil (not an error) for anything short of a well-formed, non-empty --- JSON object, so the pcall wrapping this only guards against a genuine Lua --- error (e.g. json.lua failing to load) rather than every malformed case. -local function parsed_layer_rules() - local json = dofile(os.getenv("HOME") .. "/.config/hypr/scripts/lib/json.lua") - local parsed = json.load(LAYERRULES_JSON) - if type(parsed) ~= "table" then - return nil - end - - local namespaces = {} - for ns, rule in pairs(parsed) do - if type(ns) == "string" and type(rule) == "table" then - namespaces[#namespaces + 1] = ns - end - end - if #namespaces == 0 then - return nil - end - table.sort(namespaces) - - local rules = {} - for _, ns in ipairs(namespaces) do - local r = parsed[ns] - rules[#rules + 1] = { - namespace = ns, - blur = r.blur == true, - ignore_alpha = r.ignore_alpha, - blur_popups = r.blur_popups == true, - animation = r.animation, - no_anim = r.no_anim == true, - } - end - return rules -end - --- Emits one hl.layer_rule per parsed namespace. Built as pure data by --- parsed_layer_rules() first (no hl.layer_rule calls during parsing), so a --- parse failure can never leave a partial JSON-derived rule set applied --- before the caller falls back to apply_hardcoded_layer_rules(). -local function apply_json_layer_rules(rules) - for _, r in ipairs(rules) do - hl.layer_rule({ - name = r.namespace, - match = { namespace = "^" .. r.namespace .. "$" }, - blur = r.blur, - ignore_alpha = r.ignore_alpha, - blur_popups = r.blur_popups, - animation = r.animation, - no_anim = r.no_anim, - }) - end -end - -local ok, rules = pcall(parsed_layer_rules) -if ok and rules then - apply_json_layer_rules(rules) -else - apply_hardcoded_layer_rules() -end - --- breadclip is not part of the shell theme's [compositor] table yet — always --- hardcoded, regardless of the JSON above. -hl.layer_rule({ - match = "breadclip", - blur = true, - ignore_alpha = 0.0, -}) diff --git a/iso/airootfs/root/customize_airootfs.sh b/iso/airootfs/root/customize_airootfs.sh deleted file mode 100644 index 149c6c4..0000000 --- a/iso/airootfs/root/customize_airootfs.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -# Run by mkarchiso inside the airootfs chroot, after packages are installed -# and before the squashfs is built. (archiso prints a deprecation warning for -# this hook, but there is no non-deprecated replacement for "trust an extra -# pacman repo key in the image keyring", and BOS ships no pacman-init.service.) -# -# Purpose: trust the BOS release key (56203B86…) in the image's pacman -# keyring so the signed [breadway] repo (SigLevel = Required, -# https://dl.breadway.dev/arch) verifies both on the live medium and — via -# calamares' unpackfs, which copies this squashfs to the target — on the -# installed system. calamares/post-install.sh re-does this in the target -# chroot as a fallback (unpackfs can skip /etc/pacman.d/gnupg). -set -euo pipefail - -BREADWAY_KEY_FPR="56203B86A110695AE7F310934AF3323D678EB5E2" -KEY_FILE="/etc/pacman.d/breadway-repo.asc" - -pacman-key --init -pacman-key --populate archlinux - -if [[ -f "$KEY_FILE" ]]; then - pacman-key --add "$KEY_FILE" - pacman-key --lsign-key "$BREADWAY_KEY_FPR" - echo "customize_airootfs: trusted [breadway] repo key $BREADWAY_KEY_FPR" -else - echo "customize_airootfs: WARNING $KEY_FILE missing; [breadway] will not verify" >&2 -fi diff --git a/iso/airootfs/usr/local/bin/bos-update b/iso/airootfs/usr/local/bin/bos-update index a34f70b..16b9da8 100644 --- a/iso/airootfs/usr/local/bin/bos-update +++ b/iso/airootfs/usr/local/bin/bos-update @@ -47,15 +47,7 @@ fi echo bold "==> Bread ecosystem (bakery update --all)" if command -v bakery >/dev/null; then - # /usr/local is root-owned. Never run bakery as the user against it; - # bakery itself also tries sudo -n then pkexec for privileged writes. - if sudo -n true >/dev/null 2>&1; then - sudo -n bakery update --all || echo "WARN: bakery update failed" - elif command -v pkexec >/dev/null; then - pkexec bakery update --all || echo "WARN: bakery update failed" - else - echo "WARN: bakery update needs sudo -n or pkexec for /usr/local" - fi + bakery update --all || echo "WARN: bakery update failed" else echo "bakery not found; skipping" fi diff --git a/iso/bread-lockfile.toml b/iso/bread-lockfile.toml index 8e21593..6154893 100644 --- a/iso/bread-lockfile.toml +++ b/iso/bread-lockfile.toml @@ -3,8 +3,8 @@ # build-local.sh and CI (scripts/ci-stage-bakery.py) read this file. A missing # *required* binary fails the bake: a hollow ISO is worse than a failed build. # optional_bins are baked when the verified stable index publishes them, and -# skipped with a warning when it does not. bread 0.8.0 ships bread-emit and -# bread-module-host, so those are required_bins. +# skipped with a warning when it does not (today: bread 0.8.0 has no +# bread-emit / bread-module-host). # # A flat `bins` list is still accepted and treated as required_bins. # @@ -23,8 +23,6 @@ required_bins = [ "bakery", "bread", "breadd", - "bread-emit", - "bread-module-host", "breadman", "breadbar", "breadbox", @@ -43,13 +41,19 @@ required_bins = [ "breadhelp", ] +# Bake if the verified index publishes them; do not fail the ISO if absent. +optional_bins = [ + "bread-emit", + "bread-module-host", +] + # Package name → version. Must exist at dl.breadway.dev/// and # should match the signed index so CI can verify sha256. # [[pin]] { package, version } is accepted as well and merged (conflict = bake error). [versions] -bakery = "0.7.4" +bakery = "0.7.3" bread = "0.8.0" -bread-theme = "0.7.4" +bread-theme = "0.7.3" breadbar = "0.3.2" breadbox = "0.3.2" breadcrumbs = "2.1.8" diff --git a/iso/packages.x86_64 b/iso/packages.x86_64 index d30488a..ff90edf 100644 --- a/iso/packages.x86_64 +++ b/iso/packages.x86_64 @@ -225,8 +225,6 @@ slurp wl-clipboard playerctl # Wallpaper daemon + pywal (drives the bread* colour palette from the wallpaper). -# python-pywal was dropped from Arch [extra] (AUR-only now) — republished to -# [breadway], see packaging/python-pywal. awww python-pywal # Boot splash (BOS logo + spinner instead of kernel text). diff --git a/iso/pacman.conf b/iso/pacman.conf index abb7e2f..be3d52f 100644 --- a/iso/pacman.conf +++ b/iso/pacman.conf @@ -49,17 +49,18 @@ Include = /etc/pacman.d/mirrorlist # are NOT here; they are bakery-baked into /usr/local at ISO build time. # # Packages are published to the Forgejo Arch registry (group "os") by the -# .forgejo/workflows/*.yml workflows; scripts/ci-publish-signed-repo.sh then -# collects them, detach-signs each .pkg.tar.zst with the BOS release key -# (releases@breadway.dev), runs `repo-add -s`, and publishes the signed db -# at https://dl.breadway.dev/arch/$arch (signed-repo.yml). +# .forgejo/workflows/*.yml workflows in this repo (and breadlock's). # -# SigLevel = Required: every package AND the db carry a .sig from key -# 56203B86A110695AE7F310934AF3323D678EB5E2 — the same key committed as -# KEYS.asc / airootfs/etc/pacman.d/breadway-repo.asc, imported into the -# pacman keyring at build time (build-local.sh), on the live medium, and -# on the installed target (calamares/post-install.sh). +# Forgejo's Arch package registry does not serve pacman-compatible db +# signatures. SigLevel = Never is TLS-only integrity: the connection is +# HTTPS (or rewritten to hestia's localhost:3002 in CI). breadlock (PAM) +# rides this repo. Do NOT flip to SigLevel = Required unless a signed db +# has been verified to work — Required without signatures breaks the ISO +# and every install that uses [breadway]. KEYS.asc is the ISO SHA256SUMS +# signing key, not a pacman repo key. # ----------------------------------------------------------------------- -[breadway] -SigLevel = Required -Server = https://dl.breadway.dev/arch/$arch +# The section name must match Forgejo's served db filename +# ({owner}.{group}.{domain}.db) — pacman fetches "
.db" from Server. +[Breadway.os.git.breadway.dev] +SigLevel = Never +Server = https://git.breadway.dev/api/packages/Breadway/arch/os/$arch diff --git a/packaging/arch/README.md b/packaging/arch/README.md index 1116280..ce80f7e 100644 --- a/packaging/arch/README.md +++ b/packaging/arch/README.md @@ -3,7 +3,7 @@ Arch packaging This directory only holds `PKGBUILD`s for third-party AUR packages BOS republishes to the `[breadway]` pacman repo (`calamares`, `bibata`, -`powerlevel10k`, `yay-bin`, `python-pywal`) — not the user's own code. See each +`powerlevel10k`, `yay-bin`) — not the user's own code. See each subdirectory's `.forgejo/workflows/.yml` (in this repo) for how each one publishes on a push to `packaging//**`. diff --git a/packaging/python-pywal/PKGBUILD b/packaging/python-pywal/PKGBUILD deleted file mode 100644 index b6796f5..0000000 --- a/packaging/python-pywal/PKGBUILD +++ /dev/null @@ -1,44 +0,0 @@ -# BOS in-house rebuild of python-pywal. -# -# python-pywal was dropped from Arch's [extra] repo (it is now AUR-only), but -# BOS needs the `wal` binary: bread-theme shells out to it to extract a colour -# palette from the user's wallpaper. Republished to [breadway] so the ISO can -# pull it via pacman, same pattern as calamares / bibata / powerlevel10k / -# yay-bin. Source of truth: https://aur.archlinux.org/packages/python-pywal -# -# Maintainer: Breadway -# Upstream maintainer: Morten Linderud -# Contributor: Sean Haugh - -pkgname=python-pywal -pkgver=3.3.0 -pkgrel=11 -pkgdesc="Generate and change colorschemes on the fly" -arch=('any') -url="https://github.com/dylanaraps/pywal/" -license=('MIT') -depends=('python' 'imagemagick') -makedepends=('python-build' 'python-installer' 'python-wheel' 'python-setuptools') -optdepends=('feh: set wallpaper' - 'nitrogen: set wallpaper') -# BOS PKGBUILDs verify sources by sha256 only (no source PGP), matching -# calamares / powerlevel10k here. -source=("$pkgname-$pkgver.tar.gz::https://github.com/dylanaraps/pywal/archive/${pkgver}.tar.gz") -sha256sums=('fe8fc1c29d1cad1a1a8580293dcfe32e1fac259f9dbfd5c8877439fa5948d189') - -build() { - cd "pywal-${pkgver}" - # setup.py-only project: python-build injects the setuptools backend. - python -m build --wheel --no-isolation -} - -check() { - cd "pywal-${pkgver}" - python -m unittest discover -vs tests -} - -package() { - cd "pywal-${pkgver}" - python -m installer --destdir="$pkgdir" dist/*.whl - install -Dm644 LICENSE.md "$pkgdir/usr/share/licenses/$pkgname/LICENSE" -} diff --git a/scripts/ci-publish-signed-repo.sh b/scripts/ci-publish-signed-repo.sh index 6ded0e0..08fbb53 100755 --- a/scripts/ci-publish-signed-repo.sh +++ b/scripts/ci-publish-signed-repo.sh @@ -22,7 +22,6 @@ PACKAGES=( bibata-cursor-theme-bin zsh-theme-powerlevel10k yay-bin - python-pywal ) ARCH="${BREADWAY_ARCH:-x86_64}" @@ -82,8 +81,6 @@ repo_add_signed() { fi [[ -e breadway.db.tar.gz.sig || -e breadway.db.sig ]] \ || die "repo-add -s did not write breadway.db*.sig" - # gpg writes 0600; nginx and the next publish need world-readable files. - find . -maxdepth 1 -type f -exec chmod a+r {} + || true } ensure_arch_tools() { @@ -128,12 +125,7 @@ sign_and_index_anywhere() { rt="$(container_runtime)" || die \ "need host gpg+repo-add, or docker/podman to run archlinux:latest (no Forgejo container: — host must see /srv/breadway-dl)" # Host job + bind-mount, same reason bakery writes /srv without container:. - # Run as the runner user: root-owned 0600 .sig files made chmod/nginx fail - # (run 1050) and would block the next `rm -rf` of a previous tree. "$rt" run --rm --network=host \ - --user "$(id -u):$(id -g)" \ - -e HOME=/tmp \ - -e TMPDIR=/tmp \ -e GPG_PRIVATE_KEY \ -e BREADWAY_SIGN_ONLY=1 \ -e BREADWAY_REPO_DIR=/repo \ @@ -251,10 +243,8 @@ publish_tree() { parent="$(dirname "$DEST")" dest_name="$(basename "$DEST")" mkdir -p "$parent" - chmod a+rX "$STAGE" || true - # gpg --detach-sign often writes 0600 files the runner cannot chmod; - # do not fail the publish after repo-add -s already succeeded. - find "$STAGE" -type f -exec chmod a+r {} + || true + chmod a+rX "$STAGE" + find "$STAGE" -type f -exec chmod a+r {} + prev="$parent/${dest_name}.prev" rm -rf "$prev" if [[ -e "$DEST" ]]; then diff --git a/scripts/smoke-test.sh b/scripts/smoke-test.sh index 28b5c28..ccdc571 100755 --- a/scripts/smoke-test.sh +++ b/scripts/smoke-test.sh @@ -40,15 +40,22 @@ check "grub-btrfs present" "pacman -Qq grub-btrfs" echo "== enabled system services ==" for unit in NetworkManager.service greetd.service bluetooth.service tlp.service \ - cups.socket avahi-daemon.socket ufw.service systemd-timesyncd.service; do + cups.socket avahi-daemon.service ufw.service systemd-timesyncd.service; do check "$unit enabled" "systemctl is-enabled $unit" done check "graphical.target is default" "[ \"\$(systemctl get-default)\" = graphical.target ]" echo "== bread ecosystem on PATH ==" -for bin in bakery bread breadd bread-emit bread-module-host breadbar breadbox breadbox-sync breadcrumbs breadpad breadman; do +for bin in bakery bread breadd breadbar breadbox breadbox-sync breadcrumbs breadpad breadman; do check "$bin found" "command -v $bin" done +for bin in bread-emit bread-module-host; do + if command -v "$bin" >/dev/null 2>&1; then + ok "$bin found" + else + note "$bin not on PATH (optional until stable bread ships it)" + fi +done echo "== bos-settings ==" check "bos-settings installed" "command -v bos-settings"