Compare commits

..

No commits in common. "main" and "stagex-rewrite" have entirely different histories.

29 changed files with 123 additions and 967 deletions

1
.gitattributes vendored
View File

@ -1,2 +1 @@
dist/*.iso filter=lfs diff=lfs merge=lfs -text
dist/airgap.iso filter=lfs diff=lfs merge=lfs -text

1
.gitignore vendored
View File

@ -1,4 +1,3 @@
cache/
out/
out*/
.*

View File

@ -1,257 +1,69 @@
FROM stagex/user-alsa-lib:sx2025.02.0@sha256:5e29d15860ea2f01b7b4a614d2ffbc6bb41b87b8892138a93b4adca206105593 AS user-alsa-lib
FROM stagex/core-bash:sx2025.02.0@sha256:ae98e66f8623629151d79fd2b574442778b50bd37511dea8da4237d4c18ce04c AS core-bash
FROM stagex/core-bc:sx2025.02.0@sha256:8f0a8d3e86a2221f5179a1817f482013dbc5b5f8f985c1a3404a6f3975c5eda9 AS core-bc
FROM stagex/core-busybox:sx2025.02.0@sha256:01b31cc07543733fbf6889e596427af943aba2780bc2f514a3d30bb290da7e2a AS core-busybox
FROM stagex/user-ccid:sx2025.02.0@sha256:a2ab2199974a60fc711e881e8cda43007bd39482213fd9fa50c9580e027d6fa8 AS user-ccid
FROM stagex/user-cpio:sx2025.02.0@sha256:d8837d12a89ef7e35c72115a7919224a3246a2e17a685b684628cc03957726ac AS user-cpio
FROM stagex/core-curl:sx2025.02.0@sha256:b65975066d7b2256c51601749d947fa54ce9a23d4f2b46f4de7daf6f11f9730f AS core-curl
FROM stagex/user-dtc:sx2025.02.0@sha256:39231aa3e2ca4e3ac46aa7faea4e7aee5733f425c35ae5ca83e54ce5b3629f89 AS user-dtc
FROM stagex/user-eudev:sx2025.02.0@sha256:292ece79a82c2d2dc422d44a0d4e65dd6dde0304566a40f286e8e2ff62b59c52 AS user-eudev
FROM stagex/user-flashtools:sx2025.02.0@sha256:1d3aa7c7e6f061e2f738b9bf01d9584786c9b96ae5f0e84d302278ae687a58cc AS user-flashtools
FROM stagex/core-gcc:sx2025.02.0@sha256:02896413375c15cbff666fbab7c534caefc8936d53e167a6ea457a05c27e8096 AS core-gcc
FROM stagex/user-glib:sx2025.02.0@sha256:b7e6e23e3d95b95f1e9183f3571bba21ebc2304c3ce5b545962651d29706f901 AS user-glib
FROM stagex/core-gmp:sx2025.02.0@sha256:dfff470ef36b4383854435429fc5896b8e4f953fe7d0ec3ccff5422a651d0115 AS core-gmp
FROM stagex/user-gpg:sx2025.02.0@sha256:df188d540aa18e8b9684941bff9a591270765141f0ad5a87a0e1d7cd9961da7a AS user-gpg
FROM stagex/user-grub:sx2025.02.0@sha256:f2a574d88520fbc37ac233e3380d6cc89ce969e0abd36626fb04179355cf1d92 AS user-grub
FROM stagex/user-icepick:sx2025.02.0@sha256:1d26fbf252a2ae7469b3dc4358fe11e17a54403ab184b58283798566c7f5972f AS user-icepick
FROM stagex/user-ipxe:sx2025.02.0@sha256:bac91399972e5a12b534ee92ac6be103a9d28758c609926f168924eb9a175e4b AS user-ipxe
FROM stagex/user-jq:sx2025.02.0@sha256:c6b5baceb4c171859d7a75c2919f12558fee7951db3fd87dae76076ac9d85fda AS user-jq
FROM stagex/user-keyfork:sx2025.02.0@sha256:fbd40df303d57d7bc6209a7f59a64ec8ddddb2c607564591cdbae5b2acf70d2c AS user-keyfork
FROM stagex/user-libaio:sx2025.02.0@sha256:6ec20e9f3a77c555a6bfcecd5b3461740fc6d3faa9a0f81b97ca3606819ef26b AS user-libaio
FROM stagex/user-libassuan:sx2025.02.0@sha256:3aa891c65990114ba697d1bcf90c51515947daf932ce96d8861658391206c8c7 AS user-libassuan
FROM stagex/core-libffi:sx2025.02.0@sha256:8b22d8fa8aa4da590fcc7257aba1b6a2eb74598f5f60a95900050bf00ce470ac AS core-libffi
FROM stagex/user-libgcrypt:sx2025.02.0@sha256:2281a0b1093d2bc60f4208f3a34f7e01440c3dac31f122ed9b42a2417d4085c8 AS user-libgcrypt
FROM stagex/user-libgpg-error:sx2025.02.0@sha256:902cfc4a40cc69e003dec008f4bbf86338f5984847d11f0d422f06a797e656b4 AS user-libgpg-error
FROM stagex/user-libksba:sx2025.02.0@sha256:e6b7bd3a005a881b545b6b4066dc6392d741e1f062718428f9115db1a1edf23a AS user-libksba
FROM stagex/user-libqrencode:sx2025.02.0@sha256:e6ed8097b670b0ea79018a50efc0cdde3968a2165b9ff3b7b96af92fc8a43b45 AS user-libqrencode
FROM stagex/user-libseccomp:sx2025.02.0@sha256:632684b54847814367247b8d1247832fa56bb0dd8300495c342b0585cca47c10 AS user-libseccomp
FROM stagex/user-libslirp:sx2025.02.0@sha256:29d98f357f98f91e634659b945ccbe834d37f4c9c7e243aeb8d47ed438df741d AS user-libslirp
FROM stagex/user-libtpms:sx2025.02.0@sha256:09b410b27db7e3adbf61019fbdb6bb09fad597cb32de37f869b2f157332c771b AS user-libtpms
FROM stagex/core-libunwind:sx2025.02.0@sha256:99e2574ace4f7dfa3d8bfc93ab69e1fd5f559924a80f5372b74ed868299e7131 AS core-libunwind
FROM stagex/user-libusb:sx2025.02.0@sha256:b78ca9194fdb8dfb7b7177d16a156fac21e6c9822a0c35a17841400bc1a27f68 AS user-libusb
FROM stagex/user-libzbar:sx2025.02.0@sha256:44ad89a661bc395d6b49d89a0367846f7bee40b198780777c5c7b1b3c0d49a0e AS user-libzbar
FROM stagex/core-libzstd:sx2025.02.0@sha256:23cd975a27e218c5398efd17e1f8c491d31969ab674d3468dbf8b75ba40611ad AS core-libzstd
FROM stagex/user-linux-airgap:sx2025.02.0@sha256:a2dbeace3ce085ba487e88b3968fea1ec29ce392f691d28c4b183e1ed9c0df4d AS user-linux-airgap
FROM stagex/user-lzo:sx2025.02.0@sha256:b71c2944073f3fbc1fe543b9e4dfc4f59ec013a763a6209ded77b8f8bd0a33b4 AS user-lzo
FROM stagex/user-mtools:sx2025.02.0@sha256:ea76e5f82f9833274a4438e9706779afd9b1c0b197c984c9d54c9887163ffb42 AS user-mtools
FROM stagex/core-musl:sx2025.02.0@sha256:23d0614f60449015add2369959c89a6ea08e208302773b9a0811ce1195afc3a4 AS core-musl
FROM stagex/user-nettle:sx2025.02.0@sha256:ec81bb00c990ceee3047632216387d350d1e753cc2a150f3d12c27872832c9ff AS user-nettle
FROM stagex/user-npth:sx2025.02.0@sha256:82462e0c12a8d3e3196ea8b3a647e75efd6d1cc0a84b091a0bb844e0c623d9be AS user-npth
FROM stagex/user-numactl:sx2025.02.0@sha256:b89612d78567874127522af2c73d5d0a7d5fffbb37bf4b2193affa679d7f367c AS user-numactl
FROM stagex/user-openpgp-card-tools:sx2025.02.0@sha256:77d9f2d949548c22badbf29ff8e43a3329ef568c77c66ddbde8d9e2e2dfecb1b AS user-openpgp-card-tools
FROM stagex/user-opensc:sx2025.02.0@sha256:985c0ea0d7ca91b0ed3b2f72c736b75f6d8a392e826f62859f2056a7222f7b75 AS user-opensc
FROM stagex/core-openssl:sx2025.02.0@sha256:b3371fba4b4c61ddd02d97e81d0406d122a552a59f474d23822b099874690af0 AS core-openssl
FROM stagex/user-pcsc-lite:sx2025.02.0@sha256:825708912c41d93dd38230f6f481f5876acb5b2959461504bdaa02a942f8c7b4 AS user-pcsc-lite
FROM stagex/user-pcsc-tools:sx2025.02.0@sha256:dc609b2eb7ba44f877b481633baa86873e99739573f81fe10d5485eb5a1b4f9d AS user-pcsc-tools
FROM stagex/user-qemu:sx2025.02.0@sha256:47653f32fb5874d91969a4b206e8f46f26f056dc2adfc88758d57208a6659b03 AS user-qemu
FROM stagex/user-canokey-qemu:sx2025.02.0@sha256:aba3be44d4b0da2f4ee52fdc2e2cd5b4f6dd05162323015745d2fd194d3074a7 AS user-canokey-qemu
FROM stagex/user-sdtool:sx2025.02.0@sha256:7543bbfdc39efd94820484ffdc984ec16aac29523d0533c19887d907828e7a9a AS user-sdtool
FROM stagex/user-seabios:sx2025.02.0@sha256:03eeb1344ad5f94dccdedbb3379906b272b62e246972e9334011746c79f234cf AS user-seabios
FROM stagex/user-sops:sx2025.02.0@sha256:dba1b3e27b0700d5160c470e2225cfe0734fe25dd1c1aef187d69e31cbb1f35e AS user-sops
FROM stagex/core-zlib:sx2025.02.0@sha256:15860e0789afa0f3ed1bd4e9d771ecb34fbab399064f6aa69c05e71cb8822156 AS core-zlib
FROM stagex/user-sequoia-sq:sx2025.02.0@sha256:48b9a0f425604f46a0587e6dcbf81576f32145363dcfbdb86a9c46af659996a6 AS user-sequoia-sq
FROM stagex/user-sequoia-sq-wot:sx2025.02.0@sha256:aeedcfbe20ff38937a0157fa2047a831f187a53deb319d8bee7848cf52b0cd5f AS user-sequoia-sq-wot
FROM stagex/core-sqlite3:sx2025.02.0@sha256:ca0e3274fbd2cdfcb418088f7147e865abe025a1cec043c1bade0f4b99185296 AS core-sqlite3
FROM stagex/user-swtpm:sx2025.02.0@sha256:a13468396caeba89123a414500364967ac90af9541bf01b84821db487d7c7cc9 AS user-swtpm
FROM stagex/user-syslinux:sx2025.02.0@sha256:b5e74e7384e6b1f21641296e5188073b65761724a91ae55ecaba9b7164de8c3a AS user-syslinux
FROM stagex/user-tpm2-tools:sx2025.02.0@sha256:bf5d0c4b62dda736043843a5c59d1ed7c7aaf5e50cbcdb3976025e03384eb709 AS user-tpm2-tools
FROM stagex/user-tpm2-tss:sx2025.02.0@sha256:816caefc95cadd4b0eaeccd0c2ee45a6093ff49ca8fa49dd3970284629523fd7 AS user-tpm2-tss
FROM stagex/user-util-linux:sx2025.02.0@sha256:bf03b1aaa92a3877f2d2a35d2c27cf453f95545bc7c355b7d4971b58eddbf7a3 AS user-util-linux
FROM stagex/user-xorriso:sx2025.02.0@sha256:f3b9f1eebdbc6f2e62a9d4345abb87ea81219fc4afdbdc0412a8a2110282a1a1 AS user-xorriso
FROM stagex/core-xz:sx2025.02.0@sha256:34824f16967f6bd8ecf24c320e36dfc9cd58d5746d3c524e1b896ebdf5a2e760 AS core-xz
FROM stagex/user-yq:sx2025.02.0@sha256:e817e39f34a7417fd151b4fb9d0d21e21242fe8dc19c0e248677426f2e478cce AS user-yq
FROM stagex/busybox AS busybox
FROM stagex/musl AS musl
FROM stagex/xorriso AS xorriso
FROM stagex/syslinux AS syslinux
FROM stagex/cpio AS cpio
FROM stagex/linux-airgap AS linux
FROM stagex/mtools AS mtools
FROM stagex/dosfstools AS dosfstools
FROM scratch AS base
ARG VERSION development
ARG GIT_TIMESTAMP null
ARG GIT_AUTHOR null
ARG GIT_REF null
ARG GIT_PUBKEY null
COPY --from=core-busybox . /
COPY --from=core-musl . /
COPY --from=core-xz . /
COPY --from=user-xorriso . /
COPY --from=user-cpio . /
COPY --from=user-mtools . /
COPY --from=user-grub . /
FROM base AS dev
COPY --from=core-gcc . /
COPY --from=core-zlib . /
COPY --from=user-glib . /
COPY --from=user-alsa-lib . /
COPY --from=user-lzo . /
COPY --from=user-dtc . /
COPY --from=user-numactl . /
COPY --from=user-libaio . /
COPY --from=user-libseccomp . /
COPY --from=core-libffi . /
COPY --from=core-libzstd . /
COPY --from=user-libslirp . /
COPY --from=user-seabios . /
COPY --from=user-ipxe . /
COPY --from=user-qemu . /
COPY --from=user-canokey-qemu . /
COPY --from=user-swtpm . /
COPY --from=core-openssl . /
COPY --from=core-curl . /
COPY --from=user-libtpms . /
COPY --from=user-tpm2-tss . /
COPY --from=user-tpm2-tools . /
COPY --from=busybox . /
COPY --from=musl . /
COPY --from=xorriso . /
COPY --from=cpio . /
COPY --from=mtools . /
COPY --from=linux . /
COPY --from=dosfstools . /
COPY --from=syslinux . /
FROM base AS build
## Kernel
COPY --from=user-linux-airgap /bzImage iso/boot/vmlinuz
## Initramfs
COPY --from=core-busybox . initramfs
COPY --from=user-eudev . initramfs
COPY --from=core-musl . initramfs
COPY --from=core-zlib . initramfs
COPY --from=user-npth . initramfs
COPY --from=user-libksba . initramfs
COPY --from=user-libgpg-error . initramfs
COPY --from=user-libassuan . initramfs
COPY --from=user-libgcrypt . initramfs
COPY --from=core-bash . initramfs
COPY --from=user-gpg . initramfs
COPY --from=user-jq . initramfs
COPY --from=user-yq . initramfs
COPY --from=core-bc . initramfs
COPY --from=user-flashtools . initramfs
COPY --from=core-curl . initramfs
COPY --from=user-tpm2-tools . initramfs
COPY --from=user-tpm2-tss . initramfs
COPY --from=core-openssl . initramfs
COPY --from=user-libusb . initramfs
COPY --from=user-ccid . initramfs
COPY --from=user-pcsc-lite . initramfs
COPY --from=user-pcsc-tools . initramfs
COPY --from=user-libqrencode . initramfs
COPY --from=core-gmp . initramfs
COPY --from=core-libunwind . initramfs
COPY --from=user-nettle . initramfs
COPY --from=user-opensc . initramfs
COPY --from=user-util-linux . initramfs
COPY --from=user-sops . initramfs
COPY --from=core-gcc /usr/lib/libgcc* initramfs/usr/lib/
COPY --from=core-sqlite3 . initramfs
COPY --from=user-sdtool . initramfs
RUN chmod +x initramfs/usr/bin/sdtool
COPY --from=user-openpgp-card-tools . initramfs
COPY --from=user-sequoia-sq . initramfs
COPY --from=user-sequoia-sq-wot . initramfs
COPY --from=user-libzbar . initramfs
COPY --from=user-keyfork . initramfs
COPY --from=user-icepick . initramfs
COPY rootfs/ initramfs
COPY <<-EOF initramfs/etc/environment
export VERSION="$VERSION"
export GIT_TIMESTAMP="$GIT_TIMESTAMP"
export GIT_AUTHOR="$GIT_AUTHOR"
export GIT_REF="$GIT_REF"
export GIT_PUBKEY="$GIT_PUBKEY"
COPY --from=linux /bzImage /iso/boot/bzImage
COPY --from=stagex/busybox . initramfs
COPY --chmod=0755 <<-EOF initramfs/init
#!/bin/sh
/bin/sh
EOF
RUN cd initramfs && find . | cpio -o -H newc | gzip -9 > /iso/boot/init.gz
COPY <<-EOF iso/isolinux/isolinux.cfg
DEFAULT linux
LABEL linux
KERNEL boot/bzImage
APPEND initrd=boot/init.gz
EOF
COPY --from=syslinux /usr/share/syslinux/isolinux.bin iso/isolinux/
COPY --from=syslinux /usr/share/syslinux/ldlinux.c32 iso/isolinux/
RUN <<-EOF
set -eux
cd initramfs
find . -exec touch -hcd "@0" "{}" +
find . -print0 \
| sort -z \
| cpio \
--null \
--create \
--verbose \
--reproducible \
--format=newc \
| gzip --best \
> ../iso/boot/initramfs
mkdir -p iso/efi
truncate -s $((10796+128+128))k iso/efi/esp.img
mkfs.fat -F 16 -f 1 -M 0xF0 -r 112 -R 1 iso/efi/esp.img
mmd -i iso/efi/esp.img ::boot
mcopy -i iso/efi/esp.img iso/boot/bzImage ::boot/bzImage
mcopy -i iso/efi/esp.img iso/boot/init.gz ::boot/init.gz
mmd -i iso/efi/esp.img ::syslinux
mcopy -i iso/efi/esp.img iso/isolinux/isolinux.cfg ::syslinux/syslinux.cfg
mcopy -i iso/efi/esp.img /usr/share/syslinux/efi64/ldlinux.e64 ::syslinux/ldlinux.e64
mmd -i iso/efi/esp.img ::efi
mmd -i iso/efi/esp.img ::efi/boot
mcopy -i iso/efi/esp.img /usr/share/syslinux/efi64/syslinux.efi ::efi/boot/boot64.efi
ls -Rlah iso
EOF
## Grub (EFI Boot)
COPY config/grub.cfg iso/boot/grub/grub.cfg
COPY config/grub_early.cfg grub_early.cfg
RUN <<-EOF
set -eux
mkdir -p efi/boot
grub-mkimage \
--config="grub_early.cfg" \
--prefix="/boot/grub" \
--output="efi/boot/bootx64.efi" \
--format="x86_64-efi" \
--compression="xz" \
all_video \
disk \
part_gpt \
part_msdos \
linux \
normal \
configfile \
search \
search_label \
efi_gop \
fat \
iso9660 \
gzio \
serial \
terminal
find efi -exec touch -hcd "@0" "{}" +
mformat -i iso/boot/grub/efi.img -C -f 1440 -N 0 ::
mcopy -i iso/boot/grub/efi.img -ms efi ::
touch -md "@0" iso/boot/grub/efi.img
EOF
## Syslinux (BIOS Boot)
COPY config/syslinux.cfg iso/boot/syslinux/
COPY --from=user-syslinux \
/usr/share/syslinux/isohdpfx.bin \
/usr/share/syslinux/isolinux.bin \
/usr/share/syslinux/ldlinux.c32 \
/usr/share/syslinux/libutil.c32 \
/usr/share/syslinux/libcom32.c32 \
/usr/share/syslinux/mboot.c32 \
iso/boot/syslinux/
## Build Hybrid EFI/BIOS ISO
FROM build AS install
ENV SOURCE_DATE_EPOCH=1
RUN <<-EOF
set -eux
dd if=/dev/zero bs=1M count=10 >> user.img
mformat -v user -i user.img -N 0 ::
find iso -exec touch -hcd "@0" "{}" +
xorrisofs \
-output airgap.iso \
-full-iso9660-filenames \
-joliet \
-rational-rock \
-sysid LINUX \
-volid "airgap" \
-isohybrid-mbr iso/boot/syslinux/isohdpfx.bin \
-eltorito-boot boot/syslinux/isolinux.bin \
-eltorito-catalog boot/syslinux/boot.cat \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
-eltorito-alt-boot \
-e boot/grub/efi.img \
-no-emul-boot \
-isohybrid-gpt-basdat \
-follow-links \
-append_partition 3 0xb user.img \
iso/
EOF
## Minimal Autorun SD card image
COPY sdcard sdcard
RUN <<-EOF
set -eux
dd if=/dev/zero of=sdcard.img bs=1M count=32
mformat -v external -i sdcard.img ::
mcopy -i sdcard.img -s sdcard/* ::
EOF
RUN xorriso \
-as mkisofs \
-output airgap.iso \
-eltorito-boot isolinux/isolinux.bin \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
-eltorito-alt-boot \
-eltorito-platform efi \
-eltorito-boot efi/esp.img \
-no-emul-boot \
-eltorito-catalog isolinux/boot.cat \
iso
#RUN isohybrid airgap.iso
FROM scratch AS package
COPY --from=install /sdcard.img /
COPY --from=install /airgap.iso /

153
Makefile
View File

@ -1,144 +1,21 @@
VERSION := development
GIT_REF := $(shell git log -1 --format=%H)
GIT_AUTHOR := $(shell git log -1 --format=%an)
GIT_PUBKEY := $(shell git log -1 --format=%GK)
GIT_TIMESTAMP := $(shell git log -1 --format=%cd --date=iso)
EFI := false
,:=,
export
## Use env vars from latest release when reproducing
ifdef REPRODUCE
include dist/release.env
export
endif
## Prevents use of caching when building docker image
ifdef NOCACHE
NO_CACHE := --no-cache
endif
.DEFAULT_GOAL :=
.PHONY: default
default: \
out/release.env \
out/manifest.txt \
out/airgap.iso
## Primary targets
out/airgap.iso: Containerfile $(shell git ls-files rootfs)
SOURCE_DATE_EPOCH=1 \
docker build \
--progress=plain \
--output type=local,rewrite-timestamp=true,dest=out \
--build-arg SOURCE_DATE_EPOCH=1 \
--build-arg VERSION="$(VERSION)" \
--build-arg GIT_REF="$(GIT_REF)" \
--build-arg GIT_AUTHOR="$(GIT_AUTHOR)" \
--build-arg GIT_PUBKEY="$(GIT_PUBKEY)" \
--build-arg GIT_TIMESTAMP="$(GIT_TIMESTAMP)" \
$(NO_CACHE) \
-f Containerfile \
.
## Development Targets
out/dev-shell.digest: Containerfile | out
docker build --target dev -f Containerfile -q . > $@
.PHONY: shell
shell: out/dev-shell.digest
docker run -it $(shell cat $<) /bin/sh
$(OUT_DIR)/airgap.iso
.PHONY: vm
vm: out/dev-shell.digest out/airgap.iso out/sdcard.img
docker run -it -v ./out:/out $(shell cat $<) sh -c "\
swtpm socket \
--tpmstate dir=. \
--ctrl type=unixio,path=vtpm-sock \
--tpm2 & \
qemu-system-x86_64 \
-m 4G \
-machine pc \
-chardev socket,id=chrtpm,path=vtpm-sock \
-usb -device canokey,file=/out/canokey-file \
-tpmdev emulator,id=tpm0,chardev=chrtpm \
-device tpm-tis,tpmdev=tpm0 \
-usb \
-device sdhci-pci \
-device sd-card,drive=external \
-drive id=external,if=none,format=raw,file=out/sdcard.img \
-device usb-storage,drive=usbdrive \
$(if $(filter $(EFI),true) ,\
-bios /usr/share/ovmf/OVMF.fd \
-drive id=boot$(,)if=virtio$(,)format=raw$(,)file=out/airgap.iso \
,\
-drive id=usbdrive,if=none,format=raw,file=out/airgap.iso \
-boot order=c \
) \
$(if (,$(wildcard /dev/kvm)),,-cpu host --accel kvm) \
-nographic; \
"
vm:
$(call toolchain,$(USER)," \
qemu-system-i386 \
-M pc \
-nographic \
-cdrom "$(OUT_DIR)/airgap.iso"; \
")
## Release, Signing, Verification, and Reproduction Targets
.PHONY: clean
clean:
rm -rf out
.PHONY: update
update:
python3 src/update.py
.PHONY: release
release: clean
$(MAKE) NOCACHE=1 VERSION=$(VERSION)
rm -rf dist/*
cp -R out/release.env out/airgap.iso out/manifest.txt dist/
.PHONY: sign
sign:
set -e; \
git config --get user.signingkey 2>&1 >/dev/null || { \
echo "Error: git user.signingkey is not defined"; \
exit 1; \
}; \
fingerprint=$$(\
git config --get user.signingkey \
| sed 's/.*\([A-Z0-9]\{16\}\).*/\1/g' \
); \
gpg --armor \
--detach-sig \
--output dist/manifest.$${fingerprint}.asc \
dist/manifest.txt
.PHONY: verify
verify: | dist/manifest.txt
set -e; \
for file in dist/manifest.*.asc; do \
echo "\nVerifying: $${file}\n"; \
gpg --verify $${file} dist/manifest.txt; \
done;
.PHONY: reproduce
reproduce: clean | out
$(MAKE) REPRODUCE=true NOCACHE=1
diff -q out/manifest.txt dist/manifest.txt;
out:
mkdir -p $@
out/release.env: $(shell git ls-files) | out
echo 'VERSION=$(VERSION)' > out/release.env
echo 'GIT_REF=$(GIT_REF)' >> out/release.env
echo 'GIT_AUTHOR=$(GIT_AUTHOR)' >> out/release.env
echo 'GIT_PUBKEY=$(GIT_PUBKEY)' >> out/release.env
echo 'GIT_TIMESTAMP=$(GIT_TIMESTAMP)' >> out/release.env
out/manifest.txt: out/airgap.iso out/release.env | out
openssl sha256 -r \
out/airgap.iso \
out/release.env \
| sed -e 's/ \*out\// /g' -e 's/ \.\// /g' \
> $@
$(OUT_DIR)/airgap.iso: \
$(FETCH_DIR)/buildroot
docker build \
--progress=plain \
--output type=oci,tar=false,force-compression=true,name=airgap,dest=airgap \
. \
-f Containerfile

