Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
367 changes: 233 additions & 134 deletions .github/workflows/release.yml

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

All notable changes to Bootable are documented here.

## 0.1.1 — 2026-08-27

- Added native Linux AppImage, DEB, and RPM packages, each containing the desktop app, TUI, and
protected write helper.
- Added a macOS DMG with an application bundle and explicit privileged-helper installer.
- Added Windows MSI and setup EXE installers plus direct portable GUI and TUI executables.
- Added package-content, embedded-version, checksum, and installer extraction checks to the release
workflow, with SHA-256 sidecars and provenance for every published artifact.

## 0.1.0 — 2026-08-27

- Reworked the desktop and terminal interfaces around the same workspace-first flow, shared
Expand Down
4 changes: 4 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ behavior does not count as implementation.
Do not copy code from Rufus, WoeUSB, or other projects whose license is incompatible with this
Apache-2.0 repository. Behavioral research and clean-room implementations are welcome.

Every same-repository pull request publishes a release candidate only after both CI and the native
package matrix pass. Stable releases require an explicit manual dispatch from `main`; see
[release channels](docs/releases.md).

Documentation and product copy must follow the same standard as destructive code:

- Lead with the task, constraint, or result.
Expand Down
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ default-members = [
resolver = "2"

[workspace.package]
version = "0.1.0"
version = "0.1.1"
edition = "2024"
license = "Apache-2.0"
rust-version = "1.88"
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
<p align="center"><strong>Create and verify bootable USB and SD drives.</strong></p>

<p align="center">
<a href="https://github.com/debpalash/bootable/releases/download/v0.1.0/bootable-0.1.0-x86_64-unknown-linux-gnu.tar.gz"><strong>Linux</strong></a> ·
<a href="https://github.com/debpalash/bootable/releases/download/v0.1.0/bootable-0.1.0-x86_64-pc-windows-msvc.zip"><strong>Windows</strong></a> ·
<a href="https://github.com/debpalash/bootable/releases/download/v0.1.0/bootable-0.1.0-aarch64-apple-darwin.tar.gz"><strong>macOS</strong></a> ·
<a href="https://github.com/debpalash/bootable/releases/download/v0.1.1/bootable-0.1.1-x86_64.AppImage"><strong>Linux AppImage</strong></a> ·
<a href="https://github.com/debpalash/bootable/releases/download/v0.1.1/bootable-0.1.1-x86_64-setup.exe"><strong>Windows installer</strong></a> ·
<a href="https://github.com/debpalash/bootable/releases/download/v0.1.1/bootable-0.1.1-aarch64.dmg"><strong>macOS DMG</strong></a> ·
<a href="https://bootable.palash.dev/download.html">All downloads and checksums</a>
</p>

Expand Down Expand Up @@ -65,7 +65,8 @@ curl -fsSL https://bootable.palash.dev/install.sh | sh -s -- --tui
curl -fsSL https://bootable.palash.dev/install.sh | sh -s -- --all
```

Windows: download and extract the ZIP, then run:
Native packages are also available as DEB/RPM on Linux, MSI on Windows, and DMG on macOS. For the
portable Windows ZIP, extract it and run:

```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File .\install.ps1 -Variant All
Expand All @@ -92,6 +93,7 @@ Project links
[Architecture](docs/architecture.md) ·
[Validation](docs/validation.md) ·
[GUI/TUI parity](docs/ui-parity.md) ·
[Release channels](docs/releases.md) ·
[Contributing](CONTRIBUTING.md) ·
[Changelog](CHANGELOG.md) ·
[Report a problem](https://github.com/debpalash/bootable/issues/new?template=bug-report.yml)
Expand Down
Binary file added assets/bootable-mark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/bootable.ico
Binary file not shown.
29 changes: 29 additions & 0 deletions docs/releases.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Release channels

Bootable has two GitHub release channels. The rules live in CI and are not optional release
conventions.

## Release candidates

Every same-repository pull request runs the complete CI and native package matrices. Once both
workflows pass, CI publishes an automatic GitHub prerelease named
`v<version>-rc.pr<number>.<attempt>` with the Linux, macOS, and Windows assets from that exact pull
request commit.

Pull requests from forks are deliberately excluded from publishing: their code is tested with a
read-only token, but it is never distributed under the project's GitHub Releases account.

## Stable releases

A stable release is never created by a tag push or merge. A maintainer must explicitly run the
`Release` workflow from the `main` branch. CI rebuilds and verifies every native package, attests
the stable artifacts, and publishes the Cargo workspace version as `v<version>`.

Before dispatching a stable release:

1. Confirm the intended version is committed in `Cargo.toml` and `Cargo.lock` on `main`.
2. Confirm the release-candidate assets were installed or opened on their target platforms.
3. Open **Actions → Release → Run workflow**, select `main`, and approve the run.
4. Confirm the resulting release is neither a draft nor a prerelease and contains all 22 assets.

Stable tags and releases are immutable. Corrections use a new patch version.
36 changes: 36 additions & 0 deletions packaging/Packager.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name = "bootable"
product-name = "Bootable"
identifier = "app.bootable.Bootable"
version = "0.1.1"
description = "Create verified boot media from trusted images"
long-description = "A safety-first boot media writer with matching desktop and terminal interfaces."
homepage = "https://github.com/debpalash/bootable"
authors = ["Bootable contributors"]
publisher = "Bootable contributors"
category = "Utility"
license-file = "../LICENSE"
icons = ["../assets/bootable.ico"]
resources = ["../README.md", "../LICENSE"]
formats = ["wix", "nsis"]
out-dir = "../dist/windows"
binaries-dir = "../target/x86_64-pc-windows-msvc/release"
target-triple = "x86_64-pc-windows-msvc"

[[binaries]]
path = "bootable-desktop"
main = true

[[binaries]]
path = "bootable"

[[binaries]]
path = "bootable-helper"

[nsis]
installer-mode = "perMachine"
installer-icon = "../assets/bootable.ico"
compression = "lzma"
languages = ["English"]

[wix]
languages = ["en-US"]
2 changes: 1 addition & 1 deletion scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
set -eu

REPOSITORY="${BOOTABLE_REPOSITORY:-debpalash/bootable}"
VERSION="${BOOTABLE_VERSION:-0.1.0}"
VERSION="${BOOTABLE_VERSION:-0.1.1}"
VARIANT="${1:---gui}"
INSTALL_ROOT="${BOOTABLE_INSTALL_ROOT:-${HOME}/.local}"

Expand Down
176 changes: 176 additions & 0 deletions scripts/package-linux.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
#!/usr/bin/env bash
set -euo pipefail

version="${1:?usage: package-linux.sh VERSION [TARGET] [OUTPUT_DIR]}"
target="${2:-x86_64-unknown-linux-gnu}"
output="${3:-dist/linux}"
root="$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)"
binary_dir="$root/target/$target/release"
linuxdeploy="${LINUXDEPLOY:-linuxdeploy-x86_64.AppImage}"
appimagetool="${APPIMAGETOOL:-appimagetool-x86_64.AppImage}"

for executable in bootable bootable-desktop bootable-helper; do
test -x "$binary_dir/$executable" || {
echo "missing executable: $binary_dir/$executable" >&2
exit 1
}
done
command -v dpkg-deb >/dev/null
command -v rpmbuild >/dev/null
test -x "$linuxdeploy"
test -x "$appimagetool"

output="$root/$output"
mkdir -p "$output"
work="$(mktemp -d "${TMPDIR:-/tmp}/bootable-linux-package.XXXXXX")"
trap 'rm -rf "$work"' EXIT

install_payload() {
local destination="$1"
install -D -m 0755 "$binary_dir/bootable" "$destination/usr/bin/bootable"
install -D -m 0755 "$binary_dir/bootable-desktop" "$destination/usr/bin/bootable-desktop"
install -D -m 0755 "$binary_dir/bootable-helper" "$destination/usr/libexec/bootable-helper"
install -D -m 0644 "$root/assets/bootable-mark.svg" \
"$destination/usr/share/icons/hicolor/scalable/apps/bootable.svg"
install -D -m 0644 "$root/assets/bootable-mark.png" \
"$destination/usr/share/icons/hicolor/1024x1024/apps/bootable.png"
install -D -m 0644 "$root/packaging/app.bootable.write-media.policy" \
"$destination/usr/share/polkit-1/actions/app.bootable.write-media.policy"
install -D -m 0644 "$root/README.md" "$destination/usr/share/doc/bootable/README.md"
install -D -m 0644 "$root/LICENSE" "$destination/usr/share/doc/bootable/LICENSE"
mkdir -p "$destination/usr/share/applications"
sed 's|@EXEC@|/usr/bin/bootable-desktop|g' \
"$root/packaging/app.bootable.Bootable.desktop" \
> "$destination/usr/share/applications/app.bootable.Bootable.desktop"
chmod 0644 "$destination/usr/share/applications/app.bootable.Bootable.desktop"
}

deb_root="$work/deb"
install_payload "$deb_root"
mkdir -p "$deb_root/DEBIAN"
installed_size="$(du -sk "$deb_root/usr" | awk '{print $1}')"
cat > "$deb_root/DEBIAN/control" <<EOF
Package: bootable
Version: $version
Section: utils
Priority: optional
Architecture: amd64
Installed-Size: $installed_size
Maintainer: Bootable contributors <noreply@github.com>
Homepage: https://github.com/debpalash/bootable
Depends: libc6, libfontconfig1, libxkbcommon-x11-0, polkitd | policykit-1
Description: Safety-first boot media writer
Bootable provides matching desktop and terminal interfaces for inspecting,
writing, and verifying bootable images on removable media.
EOF
deb_asset="$output/bootable_${version}_amd64.deb"
dpkg-deb --build --root-owner-group "$deb_root" "$deb_asset"

rpm_top="$work/rpmbuild"
mkdir -p "$rpm_top"/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}
install -m 0755 "$binary_dir/bootable" "$rpm_top/SOURCES/bootable"
install -m 0755 "$binary_dir/bootable-desktop" "$rpm_top/SOURCES/bootable-desktop"
install -m 0755 "$binary_dir/bootable-helper" "$rpm_top/SOURCES/bootable-helper"
install -m 0644 "$root/assets/bootable-mark.svg" "$rpm_top/SOURCES/bootable.svg"
install -m 0644 "$root/assets/bootable-mark.png" "$rpm_top/SOURCES/bootable.png"
install -m 0644 "$root/packaging/app.bootable.write-media.policy" "$rpm_top/SOURCES/app.bootable.write-media.policy"
sed 's|@EXEC@|/usr/bin/bootable-desktop|g' \
"$root/packaging/app.bootable.Bootable.desktop" \
> "$rpm_top/SOURCES/app.bootable.Bootable.desktop"
install -m 0644 "$root/README.md" "$rpm_top/SOURCES/README.md"
install -m 0644 "$root/LICENSE" "$rpm_top/SOURCES/LICENSE"
cat > "$rpm_top/SPECS/bootable.spec" <<EOF
Name: bootable
Version: $version
Release: 1%{?dist}
Summary: Safety-first boot media writer
License: Apache-2.0
URL: https://github.com/debpalash/bootable
Requires: fontconfig, libxkbcommon-x11, polkit

%description
Bootable provides matching desktop and terminal interfaces for inspecting,
writing, and verifying bootable images on removable media.

%prep

%build

%install
install -Dpm0755 %{_sourcedir}/bootable %{buildroot}%{_bindir}/bootable
install -Dpm0755 %{_sourcedir}/bootable-desktop %{buildroot}%{_bindir}/bootable-desktop
install -Dpm0755 %{_sourcedir}/bootable-helper %{buildroot}/usr/libexec/bootable-helper
install -Dpm0644 %{_sourcedir}/bootable.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/apps/bootable.svg
install -Dpm0644 %{_sourcedir}/bootable.png %{buildroot}%{_datadir}/icons/hicolor/1024x1024/apps/bootable.png
install -Dpm0644 %{_sourcedir}/app.bootable.Bootable.desktop %{buildroot}%{_datadir}/applications/app.bootable.Bootable.desktop
install -Dpm0644 %{_sourcedir}/app.bootable.write-media.policy %{buildroot}%{_datadir}/polkit-1/actions/app.bootable.write-media.policy
install -Dpm0644 %{_sourcedir}/README.md %{buildroot}%{_docdir}/bootable/README.md
install -Dpm0644 %{_sourcedir}/LICENSE %{buildroot}%{_licensedir}/bootable/LICENSE

%files
%{_bindir}/bootable
%{_bindir}/bootable-desktop
/usr/libexec/bootable-helper
%{_datadir}/applications/app.bootable.Bootable.desktop
%{_datadir}/icons/hicolor/scalable/apps/bootable.svg
%{_datadir}/icons/hicolor/1024x1024/apps/bootable.png
%{_datadir}/polkit-1/actions/app.bootable.write-media.policy
%doc %{_docdir}/bootable/README.md
%license %{_licensedir}/bootable/LICENSE

%changelog
* Thu Aug 27 2026 Bootable contributors <noreply@github.com> - $version-1
- Native installer release.
EOF
rpmbuild --define "_topdir $rpm_top" -bb "$rpm_top/SPECS/bootable.spec"
rpm_asset="$(find "$rpm_top/RPMS" -type f -name '*.rpm' -print -quit)"
test -n "$rpm_asset"
cp "$rpm_asset" "$output/bootable-${version}-1.x86_64.rpm"

appdir="$work/Bootable.AppDir"
install_payload "$appdir"
# linuxdeploy accepts SVG icons but rejects the 1024px hicolor size that is
# useful to native packages. Keep the high-resolution PNG in DEB/RPM and let
# the AppImage use the scalable mark.
rm -f "$appdir/usr/share/icons/hicolor/1024x1024/apps/bootable.png"
sed 's|@EXEC@|bootable-desktop|g' \
"$root/packaging/app.bootable.Bootable.desktop" \
> "$appdir/usr/share/applications/app.bootable.Bootable.desktop"
# The adjacent helper lets the runtime retain its fixed-name fallback inside the AppImage.
install -m 0755 "$binary_dir/bootable-helper" "$appdir/usr/bin/bootable-helper"
"$linuxdeploy" \
--appdir "$appdir" \
--executable "$appdir/usr/bin/bootable-desktop" \
--executable "$appdir/usr/bin/bootable" \
--executable "$appdir/usr/bin/bootable-helper" \
--desktop-file "$appdir/usr/share/applications/app.bootable.Bootable.desktop" \
--icon-file "$appdir/usr/share/icons/hicolor/scalable/apps/bootable.svg"
cat > "$appdir/AppRun" <<'EOF'
#!/bin/sh
set -eu
appdir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
if [ "${1:-}" = "--tui" ]; then
shift
exec "$appdir/usr/bin/bootable" "$@"
fi
exec "$appdir/usr/bin/bootable-desktop" "$@"
EOF
chmod 0755 "$appdir/AppRun"
ARCH=x86_64 "$appimagetool" "$appdir" "$output/bootable-${version}-x86_64.AppImage"

archive_stage="$work/archive"
mkdir -p "$archive_stage"
install -m 0755 "$binary_dir/bootable" "$archive_stage/bootable"
install -m 0755 "$binary_dir/bootable-desktop" "$archive_stage/bootable-desktop"
install -m 0755 "$binary_dir/bootable-helper" "$archive_stage/bootable-helper"
install -m 0755 "$root/scripts/install.sh" "$archive_stage/install.sh"
install -m 0644 "$root/assets/bootable-mark.svg" "$archive_stage/bootable.svg"
install -m 0644 "$root/packaging/app.bootable.Bootable.desktop" "$archive_stage/app.bootable.Bootable.desktop"
install -m 0644 "$root/packaging/app.bootable.write-media.policy" "$archive_stage/app.bootable.write-media.policy"
install -m 0644 "$root/README.md" "$root/LICENSE" "$archive_stage/"
tar -C "$archive_stage" -czf "$output/bootable-${version}-${target}.tar.gz" .

for asset in "$output"/*; do
case "$asset" in *.sha256) continue ;; esac
(cd "$output" && sha256sum "$(basename "$asset")" > "$(basename "$asset").sha256")
done
Loading
Loading