100
README.md
View File

@ -1,26 +1,24 @@
# AirgapOS #
<https://git.distrust.co/public/airgap>
<https://github.com/distrust-foundation/airgap>
## About ##
A full-source-bootstrapped, deterministic, minimal, immutable, and offline,
workstation linux distribution designed for creating and managing secrets
offline.
A live buildroot based Liux distribution designed for managing secrets offline.
Built for those of us that want to be -really- sure our most important secrets
are managed in a clean environment with an "air gap" between us and the
internet with high integrity on the supply chain of the firmware and OS used.
## Uses ##
* Generate PGP keychain
* Generate GPG keychain
* Store/Restore gpg keychain to security token such as a Yubikey or Nitrokey
* Signing cryptocurrency transactions
* Generate/backup BIP39 universal cryptocurrency wallet seed
* Store/Restore BIP39 seed to a hardware wallet such as a Trezor or Ledger
## Features ##
* Deterministic iso generation for multi-party code->binary verification
* Determinsitic iso generation for multi-party code->binary verification
* Small footprint (< 100MB)
* Immutable and Diskless: runs from initramfs
* Network support and most drivers removed to minimize exfiltration vectors
@ -29,54 +27,37 @@ internet with high integrity on the supply chain of the firmware and OS used.
### Software ###
* docker 26+
* docker 18+
### Hardware ###
* x86_64 PC or laptop
* linuxboot/heads firmware supported and recommended for multi-use machine
* Allows for signed builds, and verification of signed sd card payloads
* Ensure any Wifi/Disk/Bluetooth/Audio devices are disabled/removed
* Recommended: PC running coreboot-heads
* Allows for signed builds, and verification of signed sd card payloads
* Ensure any Wifi/Disk/Bluetooth/Audio devices are disabled/removed
* Supported remote attestation key (Librem Key, Nitrokey, etc)
* Supported GPG smartcard device (Yubikey, Ledger, Trezor, Librem Key, etc)
* Blank flash drive
* Blank SD card
## Build ##
### Update git submodules
```
git submodule update --init --recursive
```
### Build a new release
```
make release
```
```
make release
```
### Reproduce an existing release
```
make reproduce
```
```
make attest
```
### Sign an existing release
```
make sign
```
## Provisioning ##
1. Write airgap.iso to CD-ROM or SD Card
a. `dd if=out/airgap.iso of=/dev/sda bs=1M conv=sync status=progress`
b. `cdrecord out/airgap.iso`
2. Verify media still produces expected hash
```
sha256sum out/airgap.iso
head -c $(stat -c '%s' airgap.iso) /dev/sda | sha256sum
```
```
make sign
```
## Setup ##
@ -128,46 +109,3 @@ make vm
```
make shell
```
## Hardware Compatibility ##
### Tested Models
* Purism Librem 14
* HP 13" Intel Celeron - 4GB Memory - 64GB eMMC, HP 14-dq0052dx, SKU: 6499749, UPC: 196548430192, DCS: 6.768.5321, ~USD $179.99
* Lenovo 14" Flex 5i FHD Touchscreen 2-in-1 Laptop - Intel Core i3-1215U - 8GB Memory - Intel UHD Graphics, SKU: 6571565, ~USD $379.99
### Disabling Secure Boot
AirgapOS can't be booted using secure boot. Therefore it has to be disabled. Alternative systems like Heads may be used.
#### Instructions to Disable Secure Boot in BIOS
1. Restart your computer
2. **Enter BIOS/UEFI Setup**:
- As your computer starts up, press the appropriate key to enter the BIOS/UEFI setup. Common keys include:
- **F2** (Dell, Acer, Lenovo)
- **Delete** (ASUS, MSI)
- **F10** (HP)
- **Esc** (Some systems)
- You may see a prompt on the screen indicating which key to press
3. **Navigate to the Secure Boot Option**:
- Once in the BIOS/UEFI setup, use the arrow keys to navigate through the menus. Look for a tab or section labeled **"Boot," "Security,"** or **"Authentication."**
- The exact location of the Secure Boot option can vary, so you may need to explore a bit
4. **Locate Secure Boot**:
- Find the **Secure Boot** option within the selected menu. It may be listed as **"Secure Boot Control"** or simply **"Secure Boot."**
5. **Disable Secure Boot**:
- Select the Secure Boot option and change its setting to **Disabled**. This is usually done by pressing **Enter** and then selecting **Disabled** from the options.
6. **Save Changes and Exit**:
- After disabling Secure Boot, navigate to the **Exit** tab or section.
- Choose the option to **Save Changes and Exit**. Confirm any prompts that appear to save your changes.
7. **Reboot Your Computer**:
- Your computer will restart. Secure Boot should now be disabled.

View File

@ -1,5 +0,0 @@
set timeout=1
menuentry "Linux Airgap" {
linux /boot/vmlinuz init=/init console=ttyS0 console=tty0 ro loglevel=3
initrd /boot/initramfs
}

View File

@ -1,2 +0,0 @@
search --no-floppy --set=root --label "airgap"
set prefix=($root)/boot/grub

View File

@ -1,8 +0,0 @@
TIMEOUT 2
PROMPT -1
DEFAULT Airgap
LABEL Airgap
MENU LABEL Linux Airgap
KERNEL /boot/vmlinuz
INITRD /boot/initramfs
APPEND init=/init console=ttyS0 console=tty0 ro

BIN
dist/airgap.iso (Stored with Git LFS) vendored

Binary file not shown.

View File

@ -1,16 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE4QZ4HgB6uRyYnbMyRKhs/x/fDoUFAmfCNtYACgkQRKhs/x/f
DoVzmQ//cLQHFTu/EbgxbS8qgVv+kuVR7+KPAxDyY89pIKdTrKWzfrUvY+A3YfS0
hsXhehjmVNzaxFxWQvZ+iRBMSv3ypR/6/ui5DwpalLlnlWiFFlW/0lYakpuR1oa3
iq2CrlN9QdZ5de2jJXJilIYlkWRgyj8HQ/p3d+XzNLQ4Wtl9m8kQTSZ0tnfWDCi5
dFf+y7VjlgQSAwsC8T21zbH7P0ZwkaUhd8+ybEVB4oazZaMUdr0Zftu1Snp432Yu
PKeJWT+8RsrTr57Hvf0JFTTbJKyAqe+3VbwRV66FOn2ycxCyJT6JuRJ/SzmhiCRu
YeYdev7LEZFIUKoTSWL51DdyQfOuw+oC3v28c8hSDlwT/KD+x/JFbAI5+ln1O+HY
LjB+bDeE0bD4oWHrJn3hul+iKeFjXpfj8gYqURJuF+IJ0epOv1G2JB8brzM9vtJK
Sgu0A0kvOTpzdvyHALeHY6OtUlgD8dG/wuD/mheR242f4OjDfxcVM5Y966waCxMb
jwgdS8sBAn417ZNAtw6biUmx3W8qdYsDzYJS4kvkWeqsUS8KtfV2b3RAlNkrxUsR
sBhB6opEEzzpbMgXhRcS2mA+PDQGSksE09tTOlxuwtmYeXTowspVTzcnGgXcFyb+
mpBD+uRwR2FBcKSiqlNA3XHIMLDYb3gx7RvmroHeqqtAkQPAALc=
=8hAc
-----END PGP SIGNATURE-----

View File

@ -1,16 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEZ1U/vaRrtxq9LgsLjkeh7DWhVR0FAmfBsAQACgkQjkeh7DWh
VR2Gbg/+N80OV8+qrnamiy2p7IlAvfWi5sepTTDTjL+jXNb9DdIaUIPSFFe0bBf8
hp75G/y7gZpuubuy8n4hKf0j2IeIZez9j+HDGicAIcdSaNij4aES65r6w7xi2AAn
s4dWw+yJSymni24iwQkP6csu0ja+aauB7/0U6VHtL4w2GxjcXGZU0FXToQ6fB8hv
TavjBlyv5D/a9QKdyaNulEYMF7fvpxe+lMoF4miq3goLiI3DuFM+NH5P48nN1W4G
AHH9OUHFRMBdZUGTYF4i5KJGNnfryRIR99J3L2n9xKetwOpz8bLxinjEZG8tjws5
RQ3IlwvW/6jNSDt2zU6dk1DKYx3inndlA9BvJtkrksig/OB9HaxosjrOaI267OCc
iM7xNIZQxJJ9UTOSA5Q1QTHxu2wzYL6GaHlilD7RZEZn0X4O4JveH3zeCdLwMk2l
kf27XbFxLMf/7q8ekPJl791pPBRD6A+v0FNw8WedgQwd/Pdg9qTerRoVKXsmCUGr
tXBiobDnZ2daE5iB96PGJsACE+Jat+QEwWrE3V3ILun9ewu3TP5LUQMYEktS0UHd
fFdXO790GK+TZKvyJ0z7J0VBoGHS+D/1G35VLAHyNQXULOYK56GKwpwZeHVWykVt
h7cnGBwo+IfdMTYN6h7U9l35nj06HtRbylB2VVZdtWV3FediqSg=
=9U0u
-----END PGP SIGNATURE-----

2
dist/manifest.txt vendored
View File

@ -1,2 +0,0 @@
46c1b23cadb6c03b175e713d91b809c91a2768273249b1bd2506d05307dff9de airgap.iso
c09b5ab32791fa001c004e7b59cd0a6f0f9f3a3503cb600a8ec2c19d2e2b00c1 release.env

5
dist/release.env vendored
View File

@ -1,5 +0,0 @@
VERSION=2025.02.0
GIT_REF=dca180550e7b317938f40793aacbbbeede216b9f
GIT_AUTHOR=Lance R. Vick
GIT_PUBKEY=8E47A1EC35A1551D
GIT_TIMESTAMP=2025-02-28 04:26:59 -0800

View File

@ -1,55 +0,0 @@
#!/bin/sh
DAEMON="syslogd"
PIDFILE="/var/run/$DAEMON.pid"
SYSLOGD_ARGS=""
# shellcheck source=/dev/null
[ -r "/etc/default/$DAEMON" ] && . "/etc/default/$DAEMON"
# BusyBox' syslogd does not create a pidfile, so pass "-n" in the command line
# and use "-m" to instruct start-stop-daemon to create one.
start() {
printf 'Starting %s: ' "$DAEMON"
# shellcheck disable=SC2086 # we need the word splitting
start-stop-daemon -b -m -S -q -p "$PIDFILE" -x "/bin/$DAEMON" \
-- -n $SYSLOGD_ARGS
status=$?
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
stop() {
printf 'Stopping %s: ' "$DAEMON"
start-stop-daemon -K -q -p "$PIDFILE"
status=$?
if [ "$status" -eq 0 ]; then
rm -f "$PIDFILE"
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
restart() {
stop
sleep 1
start
}
case "$1" in
start|stop|restart)
"$1";;
reload)
# Restart, since there is no true "reload" feature.
restart;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac

View File

@ -1,55 +0,0 @@
#!/bin/sh
DAEMON="klogd"
PIDFILE="/var/run/$DAEMON.pid"
KLOGD_ARGS=""
# shellcheck source=/dev/null
[ -r "/etc/default/$DAEMON" ] && . "/etc/default/$DAEMON"
# BusyBox' klogd does not create a pidfile, so pass "-n" in the command line
# and use "-m" to instruct start-stop-daemon to create one.
start() {
printf 'Starting %s: ' "$DAEMON"
# shellcheck disable=SC2086 # we need the word splitting
start-stop-daemon -b -m -S -q -p "$PIDFILE" -x "/bin/$DAEMON" \
-- -n $KLOGD_ARGS
status=$?
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
stop() {
printf 'Stopping %s: ' "$DAEMON"
start-stop-daemon -K -q -p "$PIDFILE"
status=$?
if [ "$status" -eq 0 ]; then
rm -f "$PIDFILE"
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
restart() {
stop
sleep 1
start
}
case "$1" in
start|stop|restart)
"$1";;
reload)
# Restart, since there is no true "reload" feature.
restart;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac

View File

@ -1,94 +0,0 @@
#!/bin/sh
#
# This script is used by busybox and procps-ng.
#
# With procps-ng, the "--system" option of sysctl also enables "--ignore", so
# errors are not reported via syslog. Use the run_logger function to mimic the
# --system behavior, still reporting errors via syslog. Users not interested
# on error reports can add "-e" to SYSCTL_ARGS.
#
# busybox does not have a "--system" option neither reports errors via syslog,
# so the scripting provides a consistent behavior between the implementations.
# Testing the busybox sysctl exit code is fruitless, as at the moment, since
# its exit status is zero even if errors happen. Hopefully this will be fixed
# in a future busybox version.
PROGRAM="sysctl"
SYSCTL_ARGS=""
# shellcheck source=/dev/null
[ -r "/etc/default/$PROGRAM" ] && . "/etc/default/$PROGRAM"
# Files are read from directories in the SYSCTL_SOURCES list, in the given
# order. A file may be used more than once, since there can be multiple
# symlinks to it. No attempt is made to prevent this.
SYSCTL_SOURCES="/etc/sysctl.d/ /usr/local/lib/sysctl.d/ /usr/lib/sysctl.d/ /lib/sysctl.d/ /etc/sysctl.conf"
# If the logger utility is available all messages are sent to syslog, except
# for the final status. The file redirections do the following:
#
# - stdout is redirected to syslog with facility.level "kern.info"
# - stderr is redirected to syslog with facility.level "kern.err"
# - file dscriptor 4 is used to pass the result to the "start" function.
#
run_logger() {
# shellcheck disable=SC2086 # we need the word splitting
find $SYSCTL_SOURCES -maxdepth 1 -name '*.conf' -print0 2> /dev/null | \
xargs -0 -r -n 1 readlink -f | {
prog_status="OK"
while :; do
read -r file || {
echo "$prog_status" >&4
break
}
echo "* Applying $file ..."
/sbin/sysctl -p "$file" $SYSCTL_ARGS || prog_status="FAIL"
done 2>&1 >&3 | /usr/bin/logger -t sysctl -p kern.err
} 3>&1 | /usr/bin/logger -t sysctl -p kern.info
}
# If logger is not available all messages are sent to stdout/stderr.
run_std() {
# shellcheck disable=SC2086 # we need the word splitting
find $SYSCTL_SOURCES -maxdepth 1 -name '*.conf' -print0 2> /dev/null | \
xargs -0 -r -n 1 readlink -f | {
prog_status="OK"
while :; do
read -r file || {
echo "$prog_status" >&4
break
}
echo "* Applying $file ..."
/sbin/sysctl -p "$file" $SYSCTL_ARGS || prog_status="FAIL"
done
}
}
if [ -x /usr/bin/logger ]; then
run_program="run_logger"
else
run_program="run_std"
fi
start() {
printf '%s %s: ' "$1" "$PROGRAM"
status=$("$run_program" 4>&1)
echo "$status"
if [ "$status" = "OK" ]; then
return 0
fi
return 1
}
case "$1" in
start)
start "Running";;
restart|reload)
start "Rerunning";;
stop)
:;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac

View File

@ -1,24 +0,0 @@
#!/bin/sh
case "$1" in
start)
printf "Populating %s using udev: " "${udev_root:-/dev}"
[ -e /proc/sys/kernel/hotplug ] && printf '\000\000\000\000' > /proc/sys/kernel/hotplug
/sbin/udevd -d || { echo "FAIL"; exit 1; }
udevadm trigger --type=subsystems --action=add
udevadm trigger --type=devices --action=add
udevadm settle --timeout=30 || echo "udevadm settle failed"
echo "done"
;;
stop)
# Stop execution of events
udevadm control --stop-exec-queue
killall udevd
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
;;
esac
exit 0

View File

@ -1,20 +0,0 @@
#!/bin/sh
case "$1" in
start)
/usr/sbin/pcscd -d || { echo "FAIL"; exit 1; }
killall pcscd
/usr/sbin/pcscd -d || { echo "FAIL"; exit 1; }
echo "done"
;;
stop)
# Stop execution of events
killall pcscd
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
;;
esac
exit 0

View File

@ -1,70 +0,0 @@
#! /bin/sh
#
# Preserve the random seed between reboots. See urandom(4).
#
# Quietly do nothing if /dev/urandom does not exist
[ -c /dev/urandom ] || exit 0
URANDOM_SEED="/var/lib/random-seed"
# shellcheck source=/dev/null
[ -r "/etc/default/urandom" ] && . "/etc/default/urandom"
if pool_bits=$(cat /proc/sys/kernel/random/poolsize 2> /dev/null); then
pool_size=$((pool_bits/8))
else
pool_size=512
fi
init_rng() {
[ -f "$URANDOM_SEED" ] || return 0
printf 'Initializing random number generator: '
dd if="$URANDOM_SEED" bs="$pool_size" of=/dev/urandom count=1 2> /dev/null
status=$?
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
save_random_seed() {
printf 'Saving random seed: '
status=1
if touch "$URANDOM_SEED.new" 2> /dev/null; then
old_umask=$(umask)
umask 077
dd if=/dev/urandom of="$URANDOM_SEED.tmp" bs="$pool_size" count=1 2> /dev/null
cat "$URANDOM_SEED" "$URANDOM_SEED.tmp" 2>/dev/null \
| sha256sum \
| cut -d ' ' -f 1 > "$URANDOM_SEED.new" && \
mv "$URANDOM_SEED.new" "$URANDOM_SEED" && status=0
rm -f "$URANDOM_SEED.tmp"
umask "$old_umask"
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
else
echo "SKIP (read-only file system detected)"
fi
return "$status"
}
case "$1" in
start|restart|reload)
# Carry a random seed from start-up to start-up
# Load and then save the whole entropy pool
init_rng && save_random_seed;;
stop)
# Carry a random seed from shut-down to start-up
# Save the whole entropy pool
save_random_seed;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac

View File

@ -1,27 +0,0 @@
#!/bin/sh
# Stop all init scripts in /etc/init.d
# executing them in reversed numerical order.
#
for i in $(ls -r /etc/init.d/S??*) ;do
# Ignore dangling symlinks (if any).
[ ! -f "$i" ] && continue
case "$i" in
*.sh)
# Source shell script for speed.
(
trap - INT QUIT TSTP
set stop
. $i
)
;;
*)
# No sh extension, so fork subprocess.
$i stop
;;
esac
done

View File

@ -1,27 +0,0 @@
#!/bin/sh
# Start all init scripts in /etc/init.d
# executing them in numerical order.
#
for i in /etc/init.d/S??* ;do
# Ignore dangling symlinks (if any).
[ ! -f "$i" ] && continue
case "$i" in
*.sh)
# Source shell script for speed.
(
trap - INT QUIT TSTP
set start
. $i
)
;;
*)
# No sh extension, so fork subprocess.
$i start
;;
esac
done

View File

@ -1,5 +1,11 @@
# /etc/inittab
#
# Copyright (C) 2001 Erik Andersen <andersen@codepoet.org>
#
# Note: BusyBox init doesn't support runlevels. The runlevels field is
# completely ignored by BusyBox init. If you want runlevels, use
# sysvinit.
#
# Format for each entry: <id>:<runlevels>:<action>:<process>
#
# id == tty to run on, or empty for /dev/console
@ -8,26 +14,27 @@
# process == program to run
# Startup the system
::sysinit:/bin/mount -t devtmpfs devtmpfs /dev
::sysinit:/bin/mkdir -p /proc /run /dev/pts /dev/shm /sys
::sysinit:/bin/mount -t sysfs sysfs /sys
::sysinit:/bin/mount -t proc proc /proc
::sysinit:/bin/mount -o remount,rw /
::sysinit:/bin/mkdir /var/log
::sysinit:/bin/mkdir -p /dev/pts /dev/shm
::sysinit:/bin/mount -a
::sysinit:/sbin/swapon -a
null::sysinit:/bin/ln -sf /proc/self/fd /dev/fd
null::sysinit:/bin/ln -sf /proc/self/fd/0 /dev/stdin
null::sysinit:/bin/ln -sf /proc/self/fd/1 /dev/stdout
null::sysinit:/bin/ln -sf /proc/self/fd/2 /dev/stderr
::sysinit:/bin/hostname -F /etc/hostname
# now run any rc scripts
::sysinit:/etc/init.d/rcS
# Put shells on the serial terminal and console
console::respawn:-/bin/bash
ttyS0::respawn:-/bin/bash
# Put a getty on the serial port
#console::respawn:/sbin/getty -L console 0 vt100 # GENERIC_SERIAL
::respawn:-/bin/bash
# Stuff to do for the 3-finger salute
::ctrlaltdel:/sbin/reboot
#::ctrlaltdel:/sbin/reboot
# Stuff to do before rebooting
::shutdown:/etc/init.d/rcK
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r

View File

@ -2,9 +2,9 @@ export EDITOR=/bin/vi
export PATH="/usr/local/bin:/bin:/sbin:/usr/bin:/usr/sbin"
export PS1="[\h \t] \\$ "
export GNUPGHOME=/.gnupg
export XDG_RUNTIME_DIR=/tmp
source /etc/environment
cd /root
dmesg -n1
clear
cat << "EOF"
_ _ ___ ____
@ -19,5 +19,5 @@ echo " - Version: $VERSION"
echo " - Date: $GIT_TIMESTAMP"
echo " - Committer: $GIT_AUTHOR"
echo " - Commit: $GIT_REF"
echo " - Key: $GIT_PUBKEY"
echo " - Key: $GIT_KEY"
echo ""

View File

@ -0,0 +1,12 @@
KERNEL!="sd[a-z][0-9]", GOTO="sd_cards_auto_mount_end"
# Global mount options
ACTION=="add", ENV{mount_options}="relatime"
# Filesystem specific options
ACTION=="add", IMPORT{program}="/sbin/blkid -o udev -p %N"
ACTION=="add", ENV{ID_FS_TYPE}=="vfat|ntfs", ENV{mount_options}="$env{mount_options},utf8,flush,user,umask=0000"
ACTION=="add", RUN+="/bin/mkdir -p /media/sd-%k", RUN+="/bin/mount -o $env{mount_options} /dev/%k /media/sd-%k"
ACTION=="add", RUN+="/usr/local/bin/autorun /media/sd-%k"
ACTION=="remove", RUN+="/bin/umount -l /media/sd-%k", RUN+="/bin/rmdir /media/sd-%k"
LABEL="sd_cards_auto_mount_end"

View File

@ -1,2 +0,0 @@
#!/bin/sh
exec /bin/init

View File

@ -1,15 +0,0 @@
KERNEL!="mmcblk[0-9]p[0-9]|sd[a-z][0-9]", GOTO="automount_end"
ACTION=="add", PROGRAM!="/sbin/blkid %N", GOTO="automount_end"
IMPORT{program}="/sbin/blkid -o udev -p %N"
ENV{ID_FS_LABEL}!="", ENV{dir_name}="%E{ID_FS_LABEL}"
ENV{ID_FS_LABEL}=="", ENV{dir_name}="%k"
ACTION=="add", IMPORT{program}="/sbin/blkid -o udev -p %N"
ACTION=="add", ENV{ID_FS_TYPE}=="vfat", ENV{mount_options}="relatime,utf8,flush,user,umask=0000"
ACTION=="add", RUN+="/bin/mkdir -p /media/%E{dir_name}", RUN+="/bin/mount -o $env{mount_options} /dev/%k /media/%E{dir_name}"
ACTION=="add", RUN+="/usr/local/bin/autorun /media/%E{dir_name}"
ACTION=="remove", ENV{dir_name}!="", RUN+="/bin/umount -l /media/%E{dir_name}", RUN+="/bin/rmdir /media/%E{dir_name}"
LABEL="automount_end"

View File

@ -4,17 +4,7 @@ source /etc/profile
folder=${1?}
if [ "$folder" == "/media/USER" ] && [ -f "${folder}/autorun.sh" ]; then
if touch "${folder}/.write_test" 2>/dev/null; then
echo "!! Autorun: Read-only verification failed for /media/USER" >/dev/console
exit 1;
else
echo "" >/dev/console
echo "++ Autorun: Found /media/USER/autorun.sh" >/dev/console;
echo "** Autorun: Executing /media/USER/autorun.sh" >/dev/console
/bin/bash "/media/USER/autorun.sh" >/dev/console
fi
elif [ -f "${folder}/autorun.sh.asc" ]; then
if [ -f "${folder}/autorun.sh.asc" ]; then
echo "" >/dev/console
echo "++ Autorun: Found ${folder}/autorun.sh" >/dev/console;
gpg --verify "${folder}/autorun.sh.asc" >/dev/null 2>&1 || {

View File

@ -1,3 +0,0 @@
#!/bin/bash
echo "Autorun.sh executed"

View File

@ -1,29 +0,0 @@
#!/usr/bin/env python3
from requests import Session
from fileinput import FileInput
target = "Containerfile"
source = "https://codeberg.org/stagex/stagex/raw/branch/main/digests/"
stages = ["core","user","bootstrap"]
digests = {}
for stage in stages:
response = Session().get(f"{source}{stage}.txt")
for line in response.iter_lines():
if not line:
continue
digest,name = line.decode("utf-8").split(" ")
digests[name] = digest
with FileInput(target, inplace=True, backup='.bak') as f:
for line in f:
if line.startswith("FROM stagex/"):
name = line.split("/")[1].split(":")[0]
tag = line.split(":")[1].split("@")[0]
if name not in digests:
for stage in stages:
if f"{stage}-{name}" in digests:
name = f"{stage}-{name}"
print(f"FROM stagex/{name}:{tag}@sha256:{digests[name]} AS {name}")
else:
print(line,end='')