mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-31 20:43:41 +00:00
Compare commits
2 Commits
feature/nv
...
feat/rando
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04196df976 | ||
|
|
30b1654666 |
68
.github/workflows/startos-iso.yaml
vendored
68
.github/workflows/startos-iso.yaml
vendored
@@ -125,6 +125,9 @@ jobs:
|
||||
- name: Set up docker QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up system dependencies
|
||||
run: sudo apt-get update && sudo apt-get install -y qemu-user-static systemd-container squashfuse
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
@@ -221,13 +224,32 @@ jobs:
|
||||
sudo rm -rf "$AGENT_TOOLSDIRECTORY" # Pre-cached tool cache (Go, Node, etc.)
|
||||
if: ${{ github.event.inputs.runner != 'fast' }}
|
||||
|
||||
- name: Set up docker QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y qemu-user-static
|
||||
wget https://deb.debian.org/debian/pool/main/d/debspawn/debspawn_0.6.2-1_all.deb
|
||||
sha256sum ./debspawn_0.6.2-1_all.deb | grep 37ef27458cb1e35e8bce4d4f639b06b4b3866fc0b9191ec6b9bd157afd06a817
|
||||
sudo apt-get install -y ./debspawn_0.6.2-1_all.deb
|
||||
|
||||
- name: Configure debspawn
|
||||
run: |
|
||||
sudo mkdir -p /etc/debspawn/
|
||||
echo "AllowUnsafePermissions=true" | sudo tee /etc/debspawn/global.toml
|
||||
sudo mkdir -p /var/tmp/debspawn
|
||||
|
||||
- run: sudo mount -t tmpfs tmpfs /var/tmp/debspawn
|
||||
if: ${{ github.event.inputs.runner == 'fast' && (matrix.platform == 'x86_64' || matrix.platform == 'x86_64-nonfree') }}
|
||||
|
||||
- name: Download compiled artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -240,11 +262,12 @@ jobs:
|
||||
run: |
|
||||
mkdir -p web/node_modules
|
||||
mkdir -p web/dist/raw
|
||||
mkdir -p core/bindings
|
||||
mkdir -p core/startos/bindings
|
||||
mkdir -p sdk/base/lib/osBindings
|
||||
mkdir -p container-runtime/node_modules
|
||||
mkdir -p container-runtime/dist
|
||||
mkdir -p container-runtime/dist/node_modules
|
||||
mkdir -p core/startos/bindings
|
||||
mkdir -p sdk/dist
|
||||
mkdir -p sdk/baseDist
|
||||
mkdir -p patch-db/client/node_modules
|
||||
@@ -284,3 +307,40 @@ jobs:
|
||||
name: ${{ matrix.platform }}.img
|
||||
path: results/*.img
|
||||
if: ${{ matrix.platform == 'raspberrypi' }}
|
||||
|
||||
- name: Upload OTA to registry
|
||||
run: >-
|
||||
PLATFORM=${{ matrix.platform }} make upload-ota TARGET="${{
|
||||
fromJson('{
|
||||
"alpha": "alpha-registry-x.start9.com",
|
||||
"beta": "beta-registry.start9.com",
|
||||
}')[github.event.inputs.deploy]
|
||||
}}" KEY="${{
|
||||
fromJson(
|
||||
format('{{
|
||||
"alpha": "{0}",
|
||||
"beta": "{1}",
|
||||
}}', secrets.ALPHA_INDEX_KEY, secrets.BETA_INDEX_KEY)
|
||||
)[github.event.inputs.deploy]
|
||||
}}"
|
||||
if: ${{ github.event.inputs.deploy != '' && github.event.inputs.deploy != 'NONE' }}
|
||||
|
||||
index:
|
||||
if: ${{ github.event.inputs.deploy != '' && github.event.inputs.deploy != 'NONE' }}
|
||||
needs: [image]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: >-
|
||||
curl "https://${{
|
||||
fromJson('{
|
||||
"alpha": "alpha-registry-x.start9.com",
|
||||
"beta": "beta-registry.start9.com",
|
||||
}')[github.event.inputs.deploy]
|
||||
}}:8443/resync.cgi?key=${{
|
||||
fromJson(
|
||||
format('{{
|
||||
"alpha": "{0}",
|
||||
"beta": "{1}",
|
||||
}}', secrets.ALPHA_INDEX_KEY, secrets.BETA_INDEX_KEY)
|
||||
)[github.event.inputs.deploy]
|
||||
}}"
|
||||
|
||||
24
.gitignore
vendored
24
.gitignore
vendored
@@ -1,22 +1,28 @@
|
||||
.DS_Store
|
||||
.idea
|
||||
*.img
|
||||
*.img.gz
|
||||
*.img.xz
|
||||
*.zip
|
||||
/*.img
|
||||
/*.img.gz
|
||||
/*.img.xz
|
||||
/*-raspios-bullseye-arm64-lite.img
|
||||
/*-raspios-bullseye-arm64-lite.zip
|
||||
/product_key.txt
|
||||
/*_product_key.txt
|
||||
.vscode/settings.json
|
||||
deploy_web.sh
|
||||
deploy_web.sh
|
||||
secrets.db
|
||||
.vscode/
|
||||
/build/env/*.txt
|
||||
*.deb
|
||||
/cargo-deps/**/*
|
||||
/PLATFORM.txt
|
||||
/ENVIRONMENT.txt
|
||||
/GIT_HASH.txt
|
||||
/VERSION.txt
|
||||
/*.deb
|
||||
/target
|
||||
*.squashfs
|
||||
/*.squashfs
|
||||
/results
|
||||
/dpkg-workdir
|
||||
/compiled.tar
|
||||
/compiled-*.tar
|
||||
/build/lib/firmware
|
||||
tmp
|
||||
/firmware
|
||||
/tmp
|
||||
150
Makefile
150
Makefile
@@ -1,23 +1,23 @@
|
||||
ls-files = $(shell git ls-files --cached --others --exclude-standard $1)
|
||||
PROFILE = release
|
||||
|
||||
PLATFORM_FILE := $(shell ./build/env/check-platform.sh)
|
||||
ENVIRONMENT_FILE := $(shell ./build/env/check-environment.sh)
|
||||
GIT_HASH_FILE := $(shell ./build/env/check-git-hash.sh)
|
||||
VERSION_FILE := $(shell ./build/env/check-version.sh)
|
||||
BASENAME := $(shell PROJECT=startos ./build/env/basename.sh)
|
||||
PLATFORM := $(shell if [ -f $(PLATFORM_FILE) ]; then cat $(PLATFORM_FILE); else echo unknown; fi)
|
||||
PLATFORM_FILE := $(shell ./check-platform.sh)
|
||||
ENVIRONMENT_FILE := $(shell ./check-environment.sh)
|
||||
GIT_HASH_FILE := $(shell ./check-git-hash.sh)
|
||||
VERSION_FILE := $(shell ./check-version.sh)
|
||||
BASENAME := $(shell PROJECT=startos ./basename.sh)
|
||||
PLATFORM := $(shell if [ -f ./PLATFORM.txt ]; then cat ./PLATFORM.txt; else echo unknown; fi)
|
||||
ARCH := $(shell if [ "$(PLATFORM)" = "raspberrypi" ]; then echo aarch64; else echo $(PLATFORM) | sed 's/-nonfree$$//g'; fi)
|
||||
RUST_ARCH := $(shell if [ "$(ARCH)" = "riscv64" ]; then echo riscv64gc; else echo $(ARCH); fi)
|
||||
REGISTRY_BASENAME := $(shell PROJECT=start-registry PLATFORM=$(ARCH) ./build/env/basename.sh)
|
||||
TUNNEL_BASENAME := $(shell PROJECT=start-tunnel PLATFORM=$(ARCH) ./build/env/basename.sh)
|
||||
REGISTRY_BASENAME := $(shell PROJECT=start-registry PLATFORM=$(ARCH) ./basename.sh)
|
||||
TUNNEL_BASENAME := $(shell PROJECT=start-tunnel PLATFORM=$(ARCH) ./basename.sh)
|
||||
IMAGE_TYPE=$(shell if [ "$(PLATFORM)" = raspberrypi ]; then echo img; else echo iso; fi)
|
||||
WEB_UIS := web/dist/raw/ui/index.html web/dist/raw/setup-wizard/index.html web/dist/raw/install-wizard/index.html
|
||||
COMPRESSED_WEB_UIS := web/dist/static/ui/index.html web/dist/static/setup-wizard/index.html web/dist/static/install-wizard/index.html
|
||||
FIRMWARE_ROMS := build/lib/firmware/$(PLATFORM) $(shell jq --raw-output '.[] | select(.platform[] | contains("$(PLATFORM)")) | "./build/lib/firmware/$(PLATFORM)/" + .id + ".rom.gz"' build/lib/firmware.json)
|
||||
BUILD_SRC := $(call ls-files, build/lib) build/lib/depends build/lib/conflicts $(FIRMWARE_ROMS)
|
||||
IMAGE_RECIPE_SRC := $(call ls-files, build/image-recipe/)
|
||||
STARTD_SRC := core/startd.service $(BUILD_SRC)
|
||||
FIRMWARE_ROMS := ./firmware/$(PLATFORM) $(shell jq --raw-output '.[] | select(.platform[] | contains("$(PLATFORM)")) | "./firmware/$(PLATFORM)/" + .id + ".rom.gz"' build/lib/firmware.json)
|
||||
BUILD_SRC := $(call ls-files, build) build/lib/depends build/lib/conflicts $(FIRMWARE_ROMS)
|
||||
IMAGE_RECIPE_SRC := $(call ls-files, image-recipe/)
|
||||
STARTD_SRC := core/startos/startd.service $(BUILD_SRC)
|
||||
CORE_SRC := $(call ls-files, core) $(shell git ls-files --recurse-submodules patch-db) $(GIT_HASH_FILE)
|
||||
WEB_SHARED_SRC := $(call ls-files, web/projects/shared) $(call ls-files, web/projects/marketplace) $(shell ls -p web/ | grep -v / | sed 's/^/web\//g') web/node_modules/.package-lock.json web/config.json patch-db/client/dist/index.js sdk/baseDist/package.json web/patchdb-ui-seed.json sdk/dist/package.json
|
||||
WEB_UI_SRC := $(call ls-files, web/projects/ui)
|
||||
@@ -28,18 +28,18 @@ PATCH_DB_CLIENT_SRC := $(shell git ls-files --recurse-submodules patch-db/client
|
||||
GZIP_BIN := $(shell which pigz || which gzip)
|
||||
TAR_BIN := $(shell which gtar || which tar)
|
||||
COMPILED_TARGETS := core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/startbox core/target/$(RUST_ARCH)-unknown-linux-musl/release/start-container container-runtime/rootfs.$(ARCH).squashfs
|
||||
STARTOS_TARGETS := $(STARTD_SRC) $(ENVIRONMENT_FILE) $(GIT_HASH_FILE) $(VERSION_FILE) $(COMPILED_TARGETS) target/$(RUST_ARCH)-unknown-linux-musl/release/startos-backup-fs $(PLATFORM_FILE) \
|
||||
STARTOS_TARGETS := $(STARTD_SRC) $(ENVIRONMENT_FILE) $(GIT_HASH_FILE) $(VERSION_FILE) $(COMPILED_TARGETS) cargo-deps/$(RUST_ARCH)-unknown-linux-musl/release/startos-backup-fs $(PLATFORM_FILE) \
|
||||
$(shell if [ "$(PLATFORM)" = "raspberrypi" ]; then \
|
||||
echo target/aarch64-unknown-linux-musl/release/pi-beep; \
|
||||
echo cargo-deps/aarch64-unknown-linux-musl/release/pi-beep; \
|
||||
fi) \
|
||||
$(shell /bin/bash -c 'if [[ "${ENVIRONMENT}" =~ (^|-)unstable($$|-) ]]; then \
|
||||
echo target/$(RUST_ARCH)-unknown-linux-musl/release/flamegraph; \
|
||||
echo cargo-deps/$(RUST_ARCH)-unknown-linux-musl/release/flamegraph; \
|
||||
fi') \
|
||||
$(shell /bin/bash -c 'if [[ "${ENVIRONMENT}" =~ (^|-)console($$|-) ]]; then \
|
||||
echo target/$(RUST_ARCH)-unknown-linux-musl/release/tokio-console; \
|
||||
echo cargo-deps/$(RUST_ARCH)-unknown-linux-musl/release/tokio-console; \
|
||||
fi')
|
||||
REGISTRY_TARGETS := core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/registrybox core/start-registryd.service
|
||||
TUNNEL_TARGETS := core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/tunnelbox core/start-tunneld.service
|
||||
REGISTRY_TARGETS := core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/registrybox core/startos/start-registryd.service
|
||||
TUNNEL_TARGETS := core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/tunnelbox core/startos/start-tunneld.service
|
||||
|
||||
ifeq ($(REMOTE),)
|
||||
mkdir = mkdir -p $1
|
||||
@@ -73,7 +73,7 @@ metadata: $(VERSION_FILE) $(PLATFORM_FILE) $(ENVIRONMENT_FILE) $(GIT_HASH_FILE)
|
||||
|
||||
clean:
|
||||
rm -rf core/target
|
||||
rm -rf core/bindings
|
||||
rm -rf core/startos/bindings
|
||||
rm -rf web/.angular
|
||||
rm -f web/config.json
|
||||
rm -rf web/node_modules
|
||||
@@ -81,7 +81,7 @@ clean:
|
||||
rm -rf patch-db/client/node_modules
|
||||
rm -rf patch-db/client/dist
|
||||
rm -rf patch-db/target
|
||||
rm -rf target
|
||||
rm -rf cargo-deps
|
||||
rm -rf dpkg-workdir
|
||||
rm -rf image-recipe/deb
|
||||
rm -rf results
|
||||
@@ -89,8 +89,14 @@ clean:
|
||||
rm -rf container-runtime/dist
|
||||
rm -rf container-runtime/node_modules
|
||||
rm -f container-runtime/*.squashfs
|
||||
if [ -d container-runtime/tmp/combined ] && mountpoint container-runtime/tmp/combined; then sudo umount container-runtime/tmp/combined; fi
|
||||
if [ -d container-runtime/tmp/lower ] && mountpoint container-runtime/tmp/lower; then sudo umount container-runtime/tmp/lower; fi
|
||||
rm -rf container-runtime/tmp
|
||||
(cd sdk && make clean)
|
||||
rm -f env/*.txt
|
||||
rm -f ENVIRONMENT.txt
|
||||
rm -f PLATFORM.txt
|
||||
rm -f GIT_HASH.txt
|
||||
rm -f VERSION.txt
|
||||
|
||||
format:
|
||||
cd core && cargo +nightly fmt
|
||||
@@ -107,10 +113,10 @@ test-container-runtime: container-runtime/node_modules/.package-lock.json $(call
|
||||
cd container-runtime && npm test
|
||||
|
||||
install-cli: $(GIT_HASH_FILE)
|
||||
./core/build/build-cli.sh --install
|
||||
./core/build-cli.sh --install
|
||||
|
||||
cli: $(GIT_HASH_FILE)
|
||||
./core/build/build-cli.sh
|
||||
./core/build-cli.sh
|
||||
|
||||
registry: core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/registrybox
|
||||
|
||||
@@ -121,49 +127,49 @@ install-registry: $(REGISTRY_TARGETS)
|
||||
$(call ln,/usr/bin/start-registrybox,$(DESTDIR)/usr/bin/start-registry)
|
||||
|
||||
$(call mkdir,$(DESTDIR)/lib/systemd/system)
|
||||
$(call cp,core/start-registryd.service,$(DESTDIR)/lib/systemd/system/start-registryd.service)
|
||||
$(call cp,core/startos/start-registryd.service,$(DESTDIR)/lib/systemd/system/start-registryd.service)
|
||||
|
||||
core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/registrybox: $(CORE_SRC) $(ENVIRONMENT_FILE)
|
||||
ARCH=$(ARCH) PROFILE=$(PROFILE) ./core/build/build-registrybox.sh
|
||||
ARCH=$(ARCH) PROFILE=$(PROFILE) ./core/build-registrybox.sh
|
||||
|
||||
tunnel: core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/tunnelbox
|
||||
|
||||
install-tunnel: core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/tunnelbox core/start-tunneld.service
|
||||
install-tunnel: core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/tunnelbox core/startos/start-tunneld.service
|
||||
$(call mkdir,$(DESTDIR)/usr/bin)
|
||||
$(call cp,core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/tunnelbox,$(DESTDIR)/usr/bin/start-tunnelbox)
|
||||
$(call ln,/usr/bin/start-tunnelbox,$(DESTDIR)/usr/bin/start-tunneld)
|
||||
$(call ln,/usr/bin/start-tunnelbox,$(DESTDIR)/usr/bin/start-tunnel)
|
||||
|
||||
$(call mkdir,$(DESTDIR)/lib/systemd/system)
|
||||
$(call cp,core/start-tunneld.service,$(DESTDIR)/lib/systemd/system/start-tunneld.service)
|
||||
$(call cp,core/startos/start-tunneld.service,$(DESTDIR)/lib/systemd/system/start-tunneld.service)
|
||||
|
||||
$(call mkdir,$(DESTDIR)/usr/lib/startos/scripts)
|
||||
$(call cp,build/lib/scripts/forward-port,$(DESTDIR)/usr/lib/startos/scripts/forward-port)
|
||||
|
||||
core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/tunnelbox: $(CORE_SRC) $(ENVIRONMENT_FILE) $(GIT_HASH_FILE) web/dist/static/start-tunnel/index.html
|
||||
ARCH=$(ARCH) PROFILE=$(PROFILE) ./core/build/build-tunnelbox.sh
|
||||
ARCH=$(ARCH) PROFILE=$(PROFILE) ./core/build-tunnelbox.sh
|
||||
|
||||
deb: results/$(BASENAME).deb
|
||||
|
||||
results/$(BASENAME).deb: debian/dpkg-build.sh $(call ls-files,debian/startos) $(STARTOS_TARGETS)
|
||||
PLATFORM=$(PLATFORM) REQUIRES=debian ./build/os-compat/run-compat.sh ./debian/dpkg-build.sh
|
||||
results/$(BASENAME).deb: dpkg-build.sh $(call ls-files,debian/startos) $(STARTOS_TARGETS)
|
||||
PLATFORM=$(PLATFORM) REQUIRES=debian ./build/os-compat/run-compat.sh ./dpkg-build.sh
|
||||
|
||||
registry-deb: results/$(REGISTRY_BASENAME).deb
|
||||
|
||||
results/$(REGISTRY_BASENAME).deb: debian/dpkg-build.sh $(call ls-files,debian/start-registry) $(REGISTRY_TARGETS)
|
||||
PROJECT=start-registry PLATFORM=$(ARCH) REQUIRES=debian ./build/os-compat/run-compat.sh ./debian/dpkg-build.sh
|
||||
results/$(REGISTRY_BASENAME).deb: dpkg-build.sh $(call ls-files,debian/start-registry) $(REGISTRY_TARGETS)
|
||||
PROJECT=start-registry PLATFORM=$(ARCH) REQUIRES=debian ./build/os-compat/run-compat.sh ./dpkg-build.sh
|
||||
|
||||
tunnel-deb: results/$(TUNNEL_BASENAME).deb
|
||||
|
||||
results/$(TUNNEL_BASENAME).deb: debian/dpkg-build.sh $(call ls-files,debian/start-tunnel) $(TUNNEL_TARGETS) build/lib/scripts/forward-port
|
||||
PROJECT=start-tunnel PLATFORM=$(ARCH) REQUIRES=debian DEPENDS=wireguard-tools,iptables,conntrack ./build/os-compat/run-compat.sh ./debian/dpkg-build.sh
|
||||
results/$(TUNNEL_BASENAME).deb: dpkg-build.sh $(call ls-files,debian/start-tunnel) $(TUNNEL_TARGETS) build/lib/scripts/forward-port
|
||||
PROJECT=start-tunnel PLATFORM=$(ARCH) REQUIRES=debian DEPENDS=wireguard-tools,iptables,conntrack ./build/os-compat/run-compat.sh ./dpkg-build.sh
|
||||
|
||||
$(IMAGE_TYPE): results/$(BASENAME).$(IMAGE_TYPE)
|
||||
|
||||
squashfs: results/$(BASENAME).squashfs
|
||||
|
||||
results/$(BASENAME).$(IMAGE_TYPE) results/$(BASENAME).squashfs: $(IMAGE_RECIPE_SRC) results/$(BASENAME).deb
|
||||
ARCH=$(ARCH) ./build/image-recipe/run-local-build.sh "results/$(BASENAME).deb"
|
||||
./image-recipe/run-local-build.sh "results/$(BASENAME).deb"
|
||||
|
||||
# For creating os images. DO NOT USE
|
||||
install: $(STARTOS_TARGETS)
|
||||
@@ -172,18 +178,18 @@ install: $(STARTOS_TARGETS)
|
||||
$(call cp,core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/startbox,$(DESTDIR)/usr/bin/startbox)
|
||||
$(call ln,/usr/bin/startbox,$(DESTDIR)/usr/bin/startd)
|
||||
$(call ln,/usr/bin/startbox,$(DESTDIR)/usr/bin/start-cli)
|
||||
if [ "$(PLATFORM)" = "raspberrypi" ]; then $(call cp,target/aarch64-unknown-linux-musl/release/pi-beep,$(DESTDIR)/usr/bin/pi-beep); fi
|
||||
if [ "$(PLATFORM)" = "raspberrypi" ]; then $(call cp,cargo-deps/aarch64-unknown-linux-musl/release/pi-beep,$(DESTDIR)/usr/bin/pi-beep); fi
|
||||
if /bin/bash -c '[[ "${ENVIRONMENT}" =~ (^|-)unstable($$|-) ]]'; then \
|
||||
$(call cp,target/$(RUST_ARCH)-unknown-linux-musl/release/flamegraph,$(DESTDIR)/usr/bin/flamegraph); \
|
||||
$(call cp,cargo-deps/$(RUST_ARCH)-unknown-linux-musl/release/flamegraph,$(DESTDIR)/usr/bin/flamegraph); \
|
||||
fi
|
||||
if /bin/bash -c '[[ "${ENVIRONMENT}" =~ (^|-)console($$|-) ]]'; then \
|
||||
$(call cp,target/$(RUST_ARCH)-unknown-linux-musl/release/tokio-console,$(DESTDIR)/usr/bin/tokio-console); \
|
||||
$(call cp,cargo-deps/$(RUST_ARCH)-unknown-linux-musl/release/tokio-console,$(DESTDIR)/usr/bin/tokio-console); \
|
||||
fi
|
||||
$(call cp,target/$(RUST_ARCH)-unknown-linux-musl/release/startos-backup-fs,$(DESTDIR)/usr/bin/startos-backup-fs)
|
||||
$(call cp,cargo-deps/$(RUST_ARCH)-unknown-linux-musl/release/startos-backup-fs,$(DESTDIR)/usr/bin/startos-backup-fs)
|
||||
$(call ln,/usr/bin/startos-backup-fs,$(DESTDIR)/usr/sbin/mount.backup-fs)
|
||||
|
||||
$(call mkdir,$(DESTDIR)/lib/systemd/system)
|
||||
$(call cp,core/startd.service,$(DESTDIR)/lib/systemd/system/startd.service)
|
||||
$(call cp,core/startos/startd.service,$(DESTDIR)/lib/systemd/system/startd.service)
|
||||
|
||||
$(call mkdir,$(DESTDIR)/usr/lib)
|
||||
$(call rm,$(DESTDIR)/usr/lib/startos)
|
||||
@@ -191,16 +197,18 @@ install: $(STARTOS_TARGETS)
|
||||
$(call mkdir,$(DESTDIR)/usr/lib/startos/container-runtime)
|
||||
$(call cp,container-runtime/rootfs.$(ARCH).squashfs,$(DESTDIR)/usr/lib/startos/container-runtime/rootfs.squashfs)
|
||||
|
||||
$(call cp,build/env/PLATFORM.txt,$(DESTDIR)/usr/lib/startos/PLATFORM.txt)
|
||||
$(call cp,build/env/ENVIRONMENT.txt,$(DESTDIR)/usr/lib/startos/ENVIRONMENT.txt)
|
||||
$(call cp,build/env/GIT_HASH.txt,$(DESTDIR)/usr/lib/startos/GIT_HASH.txt)
|
||||
$(call cp,build/env/VERSION.txt,$(DESTDIR)/usr/lib/startos/VERSION.txt)
|
||||
$(call cp,PLATFORM.txt,$(DESTDIR)/usr/lib/startos/PLATFORM.txt)
|
||||
$(call cp,ENVIRONMENT.txt,$(DESTDIR)/usr/lib/startos/ENVIRONMENT.txt)
|
||||
$(call cp,GIT_HASH.txt,$(DESTDIR)/usr/lib/startos/GIT_HASH.txt)
|
||||
$(call cp,VERSION.txt,$(DESTDIR)/usr/lib/startos/VERSION.txt)
|
||||
|
||||
$(call cp,firmware/$(PLATFORM),$(DESTDIR)/usr/lib/startos/firmware)
|
||||
|
||||
update-overlay: $(STARTOS_TARGETS)
|
||||
@echo "\033[33m!!! THIS WILL ONLY REFLASH YOUR DEVICE IN MEMORY !!!\033[0m"
|
||||
@echo "\033[33mALL CHANGES WILL BE REVERTED IF YOU RESTART THE DEVICE\033[0m"
|
||||
@if [ -z "$(REMOTE)" ]; then >&2 echo "Must specify REMOTE" && false; fi
|
||||
@if [ "`ssh $(REMOTE) 'cat /usr/lib/startos/VERSION.txt'`" != "`cat $(VERSION_FILE)`" ]; then >&2 echo "StartOS requires migrations: update-overlay is unavailable." && false; fi
|
||||
@if [ "`ssh $(REMOTE) 'cat /usr/lib/startos/VERSION.txt'`" != "`cat ./VERSION.txt`" ]; then >&2 echo "StartOS requires migrations: update-overlay is unavailable." && false; fi
|
||||
$(call ssh,"sudo systemctl stop startd")
|
||||
$(MAKE) install REMOTE=$(REMOTE) SSHPASS=$(SSHPASS) PLATFORM=$(PLATFORM)
|
||||
$(call ssh,"sudo systemctl start startd")
|
||||
@@ -258,7 +266,7 @@ emulate-reflash: $(STARTOS_TARGETS)
|
||||
$(call ssh,'sudo /media/startos/next/usr/lib/startos/scripts/chroot-and-upgrade --no-sync "apt-get install -y $(shell cat ./build/lib/depends)"')
|
||||
|
||||
upload-ota: results/$(BASENAME).squashfs
|
||||
TARGET=$(TARGET) KEY=$(KEY) ./build/upload-ota.sh
|
||||
TARGET=$(TARGET) KEY=$(KEY) ./upload-ota.sh
|
||||
|
||||
container-runtime/debian.$(ARCH).squashfs: ./container-runtime/download-base-image.sh
|
||||
ARCH=$(ARCH) ./container-runtime/download-base-image.sh
|
||||
@@ -271,16 +279,16 @@ container-runtime/node_modules/.package-lock.json: container-runtime/package-loc
|
||||
npm --prefix container-runtime ci
|
||||
touch container-runtime/node_modules/.package-lock.json
|
||||
|
||||
ts-bindings: core/bindings/index.ts
|
||||
ts-bindings: core/startos/bindings/index.ts
|
||||
mkdir -p sdk/base/lib/osBindings
|
||||
rsync -ac --delete core/bindings/ sdk/base/lib/osBindings/
|
||||
rsync -ac --delete core/startos/bindings/ sdk/base/lib/osBindings/
|
||||
|
||||
core/bindings/index.ts: $(call ls-files, core) $(ENVIRONMENT_FILE)
|
||||
rm -rf core/bindings
|
||||
./core/build/build-ts.sh
|
||||
ls core/bindings/*.ts | sed 's/core\/bindings\/\([^.]*\)\.ts/export { \1 } from ".\/\1";/g' | grep -v '"./index"' | tee core/bindings/index.ts
|
||||
npm --prefix sdk exec -- prettier --config ./sdk/base/package.json -w ./core/bindings/*.ts
|
||||
touch core/bindings/index.ts
|
||||
core/startos/bindings/index.ts: $(call ls-files, core) $(ENVIRONMENT_FILE)
|
||||
rm -rf core/startos/bindings
|
||||
./core/build-ts.sh
|
||||
ls core/startos/bindings/*.ts | sed 's/core\/startos\/bindings\/\([^.]*\)\.ts/export { \1 } from ".\/\1";/g' | grep -v '"./index"' | tee core/startos/bindings/index.ts
|
||||
npm --prefix sdk exec -- prettier --config ./sdk/base/package.json -w ./core/startos/bindings/*.ts
|
||||
touch core/startos/bindings/index.ts
|
||||
|
||||
sdk/dist/package.json sdk/baseDist/package.json: $(call ls-files, sdk) sdk/base/lib/osBindings/index.ts
|
||||
(cd sdk && make bundle)
|
||||
@@ -295,21 +303,21 @@ container-runtime/dist/node_modules/.package-lock.json container-runtime/dist/pa
|
||||
./container-runtime/install-dist-deps.sh
|
||||
touch container-runtime/dist/node_modules/.package-lock.json
|
||||
|
||||
container-runtime/rootfs.$(ARCH).squashfs: container-runtime/debian.$(ARCH).squashfs container-runtime/container-runtime.service container-runtime/update-image.sh container-runtime/update-image-local.sh container-runtime/deb-install.sh container-runtime/dist/index.js container-runtime/dist/node_modules/.package-lock.json core/target/$(RUST_ARCH)-unknown-linux-musl/release/start-container
|
||||
ARCH=$(ARCH) ./container-runtime/update-image-local.sh
|
||||
container-runtime/rootfs.$(ARCH).squashfs: container-runtime/debian.$(ARCH).squashfs container-runtime/container-runtime.service container-runtime/update-image.sh container-runtime/deb-install.sh container-runtime/dist/index.js container-runtime/dist/node_modules/.package-lock.json core/target/$(RUST_ARCH)-unknown-linux-musl/release/start-container
|
||||
ARCH=$(ARCH) REQUIRES=qemu ./build/os-compat/run-compat.sh ./container-runtime/update-image.sh
|
||||
|
||||
build/lib/depends build/lib/conflicts: $(ENVIRONMENT_FILE) $(PLATFORM_FILE) $(shell ls build/dpkg-deps/*)
|
||||
PLATFORM=$(PLATFORM) ARCH=$(ARCH) build/dpkg-deps/generate.sh
|
||||
|
||||
$(FIRMWARE_ROMS): build/lib/firmware.json ./build/download-firmware.sh $(PLATFORM_FILE)
|
||||
./build/download-firmware.sh $(PLATFORM)
|
||||
$(FIRMWARE_ROMS): build/lib/firmware.json download-firmware.sh $(PLATFORM_FILE)
|
||||
./download-firmware.sh $(PLATFORM)
|
||||
|
||||
core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/startbox: $(CORE_SRC) $(COMPRESSED_WEB_UIS) web/patchdb-ui-seed.json $(ENVIRONMENT_FILE)
|
||||
ARCH=$(ARCH) PROFILE=$(PROFILE) ./core/build/build-startbox.sh
|
||||
ARCH=$(ARCH) PROFILE=$(PROFILE) ./core/build-startbox.sh
|
||||
touch core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/startbox
|
||||
|
||||
core/target/$(RUST_ARCH)-unknown-linux-musl/release/start-container: $(CORE_SRC) $(ENVIRONMENT_FILE)
|
||||
ARCH=$(ARCH) ./core/build/build-start-container.sh
|
||||
ARCH=$(ARCH) ./core/build-start-container.sh
|
||||
touch core/target/$(RUST_ARCH)-unknown-linux-musl/release/start-container
|
||||
|
||||
web/package-lock.json: web/package.json sdk/baseDist/package.json
|
||||
@@ -342,10 +350,10 @@ web/dist/raw/start-tunnel/index.html: $(WEB_START_TUNNEL_SRC) $(WEB_SHARED_SRC)
|
||||
touch web/dist/raw/start-tunnel/index.html
|
||||
|
||||
web/dist/static/%/index.html: web/dist/raw/%/index.html
|
||||
./web/compress-uis.sh $*
|
||||
./compress-uis.sh $*
|
||||
|
||||
web/config.json: $(GIT_HASH_FILE) $(ENVIRONMENT_FILE) web/config-sample.json web/update-config.sh
|
||||
./web/update-config.sh
|
||||
web/config.json: $(GIT_HASH_FILE) web/config-sample.json
|
||||
jq '.useMocks = false' web/config-sample.json | jq '.gitHash = "$(shell cat GIT_HASH.txt)"' > web/config.json
|
||||
|
||||
patch-db/client/node_modules/.package-lock.json: patch-db/client/package.json
|
||||
npm --prefix patch-db/client ci
|
||||
@@ -366,17 +374,17 @@ uis: $(WEB_UIS)
|
||||
# this is a convenience step to build the UI
|
||||
ui: web/dist/raw/ui
|
||||
|
||||
target/aarch64-unknown-linux-musl/release/pi-beep: ./build/build-cargo-dep.sh
|
||||
ARCH=aarch64 ./build/build-cargo-dep.sh pi-beep
|
||||
cargo-deps/aarch64-unknown-linux-musl/release/pi-beep: ./build-cargo-dep.sh
|
||||
ARCH=aarch64 ./build-cargo-dep.sh pi-beep
|
||||
|
||||
target/$(RUST_ARCH)-unknown-linux-musl/release/tokio-console: ./build/build-cargo-dep.sh
|
||||
ARCH=$(ARCH) ./build/build-cargo-dep.sh tokio-console
|
||||
cargo-deps/$(RUST_ARCH)-unknown-linux-musl/release/tokio-console: ./build-cargo-dep.sh
|
||||
ARCH=$(ARCH) ./build-cargo-dep.sh tokio-console
|
||||
touch $@
|
||||
|
||||
target/$(RUST_ARCH)-unknown-linux-musl/release/startos-backup-fs: ./build/build-cargo-dep.sh
|
||||
ARCH=$(ARCH) ./build/build-cargo-dep.sh --git https://github.com/Start9Labs/start-fs.git startos-backup-fs
|
||||
cargo-deps/$(RUST_ARCH)-unknown-linux-musl/release/startos-backup-fs: ./build-cargo-dep.sh
|
||||
ARCH=$(ARCH) ./build-cargo-dep.sh --git https://github.com/Start9Labs/start-fs.git startos-backup-fs
|
||||
touch $@
|
||||
|
||||
target/$(RUST_ARCH)-unknown-linux-musl/release/flamegraph: ./build/build-cargo-dep.sh
|
||||
ARCH=$(ARCH) ./build/build-cargo-dep.sh flamegraph
|
||||
cargo-deps/$(RUST_ARCH)-unknown-linux-musl/release/flamegraph: ./build-cargo-dep.sh
|
||||
ARCH=$(ARCH) ./build-cargo-dep.sh flamegraph
|
||||
touch $@
|
||||
|
||||
@@ -10,7 +10,7 @@ When bumping from version `X.Y.Z-alpha.N` to `X.Y.Z-alpha.N+1`, you need to upda
|
||||
|
||||
### 1. Core Rust Crate Version
|
||||
|
||||
**File: `core/Cargo.toml`**
|
||||
**File: `core/startos/Cargo.toml`**
|
||||
|
||||
Update the version string (line ~18):
|
||||
|
||||
@@ -31,7 +31,7 @@ This will update the version in `Cargo.lock` automatically.
|
||||
|
||||
### 2. Create New Version Migration Module
|
||||
|
||||
**File: `core/src/version/vX_Y_Z_alpha_N+1.rs`**
|
||||
**File: `core/startos/src/version/vX_Y_Z_alpha_N+1.rs`**
|
||||
|
||||
Create a new version file by copying the previous version and updating:
|
||||
|
||||
@@ -79,7 +79,7 @@ impl VersionT for Version {
|
||||
|
||||
### 3. Update Version Module Registry
|
||||
|
||||
**File: `core/src/version/mod.rs`**
|
||||
**File: `core/startos/src/version/mod.rs`**
|
||||
|
||||
Make changes in **5 locations**:
|
||||
|
||||
@@ -176,9 +176,9 @@ This pattern helps you quickly find all the places that need updating in the nex
|
||||
|
||||
## Summary Checklist
|
||||
|
||||
- [ ] Update `core/Cargo.toml` version
|
||||
- [ ] Create new `core/src/version/vX_Y_Z_alpha_N+1.rs` file
|
||||
- [ ] Update `core/src/version/mod.rs` in 5 locations
|
||||
- [ ] Update `core/startos/Cargo.toml` version
|
||||
- [ ] Create new `core/startos/src/version/vX_Y_Z_alpha_N+1.rs` file
|
||||
- [ ] Update `core/startos/src/version/mod.rs` in 5 locations
|
||||
- [ ] Run `cargo check` to update `core/Cargo.lock`
|
||||
- [ ] Update `sdk/package/lib/StartSdk.ts` OSVersion
|
||||
- [ ] Update `web/package.json` and `web/package-lock.json` version
|
||||
|
||||
29
build-cargo-dep.sh
Executable file
29
build-cargo-dep.sh
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
shopt -s expand_aliases
|
||||
|
||||
if [ "$0" != "./build-cargo-dep.sh" ]; then
|
||||
>&2 echo "Must be run from start-os directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$ARCH" ]; then
|
||||
ARCH=$(uname -m)
|
||||
fi
|
||||
|
||||
RUST_ARCH="$ARCH"
|
||||
if [ "$ARCH" = "riscv64" ]; then
|
||||
RUST_ARCH="riscv64gc"
|
||||
fi
|
||||
|
||||
mkdir -p cargo-deps
|
||||
|
||||
source core/builder-alias.sh
|
||||
|
||||
RUSTFLAGS="-C target-feature=+crt-static"
|
||||
|
||||
rust-zig-builder cargo-zigbuild install $* --target-dir /workdir/cargo-deps/ --target=$RUST_ARCH-unknown-linux-musl
|
||||
if [ "$(ls -nd "cargo-deps/$RUST_ARCH-unknown-linux-musl/release/${!#}" | awk '{ print $3 }')" != "$UID" ]; then
|
||||
rust-zig-builder sh -c "chown -R $UID:$UID cargo-deps && chown -R $UID:$UID /usr/local/cargo"
|
||||
fi
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")/.."
|
||||
|
||||
set -e
|
||||
shopt -s expand_aliases
|
||||
|
||||
if [ -z "$ARCH" ]; then
|
||||
ARCH=$(uname -m)
|
||||
fi
|
||||
|
||||
RUST_ARCH="$ARCH"
|
||||
if [ "$ARCH" = "riscv64" ]; then
|
||||
RUST_ARCH="riscv64gc"
|
||||
fi
|
||||
|
||||
mkdir -p target
|
||||
|
||||
source core/build/builder-alias.sh
|
||||
|
||||
RUSTFLAGS="-C target-feature=+crt-static"
|
||||
|
||||
rust-zig-builder cargo-zigbuild install $* --target-dir /workdir/target/ --target=$RUST_ARCH-unknown-linux-musl
|
||||
if [ "$(ls -nd "target/$RUST_ARCH-unknown-linux-musl/release/${!#}" | awk '{ print $3 }')" != "$UID" ]; then
|
||||
rust-zig-builder sh -c "chown -R $UID:$UID target && chown -R $UID:$UID /usr/local/cargo"
|
||||
fi
|
||||
@@ -3,7 +3,6 @@ avahi-utils
|
||||
b3sum
|
||||
bash-completion
|
||||
beep
|
||||
binfmt-support
|
||||
bmon
|
||||
btrfs-progs
|
||||
ca-certificates
|
||||
@@ -16,7 +15,6 @@ dnsutils
|
||||
dosfstools
|
||||
e2fsprogs
|
||||
ecryptfs-utils
|
||||
equivs
|
||||
exfatprogs
|
||||
flashrom
|
||||
fuse3
|
||||
|
||||
@@ -9,9 +9,6 @@ FEATURES+=("${ARCH}")
|
||||
if [ "$ARCH" != "$PLATFORM" ]; then
|
||||
FEATURES+=("${PLATFORM}")
|
||||
fi
|
||||
if [[ "$PLATFORM" =~ -nonfree$ ]]; then
|
||||
FEATURES+=("nonfree")
|
||||
fi
|
||||
|
||||
feature_file_checker='
|
||||
/^#/ { next }
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
+ firmware-amd-graphics
|
||||
+ firmware-atheros
|
||||
+ firmware-brcm80211
|
||||
+ firmware-iwlwifi
|
||||
+ firmware-libertas
|
||||
+ firmware-misc-nonfree
|
||||
+ firmware-realtek
|
||||
+ nvidia-container-toolkit
|
||||
# + nvidia-driver
|
||||
# + nvidia-kernel-dkms
|
||||
@@ -1,35 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")/../.."
|
||||
|
||||
BASEDIR="$(pwd -P)"
|
||||
|
||||
SUITE=trixie
|
||||
|
||||
USE_TTY=
|
||||
if tty -s; then
|
||||
USE_TTY="-it"
|
||||
fi
|
||||
|
||||
dockerfile_hash=$(sha256sum ${BASEDIR}/build/image-recipe/Dockerfile | head -c 7)
|
||||
|
||||
docker_img_name="start9/build-iso:${SUITE}-${dockerfile_hash}"
|
||||
|
||||
platform=linux/${ARCH}
|
||||
case $ARCH in
|
||||
x86_64)
|
||||
platform=linux/amd64;;
|
||||
aarch64)
|
||||
platform=linux/arm64;;
|
||||
esac
|
||||
|
||||
if ! docker run --rm --platform=$platform "${docker_img_name}" true 2> /dev/null; then
|
||||
docker buildx build --load --platform=$platform --build-arg=SUITE=${SUITE} -t "${docker_img_name}" ./build/image-recipe
|
||||
fi
|
||||
|
||||
docker run $USE_TTY --rm --platform=$platform --privileged -v "$(pwd)/build/image-recipe:/root/image-recipe" -v "$(pwd)/results:/root/results" \
|
||||
-e IB_SUITE="$SUITE" \
|
||||
-e IB_UID="$UID" \
|
||||
-e IB_INCLUDE \
|
||||
"${docker_img_name}" /root/image-recipe/build.sh $@
|
||||
@@ -4,7 +4,7 @@ parse_essential_db_info() {
|
||||
DB_DUMP="/tmp/startos_db.json"
|
||||
|
||||
if command -v start-cli >/dev/null 2>&1; then
|
||||
timeout 30 start-cli db dump > "$DB_DUMP" 2>/dev/null || return 1
|
||||
start-cli db dump > "$DB_DUMP" 2>/dev/null || return 1
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -63,7 +63,7 @@ mount --bind /proc /media/startos/next/proc
|
||||
mount --bind /boot /media/startos/next/boot
|
||||
mount --bind /media/startos/root /media/startos/next/media/startos/root
|
||||
|
||||
if mountpoint /sys/firmware/efi/efivars 2>&1 > /dev/null; then
|
||||
if mountpoint /sys/firmware/efi/efivars 2> /dev/null; then
|
||||
mount --bind /sys/firmware/efi/efivars /media/startos/next/sys/firmware/efi/efivars
|
||||
fi
|
||||
|
||||
@@ -75,7 +75,7 @@ else
|
||||
CHROOT_RES=$?
|
||||
fi
|
||||
|
||||
if mountpoint /media/startos/next/sys/firmware/efi/efivars 2>&1 > /dev/null; then
|
||||
if mountpoint /media/startos/next/sys/firmware/efi/efivars 2> /dev/null; then
|
||||
umount /media/startos/next/sys/firmware/efi/efivars
|
||||
fi
|
||||
|
||||
|
||||
@@ -35,20 +35,16 @@ if [ "$UNDO" = 1 ]; then
|
||||
exit $err
|
||||
fi
|
||||
|
||||
# DNAT: rewrite destination for incoming packets (external traffic)
|
||||
iptables -t nat -A ${NAME}_PREROUTING -d "$sip" -p tcp --dport "$sport" -j DNAT --to-destination "$dip:$dport"
|
||||
iptables -t nat -A ${NAME}_PREROUTING -d "$sip" -p udp --dport "$sport" -j DNAT --to-destination "$dip:$dport"
|
||||
|
||||
# DNAT: rewrite destination for locally-originated packets (hairpin from host itself)
|
||||
iptables -t nat -A ${NAME}_OUTPUT -d "$sip" -p tcp --dport "$sport" -j DNAT --to-destination "$dip:$dport"
|
||||
iptables -t nat -A ${NAME}_OUTPUT -d "$sip" -p udp --dport "$sport" -j DNAT --to-destination "$dip:$dport"
|
||||
|
||||
# MASQUERADE: rewrite source for all forwarded traffic to the destination
|
||||
# This ensures responses are routed back through the host regardless of source IP
|
||||
iptables -t nat -A ${NAME}_POSTROUTING -d "$dip" -p tcp --dport "$dport" -j MASQUERADE
|
||||
iptables -t nat -A ${NAME}_POSTROUTING -d "$dip" -p udp --dport "$dport" -j MASQUERADE
|
||||
iptables -t nat -A ${NAME}_PREROUTING -s "$dip/$dprefix" -d "$sip" -p tcp --dport "$sport" -j DNAT --to-destination "$dip:$dport"
|
||||
iptables -t nat -A ${NAME}_PREROUTING -s "$dip/$dprefix" -d "$sip" -p udp --dport "$sport" -j DNAT --to-destination "$dip:$dport"
|
||||
iptables -t nat -A ${NAME}_POSTROUTING -s "$dip/$dprefix" -d "$dip" -p tcp --dport "$dport" -j MASQUERADE
|
||||
iptables -t nat -A ${NAME}_POSTROUTING -s "$dip/$dprefix" -d "$dip" -p udp --dport "$dport" -j MASQUERADE
|
||||
|
||||
# Allow new connections to be forwarded to the destination
|
||||
iptables -A ${NAME}_FORWARD -d $dip -p tcp --dport $dport -m state --state NEW -j ACCEPT
|
||||
iptables -A ${NAME}_FORWARD -d $dip -p udp --dport $dport -m state --state NEW -j ACCEPT
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
export DEBCONF_NONINTERACTIVE_SEEN=true
|
||||
|
||||
TMP_DIR=$(mktemp -d)
|
||||
|
||||
(
|
||||
set -e
|
||||
cd $TMP_DIR
|
||||
|
||||
cat > control.equivs
|
||||
equivs-build control.equivs
|
||||
apt-get install -y ./*.deb < /dev/null
|
||||
)
|
||||
|
||||
rm -rf $TMP_DIR
|
||||
|
||||
echo Install complete. >&2
|
||||
exit 0
|
||||
@@ -50,12 +50,12 @@ mount --bind /proc /media/startos/next/proc
|
||||
mount --bind /boot /media/startos/next/boot
|
||||
mount --bind /media/startos/root /media/startos/next/media/startos/root
|
||||
|
||||
if mountpoint /boot/efi 2>&1 > /dev/null; then
|
||||
if mountpoint /boot/efi 2> /dev/null; then
|
||||
mkdir -p /media/startos/next/boot/efi
|
||||
mount --bind /boot/efi /media/startos/next/boot/efi
|
||||
fi
|
||||
|
||||
if mountpoint /sys/firmware/efi/efivars 2>&1 > /dev/null; then
|
||||
if mountpoint /sys/firmware/efi/efivars 2> /dev/null; then
|
||||
mount --bind /sys/firmware/efi/efivars /media/startos/next/sys/firmware/efi/efivars
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM debian:trixie
|
||||
FROM debian:forky
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y \
|
||||
@@ -12,14 +12,35 @@ RUN apt-get update && \
|
||||
jq \
|
||||
gzip \
|
||||
brotli \
|
||||
qemu-user-static \
|
||||
binfmt-support \
|
||||
squashfs-tools \
|
||||
git \
|
||||
debspawn \
|
||||
rsync \
|
||||
b3sum \
|
||||
fuse-overlayfs \
|
||||
sudo \
|
||||
systemd \
|
||||
systemd-container \
|
||||
systemd-sysv \
|
||||
dbus \
|
||||
dbus-user-session \
|
||||
nodejs
|
||||
|
||||
RUN systemctl mask \
|
||||
systemd-firstboot.service \
|
||||
systemd-udevd.service \
|
||||
getty@tty1.service \
|
||||
console-getty.service
|
||||
|
||||
RUN git config --global --add safe.directory /root/start-os
|
||||
|
||||
RUN mkdir -p /etc/debspawn && \
|
||||
echo "AllowUnsafePermissions=true" > /etc/debspawn/global.toml
|
||||
|
||||
RUN mkdir -p /root/start-os
|
||||
WORKDIR /root/start-os
|
||||
|
||||
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||||
ENTRYPOINT [ "/docker-entrypoint.sh" ]
|
||||
3
build/os-compat/docker-entrypoint.sh
Executable file
3
build/os-compat/docker-entrypoint.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
exec /lib/systemd/systemd --unit=multi-user.target --show-status=false --log-target=journal
|
||||
@@ -1,30 +1,27 @@
|
||||
#!/bin/bash
|
||||
|
||||
pwd=$(pwd)
|
||||
if [ "$FORCE_COMPAT" = 1 ] || ( [ "$REQUIRES" = "linux" ] && [ "$(uname -s)" != "Linux" ] ) || ( [ "$REQUIRES" = "debian" ] && ! which dpkg > /dev/null ) || ( [ "$REQUIRES" = "qemu" ] && ! which qemu-$ARCH > /dev/null ); then
|
||||
project_pwd="$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd)/"
|
||||
pwd="$(pwd)/"
|
||||
if ! [[ "$pwd" = "$project_pwd"* ]]; then
|
||||
>&2 echo "Must be run from start-os project dir"
|
||||
exit 1
|
||||
fi
|
||||
rel_pwd="${pwd#"$project_pwd"}"
|
||||
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")/../.."
|
||||
|
||||
set -e
|
||||
|
||||
rel_pwd="${pwd#"$(pwd)"}"
|
||||
|
||||
COMPAT_ARCH=$(uname -m)
|
||||
|
||||
platform=linux/$COMPAT_ARCH
|
||||
|
||||
case $COMPAT_ARCH in
|
||||
x86_64)
|
||||
platform=linux/amd64;;
|
||||
aarch64)
|
||||
platform=linux/arm64;;
|
||||
esac
|
||||
|
||||
if [ "$FORCE_COMPAT" = 1 ] || ( [ "$REQUIRES" = "linux" ] && [ "$(uname -s)" != "Linux" ] ) || ( [ "$REQUIRES" = "debian" ] && ! which dpkg > /dev/null ); then
|
||||
SYSTEMD_TTY="-P"
|
||||
USE_TTY=
|
||||
if tty -s; then
|
||||
USE_TTY="-it"
|
||||
SYSTEMD_TTY="-t"
|
||||
fi
|
||||
|
||||
docker run $USE_TTY --platform=$platform -eARCH -eENVIRONMENT -ePLATFORM -eGIT_BRANCH_AS_HASH -ePROJECT -eDEPENDS -eCONFLICTS -w "/root/start-os${rel_pwd}" --rm -v "$(pwd):/root/start-os" start9/build-env $@
|
||||
docker run -d --rm --name os-compat --privileged --security-opt apparmor=unconfined -v "${project_pwd}:/root/start-os" -v /lib/modules:/lib/modules:ro start9/build-env
|
||||
while ! docker exec os-compat systemctl is-active --quiet multi-user.target 2> /dev/null; do sleep .5; done
|
||||
docker exec -eARCH -eENVIRONMENT -ePLATFORM -eGIT_BRANCH_AS_HASH -ePROJECT -eDEPENDS -eCONFLICTS $USE_TTY -w "/root/start-os${rel_pwd}" os-compat $@
|
||||
code=$?
|
||||
docker stop os-compat > /dev/null
|
||||
exit $code
|
||||
else
|
||||
exec $@
|
||||
fi
|
||||
fi
|
||||
87
build/raspberrypi/make-image.sh
Executable file
87
build/raspberrypi/make-image.sh
Executable file
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
function partition_for () {
|
||||
if [[ "$1" =~ [0-9]+$ ]]; then
|
||||
echo "$1p$2"
|
||||
else
|
||||
echo "$1$2"
|
||||
fi
|
||||
}
|
||||
|
||||
VERSION=$(cat VERSION.txt)
|
||||
ENVIRONMENT=$(cat ENVIRONMENT.txt)
|
||||
GIT_HASH=$(cat GIT_HASH.txt | head -c 7)
|
||||
DATE=$(date +%Y%m%d)
|
||||
|
||||
ROOT_PART_END=7217792
|
||||
|
||||
VERSION_FULL="$VERSION-$GIT_HASH"
|
||||
|
||||
if [ -n "$ENVIRONMENT" ]; then
|
||||
VERSION_FULL="$VERSION_FULL~$ENVIRONMENT"
|
||||
fi
|
||||
|
||||
TARGET_NAME=startos-${VERSION_FULL}-${DATE}_raspberrypi.img
|
||||
TARGET_SIZE=$[($ROOT_PART_END+1)*512]
|
||||
|
||||
rm -f $TARGET_NAME
|
||||
truncate -s $TARGET_SIZE $TARGET_NAME
|
||||
(
|
||||
echo o
|
||||
echo x
|
||||
echo i
|
||||
echo "0xcb15ae4d"
|
||||
echo r
|
||||
echo n
|
||||
echo p
|
||||
echo 1
|
||||
echo 2048
|
||||
echo 526335
|
||||
echo t
|
||||
echo c
|
||||
echo n
|
||||
echo p
|
||||
echo 2
|
||||
echo 526336
|
||||
echo $ROOT_PART_END
|
||||
echo a
|
||||
echo 1
|
||||
echo w
|
||||
) | fdisk $TARGET_NAME
|
||||
OUTPUT_DEVICE=$(sudo losetup --show -fP $TARGET_NAME)
|
||||
sudo mkfs.ext4 `partition_for ${OUTPUT_DEVICE} 2`
|
||||
sudo mkfs.vfat `partition_for ${OUTPUT_DEVICE} 1`
|
||||
|
||||
TMPDIR=$(mktemp -d)
|
||||
|
||||
sudo mount `partition_for ${OUTPUT_DEVICE} 2` $TMPDIR
|
||||
sudo mkdir $TMPDIR/boot
|
||||
sudo mount `partition_for ${OUTPUT_DEVICE} 1` $TMPDIR/boot
|
||||
sudo unsquashfs -f -d $TMPDIR startos.raspberrypi.squashfs
|
||||
REAL_GIT_HASH=$(cat $TMPDIR/usr/lib/startos/GIT_HASH.txt)
|
||||
REAL_VERSION=$(cat $TMPDIR/usr/lib/startos/VERSION.txt)
|
||||
REAL_ENVIRONMENT=$(cat $TMPDIR/usr/lib/startos/ENVIRONMENT.txt)
|
||||
sudo sed -i 's| boot=startos| init=/usr/lib/startos/scripts/init_resize\.sh|' $TMPDIR/boot/cmdline.txt
|
||||
sudo cp ./build/raspberrypi/fstab $TMPDIR/etc/
|
||||
sudo cp ./build/raspberrypi/init_resize.sh $TMPDIR/usr/lib/startos/scripts/init_resize.sh
|
||||
sudo umount $TMPDIR/boot
|
||||
sudo umount $TMPDIR
|
||||
sudo losetup -d $OUTPUT_DEVICE
|
||||
|
||||
if [ "$ALLOW_VERSION_MISMATCH" != 1 ]; then
|
||||
if [ "$(cat GIT_HASH.txt)" != "$REAL_GIT_HASH" ]; then
|
||||
>&2 echo "startos.raspberrypi.squashfs GIT_HASH.txt mismatch"
|
||||
>&2 echo "expected $REAL_GIT_HASH (dpkg) found $(cat GIT_HASH.txt) (repo)"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$(cat VERSION.txt)" != "$REAL_VERSION" ]; then
|
||||
>&2 echo "startos.raspberrypi.squashfs VERSION.txt mismatch"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$(cat ENVIRONMENT.txt)" != "$REAL_ENVIRONMENT" ]; then
|
||||
>&2 echo "startos.raspberrypi.squashfs ENVIRONMENT.txt mismatch"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
@@ -1,142 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -z "$VERSION" ]; then
|
||||
>&2 echo '$VERSION required'
|
||||
exit 2
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$SKIP_DL" != "1" ]; then
|
||||
if [ "$SKIP_CLEAN" != "1" ]; then
|
||||
rm -rf ~/Downloads/v$VERSION
|
||||
mkdir ~/Downloads/v$VERSION
|
||||
cd ~/Downloads/v$VERSION
|
||||
fi
|
||||
|
||||
if [ -n "$RUN_ID" ]; then
|
||||
for arch in aarch64 aarch64-nonfree riscv64 riscv64-nonfree x86_64 x86_64-nonfree raspberrypi; do
|
||||
while ! gh run download -R Start9Labs/start-os $RUN_ID -n $arch.squashfs -D $(pwd); do sleep 1; done
|
||||
done
|
||||
for arch in aarch64 aarch64-nonfree riscv64 riscv64-nonfree x86_64 x86_64-nonfree; do
|
||||
while ! gh run download -R Start9Labs/start-os $RUN_ID -n $arch.iso -D $(pwd); do sleep 1; done
|
||||
done
|
||||
while ! gh run download -R Start9Labs/start-os $RUN_ID -n raspberrypi.img -D $(pwd); do sleep 1; done
|
||||
fi
|
||||
|
||||
if [ -n "$ST_RUN_ID" ]; then
|
||||
for arch in aarch64 riscv64 x86_64; do
|
||||
while ! gh run download -R Start9Labs/start-os $ST_RUN_ID -n start-tunnel_$arch.deb -D $(pwd); do sleep 1; done
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -n "$CLI_RUN_ID" ]; then
|
||||
for arch in aarch64 riscv64 x86_64; do
|
||||
for os in linux macos; do
|
||||
pair=${arch}-${os}
|
||||
if [ "${pair}" = "riscv64-linux" ]; then
|
||||
target=riscv64gc-unknown-linux-musl
|
||||
elif [ "${pair}" = "riscv64-macos" ]; then
|
||||
continue
|
||||
elif [ "${os}" = "linux" ]; then
|
||||
target="${arch}-unknown-linux-musl"
|
||||
elif [ "${os}" = "macos" ]; then
|
||||
target="${arch}-apple-darwin"
|
||||
fi
|
||||
while ! gh run download -R Start9Labs/start-os $CLI_RUN_ID -n start-cli_$target -D $(pwd); do sleep 1; done
|
||||
mv start-cli "start-cli_${pair}"
|
||||
done
|
||||
done
|
||||
fi
|
||||
else
|
||||
cd ~/Downloads/v$VERSION
|
||||
fi
|
||||
|
||||
start-cli --registry=https://alpha-registry-x.start9.com registry os version add $VERSION "v$VERSION" '' ">=0.3.5 <=$VERSION"
|
||||
|
||||
if [ "$SKIP_UL" = "2" ]; then
|
||||
exit 2
|
||||
elif [ "$SKIP_UL" != "1" ]; then
|
||||
for file in *.squashfs *.iso *.deb start-cli_*; do
|
||||
gh release upload -R Start9Labs/start-os v$VERSION $file
|
||||
done
|
||||
for file in *.img; do
|
||||
if ! [ -f $file.gz ]; then
|
||||
cat $file | pigz > $file.gz
|
||||
fi
|
||||
gh release upload -R Start9Labs/start-os v$VERSION $file.gz
|
||||
done
|
||||
fi
|
||||
|
||||
if [ "$SKIP_INDEX" != "1" ]; then
|
||||
for arch in aarch64 aarch64-nonfree riscv64 riscv64-nonfree x86_64 x86_64-nonfree; do
|
||||
for file in *_$arch.squashfs *_$arch.iso; do
|
||||
start-cli --registry=https://alpha-registry-x.start9.com registry os asset add --platform=$arch --version=$VERSION $file https://github.com/Start9Labs/start-os/releases/download/v$VERSION/$(echo -n "$file" | sed 's/~/./g')
|
||||
done
|
||||
done
|
||||
for arch in raspberrypi; do
|
||||
for file in *_$arch.squashfs; do
|
||||
start-cli --registry=https://alpha-registry-x.start9.com registry os asset add --platform=$arch --version=$VERSION $file https://github.com/Start9Labs/start-os/releases/download/v$VERSION/$(echo -n "$file" | sed 's/~/./g')
|
||||
done
|
||||
done
|
||||
fi
|
||||
|
||||
for file in *.iso *.img *.img.gz *.squashfs *.deb start-cli_*; do
|
||||
gpg -u 7CFFDA41CA66056A --detach-sign --armor -o "${file}.asc" "$file"
|
||||
done
|
||||
|
||||
gpg --export -a 7CFFDA41CA66056A > dr-bonez.key.asc
|
||||
tar -czvf signatures.tar.gz *.asc
|
||||
|
||||
gh release upload -R Start9Labs/start-os v$VERSION signatures.tar.gz
|
||||
|
||||
cat << 'EOF'
|
||||
# StartOS Checksums
|
||||
|
||||
## SHA-256
|
||||
```
|
||||
EOF
|
||||
sha256sum *.iso *.img *img.gz *.squashfs
|
||||
cat << 'EOF'
|
||||
```
|
||||
|
||||
## BLAKE-3
|
||||
```
|
||||
EOF
|
||||
b3sum *.iso *.img *.img.gz *.squashfs
|
||||
cat << 'EOF'
|
||||
```
|
||||
|
||||
# Start-Tunnel Checksums
|
||||
|
||||
## SHA-256
|
||||
```
|
||||
EOF
|
||||
sha256sum start-tunnel*.deb
|
||||
cat << 'EOF'
|
||||
```
|
||||
|
||||
## BLAKE-3
|
||||
```
|
||||
EOF
|
||||
b3sum start-tunnel*.deb
|
||||
cat << 'EOF'
|
||||
```
|
||||
|
||||
# start-cli Checksums
|
||||
|
||||
## SHA-256
|
||||
```
|
||||
EOF
|
||||
sha256sum start-cli_*
|
||||
cat << 'EOF'
|
||||
```
|
||||
|
||||
## BLAKE-3
|
||||
```
|
||||
EOF
|
||||
b3sum start-cli_*
|
||||
cat << 'EOF'
|
||||
```
|
||||
EOF
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||
|
||||
if ! [ -f ./ENVIRONMENT.txt ] || [ "$(cat ./ENVIRONMENT.txt)" != "$ENVIRONMENT" ]; then
|
||||
>&2 echo "Updating ENVIRONMENT.txt to \"$ENVIRONMENT\""
|
||||
echo -n "$ENVIRONMENT" > ./ENVIRONMENT.txt
|
||||
fi
|
||||
|
||||
echo -n ./build/env/ENVIRONMENT.txt
|
||||
echo -n ./ENVIRONMENT.txt
|
||||
@@ -1,7 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||
|
||||
if [ "$GIT_BRANCH_AS_HASH" != 1 ]; then
|
||||
GIT_HASH="$(git rev-parse HEAD)$(if ! git diff-index --quiet HEAD --; then echo '-modified'; fi)"
|
||||
else
|
||||
@@ -13,4 +11,4 @@ if ! [ -f ./GIT_HASH.txt ] || [ "$(cat ./GIT_HASH.txt)" != "$GIT_HASH" ]; then
|
||||
echo -n "$GIT_HASH" > ./GIT_HASH.txt
|
||||
fi
|
||||
|
||||
echo -n ./build/env/GIT_HASH.txt
|
||||
echo -n ./GIT_HASH.txt
|
||||
@@ -1,10 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||
|
||||
if ! [ -f ./PLATFORM.txt ] || [ "$(cat ./PLATFORM.txt)" != "$PLATFORM" ] && [ -n "$PLATFORM" ]; then
|
||||
>&2 echo "Updating PLATFORM.txt to \"$PLATFORM\""
|
||||
echo -n "$PLATFORM" > ./PLATFORM.txt
|
||||
fi
|
||||
|
||||
echo -n ./build/env/PLATFORM.txt
|
||||
echo -n ./PLATFORM.txt
|
||||
@@ -1,8 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||
|
||||
FE_VERSION="$(cat ../../web/package.json | grep '"version"' | sed 's/[ \t]*"version":[ \t]*"\([^"]*\)",/\1/')"
|
||||
FE_VERSION="$(cat web/package.json | grep '"version"' | sed 's/[ \t]*"version":[ \t]*"\([^"]*\)",/\1/')"
|
||||
|
||||
# TODO: Validate other version sources - backend/Cargo.toml, backend/src/version/mod.rs
|
||||
|
||||
@@ -12,4 +10,4 @@ if ! [ -f ./VERSION.txt ] || [ "$(cat ./VERSION.txt)" != "$VERSION" ]; then
|
||||
echo -n "$VERSION" > ./VERSION.txt
|
||||
fi
|
||||
|
||||
echo -n ./build/env/VERSION.txt
|
||||
echo -n ./VERSION.txt
|
||||
@@ -4,8 +4,8 @@ cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||
|
||||
set -e
|
||||
|
||||
STATIC_DIR=dist/static/$1
|
||||
RAW_DIR=dist/raw/$1
|
||||
STATIC_DIR=web/dist/static/$1
|
||||
RAW_DIR=web/dist/raw/$1
|
||||
|
||||
mkdir -p $STATIC_DIR
|
||||
rm -rf $STATIC_DIR
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
set -e
|
||||
|
||||
mkdir -p /run/systemd/resolve
|
||||
echo "nameserver 8.8.8.8" > /run/systemd/resolve/stub-resolv.conf
|
||||
|
||||
apt-get update
|
||||
apt-get install -y curl rsync qemu-user-static nodejs
|
||||
|
||||
@@ -13,4 +16,7 @@ sed -i '/\(^\|#\)ForwardToSyslog=/c\ForwardToSyslog=no' /etc/systemd/journald.co
|
||||
|
||||
systemctl enable container-runtime.service
|
||||
|
||||
rm -rf /run/systemd
|
||||
|
||||
rm -f /etc/resolv.conf
|
||||
echo "nameserver 10.0.3.1" > /etc/resolv.conf
|
||||
28
container-runtime/mkcontainer.sh
Normal file
28
container-runtime/mkcontainer.sh
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
IMAGE=$1
|
||||
|
||||
if [ -z "$IMAGE" ]; then
|
||||
>&2 echo "usage: $0 <image id>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -d "/media/images/$IMAGE" ]; then
|
||||
>&2 echo "image does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
container=$(mktemp -d)
|
||||
mkdir -p $container/rootfs $container/upper $container/work
|
||||
mount -t overlay -olowerdir=/media/images/$IMAGE,upperdir=$container/upper,workdir=$container/work overlay $container/rootfs
|
||||
|
||||
rootfs=$container/rootfs
|
||||
|
||||
for special in dev sys proc run; do
|
||||
mkdir -p $rootfs/$special
|
||||
mount --bind /$special $rootfs/$special
|
||||
done
|
||||
|
||||
echo $rootfs
|
||||
2
container-runtime/package-lock.json
generated
2
container-runtime/package-lock.json
generated
@@ -38,7 +38,7 @@
|
||||
},
|
||||
"../sdk/dist": {
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.4.0-beta.47",
|
||||
"version": "0.4.0-beta.45",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@iarna/toml": "^3.0.0",
|
||||
|
||||
12
container-runtime/rmcontainer.sh
Normal file
12
container-runtime/rmcontainer.sh
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
rootfs=$1
|
||||
if [ -z "$rootfs" ]; then
|
||||
>&2 echo "usage: $0 <container rootfs path>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
umount --recursive $rootfs
|
||||
rm -rf $rootfs/..
|
||||
@@ -178,13 +178,6 @@ export function makeEffects(context: EffectContext): Effects {
|
||||
T.Effects["getInstalledPackages"]
|
||||
>
|
||||
},
|
||||
getServiceManifest(
|
||||
...[options]: Parameters<T.Effects["getServiceManifest"]>
|
||||
) {
|
||||
return rpcRound("get-service-manifest", options) as ReturnType<
|
||||
T.Effects["getServiceManifest"]
|
||||
>
|
||||
},
|
||||
subcontainer: {
|
||||
createFs(options: { imageId: string; name: string }) {
|
||||
return rpcRound("subcontainer.create-fs", options) as ReturnType<
|
||||
|
||||
@@ -10,6 +10,7 @@ import { SDKManifest } from "@start9labs/start-sdk/base/lib/types"
|
||||
import { SubContainerRc } from "@start9labs/start-sdk/package/lib/util/SubContainer"
|
||||
|
||||
const EMBASSY_HEALTH_INTERVAL = 15 * 1000
|
||||
const EMBASSY_PROPERTIES_LOOP = 30 * 1000
|
||||
/**
|
||||
* We wanted something to represent what the main loop is doing, and
|
||||
* in this case it used to run the properties, health, and the docker/ js main.
|
||||
|
||||
@@ -50,7 +50,6 @@ import {
|
||||
transformOldConfigToNew,
|
||||
} from "./transformConfigSpec"
|
||||
import { partialDiff } from "@start9labs/start-sdk/base/lib/util"
|
||||
import { Volume } from "@start9labs/start-sdk/package/lib/util/Volume"
|
||||
|
||||
type Optional<A> = A | undefined | null
|
||||
function todo(): never {
|
||||
@@ -62,14 +61,14 @@ export const EMBASSY_JS_LOCATION = "/usr/lib/startos/package/embassy.js"
|
||||
|
||||
const configFile = FileHelper.json(
|
||||
{
|
||||
base: new Volume("embassy"),
|
||||
volumeId: "embassy",
|
||||
subpath: "config.json",
|
||||
},
|
||||
matches.any,
|
||||
)
|
||||
const dependsOnFile = FileHelper.json(
|
||||
{
|
||||
base: new Volume("embassy"),
|
||||
volumeId: "embassy",
|
||||
subpath: "dependsOn.json",
|
||||
},
|
||||
dictionary([string, array(string)]),
|
||||
@@ -288,6 +287,7 @@ function convertProperties(
|
||||
}
|
||||
}
|
||||
|
||||
const DEFAULT_REGISTRY = "https://registry.start9.com"
|
||||
export class SystemForEmbassy implements System {
|
||||
private version: ExtendedVersion
|
||||
currentRunning: MainLoop | undefined
|
||||
@@ -331,10 +331,6 @@ export class SystemForEmbassy implements System {
|
||||
) {
|
||||
this.version.upstream.prerelease = ["alpha"]
|
||||
}
|
||||
|
||||
if (this.manifest.id === "nostr") {
|
||||
this.manifest.id = "nostr-rs-relay"
|
||||
}
|
||||
}
|
||||
|
||||
async init(
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")/.."
|
||||
|
||||
USE_TTY=
|
||||
if tty -s; then
|
||||
USE_TTY="-it"
|
||||
fi
|
||||
|
||||
DOCKER_PLATFORM=linux/${ARCH}
|
||||
case $ARCH in
|
||||
x86_64)
|
||||
DOCKER_PLATFORM=linux/amd64;;
|
||||
aarch64)
|
||||
DOCKER_PLATFORM=linux/arm64;;
|
||||
esac
|
||||
|
||||
docker run --rm $USE_TTY --platform=$DOCKER_PLATFORM -eARCH --privileged -v "$(pwd):/root/start-os" start9/build-env /root/start-os/container-runtime/update-image.sh
|
||||
if [ "$(ls -nd "rootfs.${ARCH}.squashfs" | awk '{ print $3 }')" != "$UID" ]; then
|
||||
docker run --rm $USE_TTY -v "$(pwd):/root/start-os" start9/build-env chown -R $UID:$UID /root/start-os/container-runtime
|
||||
fi
|
||||
@@ -9,34 +9,56 @@ if [ "$ARCH" = "riscv64" ]; then
|
||||
RUST_ARCH="riscv64gc"
|
||||
fi
|
||||
|
||||
mount -t tmpfs tmpfs /tmp
|
||||
mkdir -p /tmp/lower /tmp/upper /tmp/work /tmp/combined
|
||||
mount -o loop debian.${ARCH}.squashfs /tmp/lower
|
||||
mount -t overlay -olowerdir=/tmp/lower,upperdir=/tmp/upper,workdir=/tmp/work overlay /tmp/combined
|
||||
if mountpoint -q tmp/combined; then sudo umount -l tmp/combined; fi
|
||||
if mountpoint -q tmp/lower; then sudo umount tmp/lower; fi
|
||||
sudo rm -rf tmp
|
||||
mkdir -p tmp/lower tmp/upper tmp/work tmp/combined
|
||||
if which squashfuse > /dev/null; then
|
||||
sudo squashfuse debian.${ARCH}.squashfs tmp/lower
|
||||
else
|
||||
sudo mount debian.${ARCH}.squashfs tmp/lower
|
||||
fi
|
||||
if which fuse-overlayfs > /dev/null; then
|
||||
sudo fuse-overlayfs -olowerdir=tmp/lower,upperdir=tmp/upper,workdir=tmp/work overlay tmp/combined
|
||||
else
|
||||
sudo mount -t overlay -olowerdir=tmp/lower,upperdir=tmp/upper,workdir=tmp/work overlay tmp/combined
|
||||
fi
|
||||
|
||||
mkdir -p /tmp/combined/usr/lib/startos/
|
||||
rsync -a --copy-unsafe-links --info=progress2 dist/ /tmp/combined/usr/lib/startos/init/
|
||||
chown -R 0:0 /tmp/combined/usr/lib/startos/
|
||||
cp container-runtime.service /tmp/combined/lib/systemd/system/container-runtime.service
|
||||
chown 0:0 /tmp/combined/lib/systemd/system/container-runtime.service
|
||||
cp container-runtime-failure.service /tmp/combined/lib/systemd/system/container-runtime-failure.service
|
||||
chown 0:0 /tmp/combined/lib/systemd/system/container-runtime-failure.service
|
||||
cp ../core/target/${RUST_ARCH}-unknown-linux-musl/release/start-container /tmp/combined/usr/bin/start-container
|
||||
echo -e '#!/bin/bash\nexec start-container "$@"' > /tmp/combined/usr/bin/start-cli # TODO: remove
|
||||
chmod +x /tmp/combined/usr/bin/start-cli
|
||||
chown 0:0 /tmp/combined/usr/bin/start-container
|
||||
echo container-runtime | sha256sum | head -c 32 | cat - <(echo) > /tmp/combined/etc/machine-id
|
||||
rm -f /tmp/combined/etc/resolv.conf
|
||||
cp /etc/resolv.conf /tmp/combined/etc/resolv.conf
|
||||
for fs in proc sys dev; do
|
||||
mount --bind /$fs /tmp/combined/$fs
|
||||
done
|
||||
cat deb-install.sh | chroot /tmp/combined /bin/bash
|
||||
for fs in proc sys dev; do
|
||||
umount /tmp/combined/$fs
|
||||
done
|
||||
truncate -s 0 /tmp/combined/etc/machine-id
|
||||
QEMU=
|
||||
if [ "$ARCH" != "$(uname -m)" ]; then
|
||||
QEMU=/usr/bin/qemu-${ARCH}
|
||||
if ! which qemu-$ARCH > /dev/null; then
|
||||
>&2 echo qemu-user is required for cross-platform builds
|
||||
sudo umount tmp/combined
|
||||
sudo umount tmp/lower
|
||||
sudo rm -rf tmp
|
||||
exit 1
|
||||
fi
|
||||
sudo cp $(which qemu-$ARCH) tmp/combined${QEMU}
|
||||
fi
|
||||
|
||||
sudo mkdir -p tmp/combined/usr/lib/startos/
|
||||
sudo rsync -a --copy-unsafe-links dist/ tmp/combined/usr/lib/startos/init/
|
||||
sudo chown -R 0:0 tmp/combined/usr/lib/startos/
|
||||
sudo cp container-runtime.service tmp/combined/lib/systemd/system/container-runtime.service
|
||||
sudo chown 0:0 tmp/combined/lib/systemd/system/container-runtime.service
|
||||
sudo cp container-runtime-failure.service tmp/combined/lib/systemd/system/container-runtime-failure.service
|
||||
sudo chown 0:0 tmp/combined/lib/systemd/system/container-runtime-failure.service
|
||||
sudo cp ../core/target/${RUST_ARCH}-unknown-linux-musl/release/start-container tmp/combined/usr/bin/start-container
|
||||
echo -e '#!/bin/bash\nexec start-container "$@"' | sudo tee tmp/combined/usr/bin/start-cli # TODO: remove
|
||||
sudo chmod +x tmp/combined/usr/bin/start-cli
|
||||
sudo chown 0:0 tmp/combined/usr/bin/start-container
|
||||
echo container-runtime | sha256sum | head -c 32 | cat - <(echo) | sudo tee tmp/combined/etc/machine-id
|
||||
cat deb-install.sh | sudo systemd-nspawn --console=pipe -D tmp/combined $QEMU /bin/bash
|
||||
sudo truncate -s 0 tmp/combined/etc/machine-id
|
||||
|
||||
if [ -n "$QEMU" ]; then
|
||||
sudo rm tmp/combined${QEMU}
|
||||
fi
|
||||
|
||||
rm -f rootfs.${ARCH}.squashfs
|
||||
mkdir -p ../build/lib/container-runtime
|
||||
mksquashfs /tmp/combined rootfs.${ARCH}.squashfs
|
||||
sudo mksquashfs tmp/combined rootfs.${ARCH}.squashfs
|
||||
sudo umount tmp/combined
|
||||
sudo umount tmp/lower
|
||||
sudo rm -rf tmp
|
||||
2
core/.gitignore
vendored
2
core/.gitignore
vendored
@@ -8,4 +8,4 @@ secrets.db
|
||||
.env
|
||||
.editorconfig
|
||||
proptest-regressions/**/*
|
||||
/bindings/*
|
||||
/startos/bindings/*
|
||||
822
core/Cargo.lock
generated
822
core/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
291
core/Cargo.toml
291
core/Cargo.toml
@@ -1,290 +1,3 @@
|
||||
[package]
|
||||
authors = ["Aiden McClelland <me@drbonez.dev>"]
|
||||
description = "The core of StartOS"
|
||||
documentation = "https://docs.rs/start-os"
|
||||
edition = "2024"
|
||||
keywords = [
|
||||
"bitcoin",
|
||||
"full-node",
|
||||
"lightning",
|
||||
"privacy",
|
||||
"raspberry-pi",
|
||||
"self-hosted",
|
||||
]
|
||||
license = "MIT"
|
||||
name = "start-os"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/Start9Labs/start-os"
|
||||
version = "0.4.0-alpha.17" # VERSION_BUMP
|
||||
[workspace]
|
||||
|
||||
[lib]
|
||||
name = "startos"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "startbox"
|
||||
path = "src/main/startbox.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "start-cli"
|
||||
path = "src/main/start-cli.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "start-container"
|
||||
path = "src/main/start-container.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "registrybox"
|
||||
path = "src/main/registrybox.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "tunnelbox"
|
||||
path = "src/main/tunnelbox.rs"
|
||||
|
||||
[features]
|
||||
arti = [
|
||||
"arti-client",
|
||||
"safelog",
|
||||
"tor-cell",
|
||||
"tor-hscrypto",
|
||||
"tor-hsservice",
|
||||
"tor-keymgr",
|
||||
"tor-llcrypto",
|
||||
"tor-proto",
|
||||
"tor-rtcompat",
|
||||
]
|
||||
beta = []
|
||||
console = ["console-subscriber", "tokio/tracing"]
|
||||
default = []
|
||||
dev = []
|
||||
test = []
|
||||
unstable = ["backtrace-on-stack-overflow"]
|
||||
|
||||
[dependencies]
|
||||
aes = { version = "0.7.5", features = ["ctr"] }
|
||||
arti-client = { version = "0.33", features = [
|
||||
"compression",
|
||||
"ephemeral-keystore",
|
||||
"experimental-api",
|
||||
"onion-service-client",
|
||||
"onion-service-service",
|
||||
"rustls",
|
||||
"static",
|
||||
"tokio",
|
||||
], default-features = false, git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true }
|
||||
async-acme = { version = "0.6.0", git = "https://github.com/dr-bonez/async-acme.git", features = [
|
||||
"use_rustls",
|
||||
"use_tokio",
|
||||
] }
|
||||
async-compression = { version = "0.4.32", features = [
|
||||
"brotli",
|
||||
"gzip",
|
||||
"tokio",
|
||||
"zstd",
|
||||
] }
|
||||
async-stream = "0.3.5"
|
||||
async-trait = "0.1.74"
|
||||
axum = { version = "0.8.4", features = ["ws", "http2"] }
|
||||
backtrace-on-stack-overflow = { version = "0.3.0", optional = true }
|
||||
base32 = "0.5.0"
|
||||
base64 = "0.22.1"
|
||||
base64ct = "1.6.0"
|
||||
basic-cookies = "0.1.4"
|
||||
blake3 = { version = "1.5.0", features = ["mmap", "rayon"] }
|
||||
bytes = "1"
|
||||
chrono = { version = "0.4.31", features = ["serde"] }
|
||||
clap = { version = "4.4.12", features = ["string"] }
|
||||
color-eyre = "0.6.2"
|
||||
console = "0.16.2"
|
||||
console-subscriber = { version = "0.5.0", optional = true }
|
||||
const_format = "0.2.34"
|
||||
cookie = "0.18.0"
|
||||
cookie_store = "0.22.0"
|
||||
curve25519-dalek = "4.1.3"
|
||||
der = { version = "0.7.9", features = ["derive", "pem"] }
|
||||
digest = "0.10.7"
|
||||
divrem = "1.0.0"
|
||||
dns-lookup = "3.0.1"
|
||||
ed25519 = { version = "2.2.3", features = ["alloc", "pem", "pkcs8"] }
|
||||
ed25519-dalek = { version = "2.2.0", features = [
|
||||
"digest",
|
||||
"hazmat",
|
||||
"pkcs8",
|
||||
"rand_core",
|
||||
"serde",
|
||||
"zeroize",
|
||||
] }
|
||||
ed25519-dalek-v1 = { package = "ed25519-dalek", version = "1" }
|
||||
exver = { version = "0.2.0", git = "https://github.com/Start9Labs/exver-rs.git", features = [
|
||||
"serde",
|
||||
] }
|
||||
fd-lock-rs = "0.1.4"
|
||||
form_urlencoded = "1.2.1"
|
||||
futures = "0.3.28"
|
||||
gpt = "4.1.0"
|
||||
hex = "0.4.3"
|
||||
hickory-server = { version = "0.25.2", features = ["resolver"] }
|
||||
hmac = "0.12.1"
|
||||
http = "1.0.0"
|
||||
http-body-util = "0.1"
|
||||
hyper = { version = "1.5", features = ["http1", "http2", "server"] }
|
||||
hyper-util = { version = "0.1.10", features = [
|
||||
"http1",
|
||||
"http2",
|
||||
"server",
|
||||
"server-auto",
|
||||
"server-graceful",
|
||||
"service",
|
||||
"tokio",
|
||||
] }
|
||||
id-pool = { version = "0.2.2", default-features = false, features = [
|
||||
"serde",
|
||||
"u16",
|
||||
] }
|
||||
iddqd = "0.3.14"
|
||||
imbl = { version = "6", features = ["serde", "small-chunks"] }
|
||||
imbl-value = { version = "0.4.3", features = ["ts-rs"] }
|
||||
include_dir = { version = "0.7.3", features = ["metadata"] }
|
||||
indexmap = { version = "2.0.2", features = ["serde"] }
|
||||
indicatif = { version = "0.18.3", features = ["tokio"] }
|
||||
inotify = "0.11.0"
|
||||
integer-encoding = { version = "4.0.0", features = ["tokio_async"] }
|
||||
ipnet = { version = "2.8.0", features = ["serde"] }
|
||||
isocountry = "0.3.2"
|
||||
itertools = "0.14.0"
|
||||
jaq-core = "0.10.1"
|
||||
jaq-std = "0.10.0"
|
||||
josekit = "0.10.3"
|
||||
jsonpath_lib = { git = "https://github.com/Start9Labs/jsonpath.git" }
|
||||
lazy_async_pool = "0.3.3"
|
||||
lazy_format = "2.0"
|
||||
lazy_static = "1.4.0"
|
||||
lettre = { version = "0.11.18", default-features = false, features = [
|
||||
"aws-lc-rs",
|
||||
"builder",
|
||||
"hostname",
|
||||
"pool",
|
||||
"rustls-platform-verifier",
|
||||
"smtp-transport",
|
||||
"tokio1-rustls",
|
||||
] }
|
||||
libc = "0.2.149"
|
||||
log = "0.4.20"
|
||||
mbrman = "0.6.0"
|
||||
miette = { version = "7.6.0", features = ["fancy"] }
|
||||
mio = "1"
|
||||
new_mime_guess = "4"
|
||||
nix = { version = "0.30.1", features = [
|
||||
"fs",
|
||||
"mount",
|
||||
"net",
|
||||
"process",
|
||||
"sched",
|
||||
"signal",
|
||||
"user",
|
||||
] }
|
||||
nom = "8.0.0"
|
||||
num = "0.4.1"
|
||||
num_cpus = "1.16.0"
|
||||
num_enum = "0.7.0"
|
||||
once_cell = "1.19.0"
|
||||
openssh-keys = "0.6.2"
|
||||
openssl = { version = "0.10.57", features = ["vendored"] }
|
||||
p256 = { version = "0.13.2", features = ["pem"] }
|
||||
patch-db = { version = "*", path = "../patch-db/patch-db", features = [
|
||||
"trace",
|
||||
] }
|
||||
pbkdf2 = "0.12.2"
|
||||
pin-project = "1.1.3"
|
||||
pkcs8 = { version = "0.10.2", features = ["std"] }
|
||||
prettytable-rs = "0.10.0"
|
||||
proptest = "1.3.1"
|
||||
proptest-derive = "0.7.0"
|
||||
qrcode = "0.14.1"
|
||||
r3bl_tui = "0.7.6"
|
||||
rand = "0.9.2"
|
||||
regex = "1.10.2"
|
||||
reqwest = { version = "0.12.25", features = [
|
||||
"json",
|
||||
"socks",
|
||||
"stream",
|
||||
"http2",
|
||||
] }
|
||||
reqwest_cookie_store = "0.9.0"
|
||||
rpassword = "7.2.0"
|
||||
rust-argon2 = "3.0.0"
|
||||
rpc-toolkit = { git = "https://github.com/Start9Labs/rpc-toolkit.git" }
|
||||
safelog = { version = "0.4.8", git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true }
|
||||
semver = { version = "1.0.20", features = ["serde"] }
|
||||
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||
serde_cbor = { package = "ciborium", version = "0.2.1" }
|
||||
serde_json = "1.0"
|
||||
serde_toml = { package = "toml", version = "0.9.9+spec-1.0.0" }
|
||||
serde_yaml = { package = "serde_yml", version = "0.0.12" }
|
||||
sha-crypt = "0.5.0"
|
||||
sha2 = "0.10.2"
|
||||
signal-hook = "0.3.17"
|
||||
socket2 = { version = "0.6.0", features = ["all"] }
|
||||
socks5-impl = { version = "0.7.2", features = ["client", "server"] }
|
||||
sqlx = { version = "0.8.6", features = [
|
||||
"postgres",
|
||||
"runtime-tokio-rustls",
|
||||
], default-features = false }
|
||||
sscanf = "0.4.1"
|
||||
ssh-key = { version = "0.6.2", features = ["ed25519"] }
|
||||
tar = "0.4.40"
|
||||
termion = "4.0.5"
|
||||
textwrap = "0.16.1"
|
||||
thiserror = "2.0.12"
|
||||
tokio = { version = "1.38.1", features = ["full"] }
|
||||
tokio-rustls = "0.26.4"
|
||||
tokio-stream = { version = "0.1.14", features = ["io-util", "net", "sync"] }
|
||||
tokio-tar = { git = "https://github.com/dr-bonez/tokio-tar.git" }
|
||||
tokio-tungstenite = { version = "0.26.2", features = ["native-tls", "url"] }
|
||||
tokio-util = { version = "0.7.9", features = ["io"] }
|
||||
tor-cell = { version = "0.33", git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true }
|
||||
tor-hscrypto = { version = "0.33", features = [
|
||||
"full",
|
||||
], git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true }
|
||||
tor-hsservice = { version = "0.33", git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true }
|
||||
tor-keymgr = { version = "0.33", features = [
|
||||
"ephemeral-keystore",
|
||||
], git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true }
|
||||
tor-llcrypto = { version = "0.33", features = [
|
||||
"full",
|
||||
], git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true }
|
||||
tor-proto = { version = "0.33", git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true }
|
||||
tor-rtcompat = { version = "0.33", features = [
|
||||
"rustls",
|
||||
"tokio",
|
||||
], git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true }
|
||||
torut = "0.2.1"
|
||||
tower-service = "0.3.3"
|
||||
tracing = "0.1.39"
|
||||
tracing-error = "0.2.0"
|
||||
tracing-journald = "0.3.0"
|
||||
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
|
||||
ts-rs = "9.0.1"
|
||||
typed-builder = "0.23.2"
|
||||
url = { version = "2.4.1", features = ["serde"] }
|
||||
uuid = { version = "1.4.1", features = ["v4"] }
|
||||
visit-rs = "0.1.1"
|
||||
x25519-dalek = { version = "2.0.1", features = ["static_secrets"] }
|
||||
zbus = "5.1.1"
|
||||
hashing-serializer = "0.1.1"
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
procfs = "0.18.0"
|
||||
pty-process = "0.5.1"
|
||||
|
||||
[profile.test]
|
||||
opt-level = 3
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 3
|
||||
|
||||
[profile.dev.package.backtrace]
|
||||
opt-level = 3
|
||||
|
||||
[profile.dev.package.sqlx-macros]
|
||||
opt-level = 3
|
||||
members = ["startos"]
|
||||
|
||||
@@ -60,7 +60,7 @@ if [ -z "${TARGET:-}" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
cd ../..
|
||||
cd ..
|
||||
FEATURES="$(echo "${ENVIRONMENT:-}" | sed 's/-/,/g')"
|
||||
RUSTFLAGS=""
|
||||
if [[ "${ENVIRONMENT:-}" =~ (^|-)console($|-) ]]; then
|
||||
@@ -30,7 +30,7 @@ if [ "$ARCH" = "riscv64" ]; then
|
||||
RUST_ARCH="riscv64gc"
|
||||
fi
|
||||
|
||||
cd ../..
|
||||
cd ..
|
||||
FEATURES="$(echo $ENVIRONMENT | sed 's/-/,/g')"
|
||||
RUSTFLAGS=""
|
||||
|
||||
@@ -30,7 +30,7 @@ if [ "$ARCH" = "riscv64" ]; then
|
||||
RUST_ARCH="riscv64gc"
|
||||
fi
|
||||
|
||||
cd ../..
|
||||
cd ..
|
||||
FEATURES="$(echo $ENVIRONMENT | sed 's/-/,/g')"
|
||||
RUSTFLAGS=""
|
||||
|
||||
@@ -30,7 +30,7 @@ if [ "$ARCH" = "riscv64" ]; then
|
||||
RUST_ARCH="riscv64gc"
|
||||
fi
|
||||
|
||||
cd ../..
|
||||
cd ..
|
||||
FEATURES="$(echo $ENVIRONMENT | sed 's/-/,/g')"
|
||||
RUSTFLAGS=""
|
||||
|
||||
@@ -30,7 +30,7 @@ if [ "$ARCH" = "riscv64" ]; then
|
||||
RUST_ARCH="riscv64gc"
|
||||
fi
|
||||
|
||||
cd ../..
|
||||
cd ..
|
||||
FEATURES="$(echo $ENVIRONMENT | sed 's/-/,/g')"
|
||||
RUSTFLAGS=""
|
||||
if [[ "${ENVIRONMENT}" =~ (^|-)console($|-) ]]; then
|
||||
@@ -39,6 +39,6 @@ fi
|
||||
echo "FEATURES=\"$FEATURES\""
|
||||
echo "RUSTFLAGS=\"$RUSTFLAGS\""
|
||||
rust-zig-builder cargo test --manifest-path=./core/Cargo.toml $BUILD_FLAGS --features test,$FEATURES --locked 'export_bindings_'
|
||||
if [ "$(ls -nd "core/bindings" | awk '{ print $3 }')" != "$UID" ]; then
|
||||
rust-zig-builder sh -c "chown -R $UID:$UID core/target && chown -R $UID:$UID core/bindings && chown -R $UID:$UID /usr/local/cargo"
|
||||
if [ "$(ls -nd "core/startos/bindings" | awk '{ print $3 }')" != "$UID" ]; then
|
||||
rust-zig-builder sh -c "chown -R $UID:$UID core/target && chown -R $UID:$UID core/startos/bindings && chown -R $UID:$UID /usr/local/cargo"
|
||||
fi
|
||||
@@ -30,7 +30,7 @@ if [ "$ARCH" = "riscv64" ]; then
|
||||
RUST_ARCH="riscv64gc"
|
||||
fi
|
||||
|
||||
cd ../..
|
||||
cd ..
|
||||
FEATURES="$(echo $ENVIRONMENT | sed 's/-/,/g')"
|
||||
RUSTFLAGS=""
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||
|
||||
source ./build/builder-alias.sh
|
||||
source ./builder-alias.sh
|
||||
|
||||
set -ea
|
||||
shopt -s expand_aliases
|
||||
|
||||
@@ -1,294 +0,0 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::ops::Deref;
|
||||
|
||||
use axum::extract::Request;
|
||||
use axum::response::Response;
|
||||
use exver::{Version, VersionRange};
|
||||
use http::HeaderValue;
|
||||
use imbl_value::InternedString;
|
||||
use patch_db::ModelExt;
|
||||
use rpc_toolkit::yajrc::RpcMethod;
|
||||
use rpc_toolkit::{Middleware, RpcRequest, RpcResponse};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
use url::Url;
|
||||
|
||||
use crate::context::RpcContext;
|
||||
use crate::prelude::*;
|
||||
use crate::registry::context::RegistryContext;
|
||||
use crate::registry::os::index::OsVersionInfoMap;
|
||||
use crate::registry::package::get::{
|
||||
GetPackageParams, GetPackageResponse, GetPackageResponseFull, PackageDetailLevel,
|
||||
};
|
||||
use crate::registry::package::index::PackageVersionInfo;
|
||||
use crate::util::VersionString;
|
||||
use crate::util::lshw::LshwDevice;
|
||||
use crate::version::VersionT;
|
||||
|
||||
pub const DEVICE_INFO_HEADER: &str = "X-StartOS-Device-Info";
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DeviceInfo {
|
||||
pub os: OsInfo,
|
||||
pub hardware: Option<HardwareInfo>,
|
||||
}
|
||||
impl DeviceInfo {
|
||||
pub async fn load(ctx: &RpcContext) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
os: OsInfo::from(ctx),
|
||||
hardware: Some(HardwareInfo::load(ctx).await?),
|
||||
})
|
||||
}
|
||||
}
|
||||
impl DeviceInfo {
|
||||
pub fn to_header_value(&self) -> HeaderValue {
|
||||
let mut url: Url = "http://localhost".parse().unwrap();
|
||||
url.query_pairs_mut()
|
||||
.append_pair("os.version", &self.os.version.to_string())
|
||||
.append_pair("os.compat", &self.os.compat.to_string())
|
||||
.append_pair("os.platform", &*self.os.platform);
|
||||
|
||||
HeaderValue::from_str(url.query().unwrap_or_default()).unwrap()
|
||||
}
|
||||
pub fn from_header_value(header: &HeaderValue) -> Result<Self, Error> {
|
||||
let query: BTreeMap<_, _> = form_urlencoded::parse(header.as_bytes()).collect();
|
||||
let has_hw_info = query.keys().any(|k| k.starts_with("hardware."));
|
||||
Ok(Self {
|
||||
os: OsInfo {
|
||||
version: query
|
||||
.get("os.version")
|
||||
.or_not_found("os.version")?
|
||||
.parse()?,
|
||||
compat: query.get("os.compat").or_not_found("os.compat")?.parse()?,
|
||||
platform: query
|
||||
.get("os.platform")
|
||||
.or_not_found("os.platform")?
|
||||
.deref()
|
||||
.into(),
|
||||
},
|
||||
hardware: has_hw_info
|
||||
.then(|| {
|
||||
Ok::<_, Error>(HardwareInfo {
|
||||
arch: query
|
||||
.get("hardware.arch")
|
||||
.or_not_found("hardware.arch")?
|
||||
.parse()?,
|
||||
ram: query
|
||||
.get("hardware.ram")
|
||||
.or_not_found("hardware.ram")?
|
||||
.parse()?,
|
||||
devices: None,
|
||||
})
|
||||
})
|
||||
.transpose()?,
|
||||
})
|
||||
}
|
||||
pub fn filter_for_hardware(
|
||||
&self,
|
||||
method: &str,
|
||||
params: Value,
|
||||
res: &mut Value,
|
||||
) -> Result<(), Error> {
|
||||
match method {
|
||||
"package.get" => {
|
||||
let params: Model<GetPackageParams> = ModelExt::from_value(params);
|
||||
|
||||
let other = params.as_other_versions().de()?;
|
||||
if params.as_id().transpose_ref().is_some() {
|
||||
if other.unwrap_or_default() == PackageDetailLevel::Full {
|
||||
self.filter_package_get_full(ModelExt::value_as_mut(res))?;
|
||||
} else {
|
||||
self.filter_package_get(ModelExt::value_as_mut(res))?;
|
||||
}
|
||||
} else {
|
||||
for (_, v) in res.as_object_mut().into_iter().flat_map(|o| o.iter_mut()) {
|
||||
if other.unwrap_or_default() == PackageDetailLevel::Full {
|
||||
self.filter_package_get_full(ModelExt::value_as_mut(v))?;
|
||||
} else {
|
||||
self.filter_package_get(ModelExt::value_as_mut(v))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
"os.version.get" => self.filter_os_version(ModelExt::value_as_mut(res)),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_package_versions(
|
||||
&self,
|
||||
versions: &mut Model<BTreeMap<VersionString, PackageVersionInfo>>,
|
||||
) -> Result<(), Error> {
|
||||
let alpha_17: Version = "0.4.0-alpha.17".parse()?;
|
||||
|
||||
// Filter package versions using for_device
|
||||
versions.retain(|_, info| info.for_device(self))?;
|
||||
|
||||
// Alpha.17 compatibility: add legacy fields
|
||||
if self.os.version <= alpha_17 {
|
||||
for (_, info) in versions.as_entries_mut()? {
|
||||
let v = info.as_value_mut();
|
||||
if let Some(mut tup) = v["s9pks"].get(0).cloned() {
|
||||
v["s9pk"] = tup[1].take();
|
||||
v["hardwareRequirements"] = tup[0].take();
|
||||
v["s9pk"]["url"] = v["s9pk"]["urls"][0].clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn filter_package_get(&self, res: &mut Model<GetPackageResponse>) -> Result<(), Error> {
|
||||
self.filter_package_versions(res.as_best_mut())
|
||||
}
|
||||
|
||||
fn filter_package_get_full(
|
||||
&self,
|
||||
res: &mut Model<GetPackageResponseFull>,
|
||||
) -> Result<(), Error> {
|
||||
self.filter_package_versions(res.as_best_mut())?;
|
||||
self.filter_package_versions(res.as_other_versions_mut())
|
||||
}
|
||||
|
||||
fn filter_os_version(&self, res: &mut Model<OsVersionInfoMap>) -> Result<(), Error> {
|
||||
let alpha_17: Version = "0.4.0-alpha.17".parse()?;
|
||||
|
||||
// Filter OS versions based on source_version compatibility
|
||||
res.retain(|_, info| {
|
||||
let source_version = info.as_source_version().de()?;
|
||||
Ok(self.os.version.satisfies(&source_version))
|
||||
})?;
|
||||
|
||||
// Alpha.17 compatibility: add url field from urls array
|
||||
if self.os.version <= alpha_17 {
|
||||
for (_, info) in res.as_entries_mut()? {
|
||||
let v = info.as_value_mut();
|
||||
for asset_ty in ["iso", "squashfs", "img"] {
|
||||
for (_, asset) in v[asset_ty]
|
||||
.as_object_mut()
|
||||
.into_iter()
|
||||
.flat_map(|o| o.iter_mut())
|
||||
{
|
||||
asset["url"] = asset["urls"][0].clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct OsInfo {
|
||||
#[ts(as = "VersionString")]
|
||||
pub version: Version,
|
||||
#[ts(type = "string")]
|
||||
pub compat: VersionRange,
|
||||
#[ts(type = "string")]
|
||||
pub platform: InternedString,
|
||||
}
|
||||
impl From<&RpcContext> for OsInfo {
|
||||
fn from(_: &RpcContext) -> Self {
|
||||
Self {
|
||||
version: crate::version::Current::default().semver(),
|
||||
compat: crate::version::Current::default().compat().clone(),
|
||||
platform: InternedString::intern(&*crate::PLATFORM),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct HardwareInfo {
|
||||
#[ts(type = "string")]
|
||||
pub arch: InternedString,
|
||||
#[ts(type = "number")]
|
||||
pub ram: u64,
|
||||
pub devices: Option<Vec<LshwDevice>>,
|
||||
}
|
||||
impl HardwareInfo {
|
||||
pub async fn load(ctx: &RpcContext) -> Result<Self, Error> {
|
||||
let s = ctx.db.peek().await.into_public().into_server_info();
|
||||
Ok(Self {
|
||||
arch: s.as_arch().de()?,
|
||||
ram: s.as_ram().de()?,
|
||||
devices: Some(s.as_devices().de()?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Metadata {
|
||||
#[serde(default)]
|
||||
get_device_info: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DeviceInfoMiddleware {
|
||||
device_info_header: Option<HeaderValue>,
|
||||
device_info: Option<DeviceInfo>,
|
||||
req: Option<RpcRequest>,
|
||||
}
|
||||
impl DeviceInfoMiddleware {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
device_info_header: None,
|
||||
device_info: None,
|
||||
req: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Middleware<RegistryContext> for DeviceInfoMiddleware {
|
||||
type Metadata = Metadata;
|
||||
async fn process_http_request(
|
||||
&mut self,
|
||||
_: &RegistryContext,
|
||||
request: &mut Request,
|
||||
) -> Result<(), Response> {
|
||||
self.device_info_header = request.headers_mut().remove(DEVICE_INFO_HEADER);
|
||||
Ok(())
|
||||
}
|
||||
async fn process_rpc_request(
|
||||
&mut self,
|
||||
_: &RegistryContext,
|
||||
metadata: Self::Metadata,
|
||||
request: &mut RpcRequest,
|
||||
) -> Result<(), RpcResponse> {
|
||||
async move {
|
||||
if metadata.get_device_info {
|
||||
if let Some(device_info) = &self.device_info_header {
|
||||
let device_info = DeviceInfo::from_header_value(device_info)?;
|
||||
request.params["__DeviceInfo_device_info"] = to_value(&device_info)?;
|
||||
self.device_info = Some(device_info);
|
||||
self.req = Some(request.clone());
|
||||
}
|
||||
}
|
||||
|
||||
Ok::<_, Error>(())
|
||||
}
|
||||
.await
|
||||
.map_err(|e| RpcResponse::from_result(Err(e)))
|
||||
}
|
||||
async fn process_rpc_response(
|
||||
&mut self,
|
||||
_: &RegistryContext,
|
||||
response: &mut RpcResponse,
|
||||
) -> () {
|
||||
if let (Some(req), Some(device_info), Ok(res)) =
|
||||
(&self.req, &self.device_info, &mut response.result)
|
||||
{
|
||||
if let Err(e) =
|
||||
device_info.filter_for_hardware(req.method.as_str(), req.params.clone(), res)
|
||||
{
|
||||
response.result = Err(e).map_err(From::from);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
use imbl::vector;
|
||||
|
||||
use super::RegistryMigration;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub struct RegistryAssetArray;
|
||||
impl RegistryMigration for RegistryAssetArray {
|
||||
fn action(&self, db: &mut Value) -> Result<(), Error> {
|
||||
for (_, info) in db["index"]["package"]["packages"]
|
||||
.as_object_mut()
|
||||
.unwrap()
|
||||
.iter_mut()
|
||||
{
|
||||
for (_, info) in info["versions"].as_object_mut().unwrap().iter_mut() {
|
||||
let hw_req = info["hardwareRequirements"].take();
|
||||
let mut s9pk = info["s9pk"].take();
|
||||
s9pk["urls"] = Value::Array(vector![s9pk["url"].take()]);
|
||||
info["s9pks"] = Value::Array(vector![Value::Array(vector![hw_req, s9pk])]);
|
||||
}
|
||||
}
|
||||
for (_, info) in db["index"]["os"]["versions"]
|
||||
.as_object_mut()
|
||||
.unwrap()
|
||||
.iter_mut()
|
||||
{
|
||||
for asset_ty in ["iso", "squashfs", "img"] {
|
||||
for (_, info) in info[asset_ty].as_object_mut().unwrap().iter_mut() {
|
||||
info["urls"] = Value::Array(vector![info["url"].take()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,501 +0,0 @@
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use clap::Parser;
|
||||
use imbl_value::InternedString;
|
||||
use itertools::Itertools;
|
||||
use rpc_toolkit::HandlerArgs;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
use url::Url;
|
||||
|
||||
use crate::PackageId;
|
||||
use crate::context::CliContext;
|
||||
use crate::prelude::*;
|
||||
use crate::progress::FullProgressTracker;
|
||||
use crate::registry::asset::BufferedHttpSource;
|
||||
use crate::registry::context::RegistryContext;
|
||||
use crate::registry::package::index::PackageVersionInfo;
|
||||
use crate::s9pk::S9pk;
|
||||
use crate::s9pk::merkle_archive::source::http::HttpSource;
|
||||
use crate::s9pk::v2::SIG_CONTEXT;
|
||||
use crate::sign::commitment::merkle_archive::MerkleArchiveCommitment;
|
||||
use crate::sign::ed25519::Ed25519;
|
||||
use crate::sign::{AnySignature, AnyVerifyingKey, SignatureScheme};
|
||||
use crate::util::VersionString;
|
||||
use crate::util::io::TrackingIO;
|
||||
use crate::util::serde::Base64;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct AddPackageParams {
|
||||
#[ts(type = "string[]")]
|
||||
pub urls: Vec<Url>,
|
||||
#[ts(skip)]
|
||||
#[serde(rename = "__Auth_signer")]
|
||||
pub uploader: AnyVerifyingKey,
|
||||
pub commitment: MerkleArchiveCommitment,
|
||||
pub signature: AnySignature,
|
||||
}
|
||||
|
||||
pub async fn add_package(
|
||||
ctx: RegistryContext,
|
||||
AddPackageParams {
|
||||
urls,
|
||||
uploader,
|
||||
commitment,
|
||||
signature,
|
||||
}: AddPackageParams,
|
||||
) -> Result<(), Error> {
|
||||
uploader
|
||||
.scheme()
|
||||
.verify_commitment(&uploader, &commitment, SIG_CONTEXT, &signature)?;
|
||||
let peek = ctx.db.peek().await;
|
||||
let uploader_guid = peek.as_index().as_signers().get_signer(&uploader)?;
|
||||
|
||||
let Some(([url], rest)) = urls.split_at_checked(1) else {
|
||||
return Err(Error::new(
|
||||
eyre!("must specify at least 1 url"),
|
||||
ErrorKind::InvalidRequest,
|
||||
));
|
||||
};
|
||||
|
||||
let s9pk = S9pk::deserialize(
|
||||
&Arc::new(HttpSource::new(ctx.client.clone(), url.clone()).await?),
|
||||
Some(&commitment),
|
||||
)
|
||||
.await?;
|
||||
|
||||
for url in rest {
|
||||
S9pk::deserialize(
|
||||
&Arc::new(HttpSource::new(ctx.client.clone(), url.clone()).await?),
|
||||
Some(&commitment),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
let manifest = s9pk.as_manifest();
|
||||
|
||||
let mut info = PackageVersionInfo::from_s9pk(&s9pk, urls).await?;
|
||||
for (_, s9pk) in &mut info.s9pks {
|
||||
if !s9pk.signatures.contains_key(&uploader) && s9pk.commitment == commitment {
|
||||
s9pk.signatures.insert(uploader.clone(), signature.clone());
|
||||
}
|
||||
}
|
||||
|
||||
ctx.db
|
||||
.mutate(|db| {
|
||||
if db.as_admins().de()?.contains(&uploader_guid)
|
||||
|| db
|
||||
.as_index()
|
||||
.as_package()
|
||||
.as_packages()
|
||||
.as_idx(&manifest.id)
|
||||
.or_not_found(&manifest.id)?
|
||||
.as_authorized()
|
||||
.de()?
|
||||
.get(&uploader_guid)
|
||||
.map_or(false, |v| manifest.version.satisfies(v))
|
||||
{
|
||||
let package = db
|
||||
.as_index_mut()
|
||||
.as_package_mut()
|
||||
.as_packages_mut()
|
||||
.upsert(&manifest.id, || Ok(Default::default()))?;
|
||||
let v = package.as_versions_mut();
|
||||
if let Some(prev) = v.as_idx_mut(&manifest.version) {
|
||||
prev.mutate(|p| p.merge_with(info, true))?;
|
||||
} else {
|
||||
v.insert(&manifest.version, &info)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(eyre!("UNAUTHORIZED"), ErrorKind::Authorization))
|
||||
}
|
||||
})
|
||||
.await
|
||||
.result
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Parser)]
|
||||
#[command(rename_all = "kebab-case")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CliAddPackageParams {
|
||||
pub file: PathBuf,
|
||||
#[arg(long)]
|
||||
pub url: Vec<Url>,
|
||||
#[arg(long)]
|
||||
pub no_verify: bool,
|
||||
}
|
||||
|
||||
pub async fn cli_add_package(
|
||||
HandlerArgs {
|
||||
context: ctx,
|
||||
parent_method,
|
||||
method,
|
||||
params:
|
||||
CliAddPackageParams {
|
||||
file,
|
||||
url,
|
||||
no_verify,
|
||||
},
|
||||
..
|
||||
}: HandlerArgs<CliContext, CliAddPackageParams>,
|
||||
) -> Result<(), Error> {
|
||||
let s9pk = S9pk::open(&file, None).await?;
|
||||
|
||||
let progress = FullProgressTracker::new();
|
||||
let mut sign_phase = progress.add_phase(InternedString::intern("Signing File"), Some(1));
|
||||
let verify = if !no_verify {
|
||||
url.iter()
|
||||
.map(|url| {
|
||||
let phase = progress.add_phase(
|
||||
InternedString::from_display(&lazy_format!("Verifying {url}")),
|
||||
Some(100),
|
||||
);
|
||||
(url.clone(), phase)
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
let mut index_phase = progress.add_phase(
|
||||
InternedString::intern("Adding File to Registry Index"),
|
||||
Some(1),
|
||||
);
|
||||
|
||||
let progress_task =
|
||||
progress.progress_bar_task(&format!("Adding {} to registry...", file.display()));
|
||||
|
||||
sign_phase.start();
|
||||
let commitment = s9pk.as_archive().commitment().await?;
|
||||
let signature = Ed25519.sign_commitment(ctx.developer_key()?, &commitment, SIG_CONTEXT)?;
|
||||
sign_phase.complete();
|
||||
|
||||
for (url, mut phase) in verify {
|
||||
phase.start();
|
||||
let source = BufferedHttpSource::new(ctx.client.clone(), url, phase).await?;
|
||||
let mut src = S9pk::deserialize(&Arc::new(source), Some(&commitment)).await?;
|
||||
src.serialize(&mut TrackingIO::new(0, &mut tokio::io::sink()), true)
|
||||
.await?;
|
||||
}
|
||||
|
||||
index_phase.start();
|
||||
ctx.call_remote::<RegistryContext>(
|
||||
&parent_method.into_iter().chain(method).join("."),
|
||||
imbl_value::json!({
|
||||
"urls": &url,
|
||||
"signature": AnySignature::Ed25519(signature),
|
||||
"commitment": commitment,
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
index_phase.complete();
|
||||
|
||||
progress.complete();
|
||||
|
||||
progress_task.await.with_kind(ErrorKind::Unknown)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Parser, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct RemovePackageParams {
|
||||
pub id: PackageId,
|
||||
pub version: VersionString,
|
||||
#[arg(long)]
|
||||
pub sighash: Option<Base64<[u8; 32]>>,
|
||||
#[ts(skip)]
|
||||
#[arg(skip)]
|
||||
#[serde(rename = "__Auth_signer")]
|
||||
pub signer: Option<AnyVerifyingKey>,
|
||||
}
|
||||
|
||||
pub async fn remove_package(
|
||||
ctx: RegistryContext,
|
||||
RemovePackageParams {
|
||||
id,
|
||||
version,
|
||||
sighash,
|
||||
signer,
|
||||
}: RemovePackageParams,
|
||||
) -> Result<bool, Error> {
|
||||
let peek = ctx.db.peek().await;
|
||||
let signer =
|
||||
signer.ok_or_else(|| Error::new(eyre!("missing signer"), ErrorKind::InvalidRequest))?;
|
||||
let signer_guid = peek.as_index().as_signers().get_signer(&signer)?;
|
||||
|
||||
let rev = ctx
|
||||
.db
|
||||
.mutate(|db| {
|
||||
if db.as_admins().de()?.contains(&signer_guid)
|
||||
|| db
|
||||
.as_index()
|
||||
.as_package()
|
||||
.as_packages()
|
||||
.as_idx(&id)
|
||||
.or_not_found(&id)?
|
||||
.as_authorized()
|
||||
.de()?
|
||||
.get(&signer_guid)
|
||||
.map_or(false, |v| version.satisfies(v))
|
||||
{
|
||||
if let Some(package) = db
|
||||
.as_index_mut()
|
||||
.as_package_mut()
|
||||
.as_packages_mut()
|
||||
.as_idx_mut(&id)
|
||||
{
|
||||
if let Some(sighash) = sighash {
|
||||
if if let Some(package) = package.as_versions_mut().as_idx_mut(&version) {
|
||||
package.as_s9pks_mut().mutate(|s| {
|
||||
s.retain(|(_, asset)| asset.commitment.root_sighash != sighash);
|
||||
Ok(s.is_empty())
|
||||
})?
|
||||
} else {
|
||||
false
|
||||
} {
|
||||
package.as_versions_mut().remove(&version)?;
|
||||
}
|
||||
} else {
|
||||
package.as_versions_mut().remove(&version)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(eyre!("UNAUTHORIZED"), ErrorKind::Authorization))
|
||||
}
|
||||
})
|
||||
.await;
|
||||
rev.result.map(|_| rev.revision.is_some())
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct AddMirrorParams {
|
||||
#[ts(type = "string")]
|
||||
pub url: Url,
|
||||
#[ts(skip)]
|
||||
#[serde(rename = "__Auth_signer")]
|
||||
pub uploader: AnyVerifyingKey,
|
||||
pub commitment: MerkleArchiveCommitment,
|
||||
pub signature: AnySignature,
|
||||
}
|
||||
|
||||
pub async fn add_mirror(
|
||||
ctx: RegistryContext,
|
||||
AddMirrorParams {
|
||||
url,
|
||||
uploader,
|
||||
commitment,
|
||||
signature,
|
||||
}: AddMirrorParams,
|
||||
) -> Result<(), Error> {
|
||||
uploader
|
||||
.scheme()
|
||||
.verify_commitment(&uploader, &commitment, SIG_CONTEXT, &signature)?;
|
||||
let peek = ctx.db.peek().await;
|
||||
let uploader_guid = peek.as_index().as_signers().get_signer(&uploader)?;
|
||||
|
||||
let s9pk = S9pk::deserialize(
|
||||
&Arc::new(HttpSource::new(ctx.client.clone(), url.clone()).await?),
|
||||
Some(&commitment),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let manifest = s9pk.as_manifest();
|
||||
|
||||
let mut info = PackageVersionInfo::from_s9pk(&s9pk, vec![url]).await?;
|
||||
for (_, s9pk) in &mut info.s9pks {
|
||||
if !s9pk.signatures.contains_key(&uploader) && s9pk.commitment == commitment {
|
||||
s9pk.signatures.insert(uploader.clone(), signature.clone());
|
||||
}
|
||||
}
|
||||
|
||||
ctx.db
|
||||
.mutate(|db| {
|
||||
if db.as_admins().de()?.contains(&uploader_guid)
|
||||
|| db
|
||||
.as_index()
|
||||
.as_package()
|
||||
.as_packages()
|
||||
.as_idx(&manifest.id)
|
||||
.or_not_found(&manifest.id)?
|
||||
.as_authorized()
|
||||
.de()?
|
||||
.get(&uploader_guid)
|
||||
.map_or(false, |v| manifest.version.satisfies(v))
|
||||
{
|
||||
let package = db
|
||||
.as_index_mut()
|
||||
.as_package_mut()
|
||||
.as_packages_mut()
|
||||
.as_idx_mut(&manifest.id)
|
||||
.and_then(|p| p.as_versions_mut().as_idx_mut(&manifest.version))
|
||||
.or_not_found(&lazy_format!("{}@{}", &manifest.id, &manifest.version))?;
|
||||
package.mutate(|p| p.merge_with(info, false))?;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(eyre!("UNAUTHORIZED"), ErrorKind::Authorization))
|
||||
}
|
||||
})
|
||||
.await
|
||||
.result
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Parser)]
|
||||
#[command(rename_all = "kebab-case")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CliAddMirrorParams {
|
||||
pub file: PathBuf,
|
||||
pub url: Url,
|
||||
pub no_verify: bool,
|
||||
}
|
||||
|
||||
pub async fn cli_add_mirror(
|
||||
HandlerArgs {
|
||||
context: ctx,
|
||||
parent_method,
|
||||
method,
|
||||
params:
|
||||
CliAddMirrorParams {
|
||||
file,
|
||||
url,
|
||||
no_verify,
|
||||
},
|
||||
..
|
||||
}: HandlerArgs<CliContext, CliAddMirrorParams>,
|
||||
) -> Result<(), Error> {
|
||||
let s9pk = S9pk::open(&file, None).await?;
|
||||
|
||||
let progress = FullProgressTracker::new();
|
||||
let mut sign_phase = progress.add_phase(InternedString::intern("Signing File"), Some(1));
|
||||
let verify = if !no_verify {
|
||||
let url = &url;
|
||||
vec![(
|
||||
url.clone(),
|
||||
progress.add_phase(
|
||||
InternedString::from_display(&lazy_format!("Verifying {url}")),
|
||||
Some(100),
|
||||
),
|
||||
)]
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
let mut index_phase = progress.add_phase(
|
||||
InternedString::intern("Adding File to Registry Index"),
|
||||
Some(1),
|
||||
);
|
||||
|
||||
let progress_task =
|
||||
progress.progress_bar_task(&format!("Adding {} to registry...", file.display()));
|
||||
|
||||
sign_phase.start();
|
||||
let commitment = s9pk.as_archive().commitment().await?;
|
||||
let signature = Ed25519.sign_commitment(ctx.developer_key()?, &commitment, SIG_CONTEXT)?;
|
||||
sign_phase.complete();
|
||||
|
||||
for (url, mut phase) in verify {
|
||||
phase.start();
|
||||
let source = BufferedHttpSource::new(ctx.client.clone(), url, phase).await?;
|
||||
let mut src = S9pk::deserialize(&Arc::new(source), Some(&commitment)).await?;
|
||||
src.serialize(&mut TrackingIO::new(0, &mut tokio::io::sink()), true)
|
||||
.await?;
|
||||
}
|
||||
|
||||
index_phase.start();
|
||||
ctx.call_remote::<RegistryContext>(
|
||||
&parent_method.into_iter().chain(method).join("."),
|
||||
imbl_value::json!({
|
||||
"url": &url,
|
||||
"signature": AnySignature::Ed25519(signature),
|
||||
"commitment": commitment,
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
index_phase.complete();
|
||||
|
||||
progress.complete();
|
||||
|
||||
progress_task.await.with_kind(ErrorKind::Unknown)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Parser, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct RemoveMirrorParams {
|
||||
pub id: PackageId,
|
||||
pub version: VersionString,
|
||||
#[arg(long)]
|
||||
#[ts(type = "string")]
|
||||
pub url: Url,
|
||||
#[ts(skip)]
|
||||
#[arg(skip)]
|
||||
#[serde(rename = "__Auth_signer")]
|
||||
pub signer: Option<AnyVerifyingKey>,
|
||||
}
|
||||
|
||||
pub async fn remove_mirror(
|
||||
ctx: RegistryContext,
|
||||
RemoveMirrorParams {
|
||||
id,
|
||||
version,
|
||||
url,
|
||||
signer,
|
||||
}: RemoveMirrorParams,
|
||||
) -> Result<(), Error> {
|
||||
let peek = ctx.db.peek().await;
|
||||
let signer =
|
||||
signer.ok_or_else(|| Error::new(eyre!("missing signer"), ErrorKind::InvalidRequest))?;
|
||||
let signer_guid = peek.as_index().as_signers().get_signer(&signer)?;
|
||||
|
||||
ctx.db
|
||||
.mutate(|db| {
|
||||
if db.as_admins().de()?.contains(&signer_guid)
|
||||
|| db
|
||||
.as_index()
|
||||
.as_package()
|
||||
.as_packages()
|
||||
.as_idx(&id)
|
||||
.or_not_found(&id)?
|
||||
.as_authorized()
|
||||
.de()?
|
||||
.get(&signer_guid)
|
||||
.map_or(false, |v| version.satisfies(v))
|
||||
{
|
||||
if let Some(package) = db
|
||||
.as_index_mut()
|
||||
.as_package_mut()
|
||||
.as_packages_mut()
|
||||
.as_idx_mut(&id)
|
||||
.and_then(|p| p.as_versions_mut().as_idx_mut(&version))
|
||||
{
|
||||
package.as_s9pks_mut().mutate(|s| {
|
||||
s.iter_mut()
|
||||
.for_each(|(_, asset)| asset.urls.retain(|u| u != &url));
|
||||
if s.iter().any(|(_, asset)| asset.urls.is_empty()) {
|
||||
Err(Error::new(
|
||||
eyre!("cannot remove last mirror from an s9pk"),
|
||||
ErrorKind::InvalidRequest,
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(eyre!("UNAUTHORIZED"), ErrorKind::Authorization))
|
||||
}
|
||||
})
|
||||
.await
|
||||
.result
|
||||
}
|
||||
@@ -1,291 +0,0 @@
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::u32;
|
||||
|
||||
use chrono::Utc;
|
||||
use exver::{Version, VersionRange};
|
||||
use imbl_value::InternedString;
|
||||
use patch_db::ModelExt;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
use url::Url;
|
||||
|
||||
use crate::PackageId;
|
||||
use crate::prelude::*;
|
||||
use crate::registry::asset::RegistryAsset;
|
||||
use crate::registry::context::RegistryContext;
|
||||
use crate::registry::device_info::DeviceInfo;
|
||||
use crate::rpc_continuations::Guid;
|
||||
use crate::s9pk::S9pk;
|
||||
use crate::s9pk::git_hash::GitHash;
|
||||
use crate::s9pk::manifest::{Alerts, Description, HardwareRequirements};
|
||||
use crate::s9pk::merkle_archive::source::FileSource;
|
||||
use crate::sign::commitment::merkle_archive::MerkleArchiveCommitment;
|
||||
use crate::sign::{AnySignature, AnyVerifyingKey};
|
||||
use crate::util::{DataUrl, VersionString};
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize, HasModel, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[model = "Model<Self>"]
|
||||
#[ts(export)]
|
||||
pub struct PackageIndex {
|
||||
pub categories: BTreeMap<InternedString, Category>,
|
||||
pub packages: BTreeMap<PackageId, PackageInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize, HasModel, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[model = "Model<Self>"]
|
||||
#[ts(export)]
|
||||
pub struct PackageInfo {
|
||||
#[ts(as = "BTreeMap::<Guid, String>")]
|
||||
pub authorized: BTreeMap<Guid, VersionRange>,
|
||||
pub versions: BTreeMap<VersionString, PackageVersionInfo>,
|
||||
#[ts(type = "string[]")]
|
||||
pub categories: BTreeSet<InternedString>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, HasModel, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[model = "Model<Self>"]
|
||||
#[ts(export)]
|
||||
pub struct Category {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, HasModel, TS, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[model = "Model<Self>"]
|
||||
#[ts(export)]
|
||||
pub struct DependencyMetadata {
|
||||
#[ts(type = "string | null")]
|
||||
pub title: Option<InternedString>,
|
||||
pub icon: Option<DataUrl<'static>>,
|
||||
pub description: Option<String>,
|
||||
pub optional: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, HasModel, TS, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[model = "Model<Self>"]
|
||||
pub struct PackageMetadata {
|
||||
#[ts(type = "string")]
|
||||
pub title: InternedString,
|
||||
pub icon: DataUrl<'static>,
|
||||
pub description: Description,
|
||||
pub release_notes: String,
|
||||
pub git_hash: Option<GitHash>,
|
||||
#[ts(type = "string")]
|
||||
pub license: InternedString,
|
||||
#[ts(type = "string")]
|
||||
pub wrapper_repo: Url,
|
||||
#[ts(type = "string")]
|
||||
pub upstream_repo: Url,
|
||||
#[ts(type = "string")]
|
||||
pub support_site: Url,
|
||||
#[ts(type = "string")]
|
||||
pub marketing_site: Url,
|
||||
#[ts(type = "string | null")]
|
||||
pub donation_url: Option<Url>,
|
||||
#[ts(type = "string | null")]
|
||||
pub docs_url: Option<Url>,
|
||||
pub alerts: Alerts,
|
||||
pub dependency_metadata: BTreeMap<PackageId, DependencyMetadata>,
|
||||
#[ts(type = "string")]
|
||||
pub os_version: Version,
|
||||
#[ts(type = "string | null")]
|
||||
pub sdk_version: Option<Version>,
|
||||
#[serde(default)]
|
||||
pub hardware_acceleration: bool,
|
||||
}
|
||||
impl PackageMetadata {
|
||||
pub async fn load<S: FileSource + Clone>(s9pk: &S9pk<S>) -> Result<Self, Error> {
|
||||
let manifest = s9pk.as_manifest();
|
||||
let mut dependency_metadata = BTreeMap::new();
|
||||
for (id, info) in &manifest.dependencies.0 {
|
||||
let metadata = s9pk.dependency_metadata(id).await?;
|
||||
dependency_metadata.insert(
|
||||
id.clone(),
|
||||
DependencyMetadata {
|
||||
title: metadata.map(|m| m.title),
|
||||
icon: s9pk.dependency_icon_data_url(id).await?,
|
||||
description: info.description.clone(),
|
||||
optional: info.optional,
|
||||
},
|
||||
);
|
||||
}
|
||||
Ok(Self {
|
||||
title: manifest.title.clone(),
|
||||
icon: s9pk.icon_data_url().await?,
|
||||
description: manifest.description.clone(),
|
||||
release_notes: manifest.release_notes.clone(),
|
||||
git_hash: manifest.git_hash.clone(),
|
||||
license: manifest.license.clone(),
|
||||
wrapper_repo: manifest.wrapper_repo.clone(),
|
||||
upstream_repo: manifest.upstream_repo.clone(),
|
||||
support_site: manifest.support_site.clone(),
|
||||
marketing_site: manifest.marketing_site.clone(),
|
||||
donation_url: manifest.donation_url.clone(),
|
||||
docs_url: manifest.docs_url.clone(),
|
||||
alerts: manifest.alerts.clone(),
|
||||
dependency_metadata,
|
||||
os_version: manifest.os_version.clone(),
|
||||
sdk_version: manifest.sdk_version.clone(),
|
||||
hardware_acceleration: manifest.hardware_acceleration.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, HasModel, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[model = "Model<Self>"]
|
||||
#[ts(export)]
|
||||
pub struct PackageVersionInfo {
|
||||
#[serde(flatten)]
|
||||
pub metadata: PackageMetadata,
|
||||
#[ts(type = "string | null")]
|
||||
pub source_version: Option<VersionRange>,
|
||||
pub s9pks: Vec<(HardwareRequirements, RegistryAsset<MerkleArchiveCommitment>)>,
|
||||
}
|
||||
impl PackageVersionInfo {
|
||||
pub async fn from_s9pk<S: FileSource + Clone>(
|
||||
s9pk: &S9pk<S>,
|
||||
urls: Vec<Url>,
|
||||
) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
metadata: PackageMetadata::load(s9pk).await?,
|
||||
source_version: None, // TODO
|
||||
s9pks: vec![(
|
||||
s9pk.as_manifest().hardware_requirements.clone(),
|
||||
RegistryAsset {
|
||||
published_at: Utc::now(),
|
||||
urls,
|
||||
commitment: s9pk.as_archive().commitment().await?,
|
||||
signatures: [(
|
||||
AnyVerifyingKey::Ed25519(s9pk.as_archive().signer()),
|
||||
AnySignature::Ed25519(s9pk.as_archive().signature().await?),
|
||||
)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
)],
|
||||
})
|
||||
}
|
||||
pub fn merge_with(&mut self, other: Self, replace_urls: bool) -> Result<(), Error> {
|
||||
for (hw_req, asset) in other.s9pks {
|
||||
if let Some((_, matching)) = self
|
||||
.s9pks
|
||||
.iter_mut()
|
||||
.find(|(h, s)| s.commitment == asset.commitment && *h == hw_req)
|
||||
{
|
||||
if replace_urls {
|
||||
matching.urls = asset.urls;
|
||||
} else {
|
||||
for url in asset.urls {
|
||||
if matching.urls.contains(&url) {
|
||||
continue;
|
||||
}
|
||||
matching.urls.push(url);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let Some((h, matching)) = self.s9pks.iter_mut().find(|(h, _)| *h == hw_req) {
|
||||
*matching = asset;
|
||||
*h = hw_req;
|
||||
} else {
|
||||
self.s9pks.push((hw_req, asset));
|
||||
}
|
||||
}
|
||||
}
|
||||
self.s9pks.sort_by_key(|(h, _)| h.specificity_desc());
|
||||
Ok(())
|
||||
}
|
||||
pub fn table(&self, version: &VersionString) -> prettytable::Table {
|
||||
use prettytable::*;
|
||||
|
||||
let mut table = Table::new();
|
||||
|
||||
table.add_row(row![bc => &self.metadata.title]);
|
||||
table.add_row(row![br -> "VERSION", AsRef::<str>::as_ref(version)]);
|
||||
table.add_row(row![br -> "RELEASE NOTES", &self.metadata.release_notes]);
|
||||
table.add_row(
|
||||
row![br -> "ABOUT", &textwrap::wrap(&self.metadata.description.short, 80).join("\n")],
|
||||
);
|
||||
table.add_row(row![
|
||||
br -> "DESCRIPTION",
|
||||
&textwrap::wrap(&self.metadata.description.long, 80).join("\n")
|
||||
]);
|
||||
table.add_row(row![br -> "GIT HASH", self.metadata.git_hash.as_deref().unwrap_or("N/A")]);
|
||||
table.add_row(row![br -> "LICENSE", &self.metadata.license]);
|
||||
table.add_row(row![br -> "PACKAGE REPO", &self.metadata.wrapper_repo.to_string()]);
|
||||
table.add_row(row![br -> "SERVICE REPO", &self.metadata.upstream_repo.to_string()]);
|
||||
table.add_row(row![br -> "WEBSITE", &self.metadata.marketing_site.to_string()]);
|
||||
table.add_row(row![br -> "SUPPORT", &self.metadata.support_site.to_string()]);
|
||||
|
||||
table
|
||||
}
|
||||
}
|
||||
impl Model<PackageVersionInfo> {
|
||||
/// Filters this package version for compatibility with the given device.
|
||||
/// Returns false if the package is incompatible (should be removed).
|
||||
/// Modifies s9pks in place to only include compatible variants.
|
||||
pub fn for_device(&mut self, device_info: &DeviceInfo) -> Result<bool, Error> {
|
||||
if !self
|
||||
.as_metadata()
|
||||
.as_os_version()
|
||||
.de()?
|
||||
.satisfies(&device_info.os.compat)
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
if let Some(hw) = &device_info.hardware {
|
||||
self.as_s9pks_mut().mutate(|s9pks| {
|
||||
s9pks.retain(|(hw_req, _)| {
|
||||
if let Some(arch) = &hw_req.arch {
|
||||
if !arch.contains(&hw.arch) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if let Some(ram) = hw_req.ram {
|
||||
if hw.ram < ram {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if let Some(dev) = &hw.devices {
|
||||
for device_filter in &hw_req.device {
|
||||
if !dev
|
||||
.iter()
|
||||
.filter(|d| d.class() == &*device_filter.class)
|
||||
.any(|d| device_filter.matches(d))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
});
|
||||
if hw.devices.is_some() {
|
||||
s9pks.sort_by_key(|(req, _)| req.specificity_desc());
|
||||
} else {
|
||||
s9pks.sort_by_key(|(req, _)| {
|
||||
let (dev, arch, ram) = req.specificity_desc();
|
||||
(u32::MAX - dev, arch, ram)
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
if ModelExt::as_value(self.as_s9pks())
|
||||
.as_array()
|
||||
.map_or(true, |s| s.is_empty())
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_package_index(ctx: RegistryContext) -> Result<PackageIndex, Error> {
|
||||
ctx.db.peek().await.into_index().into_package().de()
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use imbl_value::InternedString;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::process::Command;
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::util::Invoke;
|
||||
|
||||
const KNOWN_CLASSES: &[&str] = &["processor", "display"];
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[serde(tag = "class")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub enum LshwDevice {
|
||||
Processor(LshwProcessor),
|
||||
Display(LshwDisplay),
|
||||
}
|
||||
impl LshwDevice {
|
||||
pub fn class(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Processor(_) => "processor",
|
||||
Self::Display(_) => "display",
|
||||
}
|
||||
}
|
||||
pub fn from_value(value: &Value) -> Option<Self> {
|
||||
match value["class"].as_str() {
|
||||
Some("processor") => Some(LshwDevice::Processor(LshwProcessor::from_value(value))),
|
||||
Some("display") => Some(LshwDevice::Display(LshwDisplay::from_value(value))),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
pub struct LshwProcessor {
|
||||
pub product: Option<InternedString>,
|
||||
pub vendor: Option<InternedString>,
|
||||
pub capabilities: BTreeSet<InternedString>,
|
||||
}
|
||||
impl LshwProcessor {
|
||||
fn from_value(value: &Value) -> Self {
|
||||
Self {
|
||||
product: value["product"].as_str().map(From::from),
|
||||
vendor: value["vendor"].as_str().map(From::from),
|
||||
capabilities: value["capabilities"]
|
||||
.as_object()
|
||||
.into_iter()
|
||||
.flat_map(|o| o.keys())
|
||||
.map(|k| k.clone())
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
pub struct LshwDisplay {
|
||||
pub product: Option<InternedString>,
|
||||
pub vendor: Option<InternedString>,
|
||||
pub capabilities: BTreeSet<InternedString>,
|
||||
pub driver: Option<InternedString>,
|
||||
}
|
||||
impl LshwDisplay {
|
||||
fn from_value(value: &Value) -> Self {
|
||||
Self {
|
||||
product: value["product"].as_str().map(From::from),
|
||||
vendor: value["vendor"].as_str().map(From::from),
|
||||
capabilities: value["capabilities"]
|
||||
.as_object()
|
||||
.into_iter()
|
||||
.flat_map(|o| o.keys())
|
||||
.map(|k| k.clone())
|
||||
.collect(),
|
||||
driver: value["configuration"]["driver"].as_str().map(From::from),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn lshw() -> Result<Vec<LshwDevice>, Error> {
|
||||
let mut cmd = Command::new("lshw");
|
||||
cmd.arg("-json");
|
||||
for class in KNOWN_CLASSES {
|
||||
cmd.arg("-class").arg(*class);
|
||||
}
|
||||
Ok(
|
||||
serde_json::from_slice::<Vec<Value>>(&cmd.invoke(crate::ErrorKind::Lshw).await?)
|
||||
.with_kind(crate::ErrorKind::Deserialization)?
|
||||
.iter()
|
||||
.filter_map(LshwDevice::from_value)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
use exver::{PreReleaseSegment, VersionRange};
|
||||
|
||||
use super::v0_3_5::V0_3_0_COMPAT;
|
||||
use super::{VersionT, v0_4_0_alpha_16};
|
||||
use crate::db::model::public::AcmeSettings;
|
||||
use crate::net::acme::AcmeProvider;
|
||||
use crate::prelude::*;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref V0_4_0_alpha_17: exver::Version = exver::Version::new(
|
||||
[0, 4, 0],
|
||||
[PreReleaseSegment::String("alpha".into()), 17.into()]
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct Version;
|
||||
|
||||
impl VersionT for Version {
|
||||
type Previous = v0_4_0_alpha_16::Version;
|
||||
type PreUpRes = ();
|
||||
|
||||
async fn pre_up(self) -> Result<Self::PreUpRes, Error> {
|
||||
Ok(())
|
||||
}
|
||||
fn semver(self) -> exver::Version {
|
||||
V0_4_0_alpha_17.clone()
|
||||
}
|
||||
fn compat(self) -> &'static VersionRange {
|
||||
&V0_3_0_COMPAT
|
||||
}
|
||||
#[instrument(skip_all)]
|
||||
fn up(self, db: &mut Value, _: Self::PreUpRes) -> Result<Value, Error> {
|
||||
let acme = db["public"]["serverInfo"]["network"]["acme"]
|
||||
.as_object_mut()
|
||||
.or_not_found("public.serverInfo.network.acme")?;
|
||||
let letsencrypt =
|
||||
InternedString::intern::<&str>("letsencrypt".parse::<AcmeProvider>()?.as_ref());
|
||||
if !acme.contains_key(&letsencrypt) {
|
||||
acme.insert(
|
||||
letsencrypt,
|
||||
to_value(&AcmeSettings {
|
||||
contact: Vec::new(),
|
||||
})?,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(Value::Null)
|
||||
}
|
||||
fn down(self, _db: &mut Value) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
289
core/startos/Cargo.toml
Normal file
289
core/startos/Cargo.toml
Normal file
@@ -0,0 +1,289 @@
|
||||
[package]
|
||||
authors = ["Aiden McClelland <me@drbonez.dev>"]
|
||||
description = "The core of StartOS"
|
||||
documentation = "https://docs.rs/start-os"
|
||||
edition = "2024"
|
||||
keywords = [
|
||||
"bitcoin",
|
||||
"full-node",
|
||||
"lightning",
|
||||
"privacy",
|
||||
"raspberry-pi",
|
||||
"self-hosted",
|
||||
]
|
||||
license = "MIT"
|
||||
name = "start-os"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/Start9Labs/start-os"
|
||||
version = "0.4.0-alpha.16" # VERSION_BUMP
|
||||
|
||||
[lib]
|
||||
name = "startos"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "startbox"
|
||||
path = "src/main/startbox.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "start-cli"
|
||||
path = "src/main/start-cli.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "start-container"
|
||||
path = "src/main/start-container.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "registrybox"
|
||||
path = "src/main/registrybox.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "tunnelbox"
|
||||
path = "src/main/tunnelbox.rs"
|
||||
|
||||
[features]
|
||||
arti = [
|
||||
"arti-client",
|
||||
"safelog",
|
||||
"tor-cell",
|
||||
"tor-hscrypto",
|
||||
"tor-hsservice",
|
||||
"tor-keymgr",
|
||||
"tor-llcrypto",
|
||||
"tor-proto",
|
||||
"tor-rtcompat",
|
||||
]
|
||||
console = ["console-subscriber", "tokio/tracing"]
|
||||
default = []
|
||||
dev = []
|
||||
test = []
|
||||
unstable = ["backtrace-on-stack-overflow"]
|
||||
|
||||
[dependencies]
|
||||
aes = { version = "0.7.5", features = ["ctr"] }
|
||||
arti-client = { version = "0.33", features = [
|
||||
"compression",
|
||||
"ephemeral-keystore",
|
||||
"experimental-api",
|
||||
"onion-service-client",
|
||||
"onion-service-service",
|
||||
"rustls",
|
||||
"static",
|
||||
"tokio",
|
||||
], default-features = false, git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true }
|
||||
async-acme = { version = "0.6.0", git = "https://github.com/dr-bonez/async-acme.git", features = [
|
||||
"use_rustls",
|
||||
"use_tokio",
|
||||
] }
|
||||
async-compression = { version = "0.4.32", features = [
|
||||
"brotli",
|
||||
"gzip",
|
||||
"tokio",
|
||||
"zstd",
|
||||
] }
|
||||
async-stream = "0.3.5"
|
||||
async-trait = "0.1.74"
|
||||
axum = { version = "0.8.4", features = ["ws", "http2"] }
|
||||
backtrace-on-stack-overflow = { version = "0.3.0", optional = true }
|
||||
base32 = "0.5.0"
|
||||
base64 = "0.22.1"
|
||||
base64ct = "1.6.0"
|
||||
basic-cookies = "0.1.4"
|
||||
blake3 = { version = "1.5.0", features = ["mmap", "rayon"] }
|
||||
bytes = "1"
|
||||
chrono = { version = "0.4.31", features = ["serde"] }
|
||||
clap = { version = "4.4.12", features = ["string"] }
|
||||
color-eyre = "0.6.2"
|
||||
console = "0.16.2"
|
||||
console-subscriber = { version = "0.5.0", optional = true }
|
||||
const_format = "0.2.34"
|
||||
cookie = "0.18.0"
|
||||
cookie_store = "0.22.0"
|
||||
curve25519-dalek = "4.1.3"
|
||||
der = { version = "0.7.9", features = ["derive", "pem"] }
|
||||
digest = "0.10.7"
|
||||
divrem = "1.0.0"
|
||||
dns-lookup = "3.0.1"
|
||||
ed25519 = { version = "2.2.3", features = ["alloc", "pem", "pkcs8"] }
|
||||
ed25519-dalek = { version = "2.2.0", features = [
|
||||
"digest",
|
||||
"hazmat",
|
||||
"pkcs8",
|
||||
"rand_core",
|
||||
"serde",
|
||||
"zeroize",
|
||||
] }
|
||||
ed25519-dalek-v1 = { package = "ed25519-dalek", version = "1" }
|
||||
exver = { version = "0.2.0", git = "https://github.com/Start9Labs/exver-rs.git", features = [
|
||||
"serde",
|
||||
] }
|
||||
fd-lock-rs = "0.1.4"
|
||||
form_urlencoded = "1.2.1"
|
||||
futures = "0.3.28"
|
||||
gpt = "4.1.0"
|
||||
hex = "0.4.3"
|
||||
hickory-client = "0.25.2"
|
||||
hickory-server = "0.25.2"
|
||||
hmac = "0.12.1"
|
||||
http = "1.0.0"
|
||||
http-body-util = "0.1"
|
||||
hyper = { version = "1.5", features = ["http1", "http2", "server"] }
|
||||
hyper-util = { version = "0.1.10", features = [
|
||||
"http1",
|
||||
"http2",
|
||||
"server",
|
||||
"server-auto",
|
||||
"server-graceful",
|
||||
"service",
|
||||
"tokio",
|
||||
] }
|
||||
id-pool = { version = "0.2.2", default-features = false, features = [
|
||||
"serde",
|
||||
"u16",
|
||||
] }
|
||||
iddqd = "0.3.14"
|
||||
imbl = { version = "6", features = ["serde", "small-chunks"] }
|
||||
imbl-value = { version = "0.4.3", features = ["ts-rs"] }
|
||||
include_dir = { version = "0.7.3", features = ["metadata"] }
|
||||
indexmap = { version = "2.0.2", features = ["serde"] }
|
||||
indicatif = { version = "0.18.3", features = ["tokio"] }
|
||||
inotify = "0.11.0"
|
||||
integer-encoding = { version = "4.0.0", features = ["tokio_async"] }
|
||||
ipnet = { version = "2.8.0", features = ["serde"] }
|
||||
isocountry = "0.3.2"
|
||||
itertools = "0.14.0"
|
||||
jaq-core = "0.10.1"
|
||||
jaq-std = "0.10.0"
|
||||
josekit = "0.10.3"
|
||||
jsonpath_lib = { git = "https://github.com/Start9Labs/jsonpath.git" }
|
||||
lazy_async_pool = "0.3.3"
|
||||
lazy_format = "2.0"
|
||||
lazy_static = "1.4.0"
|
||||
lettre = { version = "0.11.18", default-features = false, features = [
|
||||
"aws-lc-rs",
|
||||
"builder",
|
||||
"hostname",
|
||||
"pool",
|
||||
"rustls-platform-verifier",
|
||||
"smtp-transport",
|
||||
"tokio1-rustls",
|
||||
] }
|
||||
libc = "0.2.149"
|
||||
log = "0.4.20"
|
||||
mbrman = "0.6.0"
|
||||
miette = { version = "7.6.0", features = ["fancy"] }
|
||||
mio = "1"
|
||||
new_mime_guess = "4"
|
||||
nix = { version = "0.30.1", features = [
|
||||
"fs",
|
||||
"mount",
|
||||
"net",
|
||||
"process",
|
||||
"sched",
|
||||
"signal",
|
||||
"user",
|
||||
] }
|
||||
nom = "8.0.0"
|
||||
num = "0.4.1"
|
||||
num_cpus = "1.16.0"
|
||||
num_enum = "0.7.0"
|
||||
once_cell = "1.19.0"
|
||||
openssh-keys = "0.6.2"
|
||||
openssl = { version = "0.10.57", features = ["vendored"] }
|
||||
p256 = { version = "0.13.2", features = ["pem"] }
|
||||
patch-db = { version = "*", path = "../../patch-db/patch-db", features = [
|
||||
"trace",
|
||||
] }
|
||||
pbkdf2 = "0.12.2"
|
||||
pin-project = "1.1.3"
|
||||
pkcs8 = { version = "0.10.2", features = ["std"] }
|
||||
prettytable-rs = "0.10.0"
|
||||
proptest = "1.3.1"
|
||||
proptest-derive = "0.7.0"
|
||||
qrcode = "0.14.1"
|
||||
r3bl_tui = "0.7.6"
|
||||
rand = "0.9.2"
|
||||
regex = "1.10.2"
|
||||
reqwest = { version = "0.12.25", features = [
|
||||
"json",
|
||||
"socks",
|
||||
"stream",
|
||||
"http2",
|
||||
] }
|
||||
reqwest_cookie_store = "0.9.0"
|
||||
rpassword = "7.2.0"
|
||||
rust-argon2 = "3.0.0"
|
||||
rpc-toolkit = { git = "https://github.com/Start9Labs/rpc-toolkit.git" }
|
||||
safelog = { version = "0.4.8", git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true }
|
||||
semver = { version = "1.0.20", features = ["serde"] }
|
||||
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||
serde_cbor = { package = "ciborium", version = "0.2.1" }
|
||||
serde_json = "1.0"
|
||||
serde_toml = { package = "toml", version = "0.9.9+spec-1.0.0" }
|
||||
serde_yaml = { package = "serde_yml", version = "0.0.12" }
|
||||
sha-crypt = "0.5.0"
|
||||
sha2 = "0.10.2"
|
||||
signal-hook = "0.3.17"
|
||||
socket2 = { version = "0.6.0", features = ["all"] }
|
||||
socks5-impl = { version = "0.7.2", features = ["client", "server"] }
|
||||
sqlx = { version = "0.8.6", features = [
|
||||
"postgres",
|
||||
"runtime-tokio-rustls",
|
||||
], default-features = false }
|
||||
sscanf = "0.4.1"
|
||||
ssh-key = { version = "0.6.2", features = ["ed25519"] }
|
||||
tar = "0.4.40"
|
||||
termion = "4.0.5"
|
||||
textwrap = "0.16.1"
|
||||
thiserror = "2.0.12"
|
||||
tokio = { version = "1.38.1", features = ["full"] }
|
||||
tokio-rustls = "0.26.4"
|
||||
tokio-stream = { version = "0.1.14", features = ["io-util", "net", "sync"] }
|
||||
tokio-tar = { git = "https://github.com/dr-bonez/tokio-tar.git" }
|
||||
tokio-tungstenite = { version = "0.26.2", features = ["native-tls", "url"] }
|
||||
tokio-util = { version = "0.7.9", features = ["io"] }
|
||||
tor-cell = { version = "0.33", git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true }
|
||||
tor-hscrypto = { version = "0.33", features = [
|
||||
"full",
|
||||
], git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true }
|
||||
tor-hsservice = { version = "0.33", git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true }
|
||||
tor-keymgr = { version = "0.33", features = [
|
||||
"ephemeral-keystore",
|
||||
], git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true }
|
||||
tor-llcrypto = { version = "0.33", features = [
|
||||
"full",
|
||||
], git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true }
|
||||
tor-proto = { version = "0.33", git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true }
|
||||
tor-rtcompat = { version = "0.33", features = [
|
||||
"rustls",
|
||||
"tokio",
|
||||
], git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true }
|
||||
torut = "0.2.1"
|
||||
tower-service = "0.3.3"
|
||||
tracing = "0.1.39"
|
||||
tracing-error = "0.2.0"
|
||||
tracing-journald = "0.3.0"
|
||||
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
|
||||
ts-rs = "9.0.1"
|
||||
typed-builder = "0.23.2"
|
||||
url = { version = "2.4.1", features = ["serde"] }
|
||||
uuid = { version = "1.4.1", features = ["v4"] }
|
||||
visit-rs = "0.1.1"
|
||||
x25519-dalek = { version = "2.0.1", features = ["static_secrets"] }
|
||||
zbus = "5.1.1"
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
procfs = "0.18.0"
|
||||
pty-process = "0.5.1"
|
||||
|
||||
[profile.test]
|
||||
opt-level = 3
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 3
|
||||
|
||||
[profile.dev.package.backtrace]
|
||||
opt-level = 3
|
||||
|
||||
[profile.dev.package.sqlx-macros]
|
||||
opt-level = 3
|
||||
3
core/startos/Effects.ts
Normal file
3
core/startos/Effects.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface SetStoreParams { value: any, path: string, }
|
||||
@@ -0,0 +1,7 @@
|
||||
# Seeds for failure cases proptest has generated in the past. It is
|
||||
# automatically read and these particular cases re-run before any
|
||||
# novel cases are generated.
|
||||
#
|
||||
# It is recommended to check this file in to source control so that
|
||||
# everyone who runs the test benefits from these saved cases.
|
||||
cc dbb4790c31f9e400ed29a9ba2dbd61e3c55ce8a3fbae16601ca3512e803020ed # shrinks to files = []
|
||||
@@ -184,11 +184,7 @@ async fn cli_login<C: SessionAuthContext>(
|
||||
where
|
||||
CliContext: CallRemote<C>,
|
||||
{
|
||||
let password = if let Ok(password) = std::env::var("PASSWORD") {
|
||||
password
|
||||
} else {
|
||||
rpassword::prompt_password("Password: ")?
|
||||
};
|
||||
let password = rpassword::prompt_password("Password: ")?;
|
||||
|
||||
ctx.call_remote::<C>(
|
||||
&parent_method.into_iter().chain(method).join("."),
|
||||
@@ -11,89 +11,67 @@ pub mod startd;
|
||||
pub mod tunnel;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MultiExecutable {
|
||||
default: Option<&'static str>,
|
||||
bins: BTreeMap<&'static str, fn(VecDeque<OsString>)>,
|
||||
}
|
||||
pub struct MultiExecutable(BTreeMap<&'static str, fn(VecDeque<OsString>)>);
|
||||
impl MultiExecutable {
|
||||
pub fn enable_startd(&mut self) -> &mut Self {
|
||||
self.bins.insert("startd", startd::main);
|
||||
self.bins
|
||||
self.0.insert("startd", startd::main);
|
||||
self.0
|
||||
.insert("embassyd", |_| deprecated::renamed("embassyd", "startd"));
|
||||
self.bins
|
||||
self.0
|
||||
.insert("embassy-init", |_| deprecated::removed("embassy-init"));
|
||||
self
|
||||
}
|
||||
pub fn enable_start_cli(&mut self) -> &mut Self {
|
||||
self.bins.insert("start-cli", start_cli::main);
|
||||
self.bins.insert("embassy-cli", |_| {
|
||||
self.0.insert("start-cli", start_cli::main);
|
||||
self.0.insert("embassy-cli", |_| {
|
||||
deprecated::renamed("embassy-cli", "start-cli")
|
||||
});
|
||||
self.bins
|
||||
self.0
|
||||
.insert("embassy-sdk", |_| deprecated::removed("embassy-sdk"));
|
||||
self
|
||||
}
|
||||
pub fn enable_start_container(&mut self) -> &mut Self {
|
||||
self.bins.insert("start-container", container_cli::main);
|
||||
self.0.insert("start-container", container_cli::main);
|
||||
self
|
||||
}
|
||||
pub fn enable_start_registryd(&mut self) -> &mut Self {
|
||||
self.bins.insert("start-registryd", registry::main);
|
||||
self.0.insert("start-registryd", registry::main);
|
||||
self
|
||||
}
|
||||
pub fn enable_start_registry(&mut self) -> &mut Self {
|
||||
self.bins.insert("start-registry", registry::cli);
|
||||
self.0.insert("start-registry", registry::cli);
|
||||
self
|
||||
}
|
||||
pub fn enable_start_tunneld(&mut self) -> &mut Self {
|
||||
self.bins.insert("start-tunneld", tunnel::main);
|
||||
self.0.insert("start-tunneld", tunnel::main);
|
||||
self
|
||||
}
|
||||
pub fn enable_start_tunnel(&mut self) -> &mut Self {
|
||||
self.bins.insert("start-tunnel", tunnel::cli);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_default(&mut self, name: &str) -> &mut Self {
|
||||
if let Some((name, _)) = self.bins.get_key_value(name) {
|
||||
self.default = Some(*name);
|
||||
} else {
|
||||
panic!("{name} does not exist in MultiExecutable");
|
||||
}
|
||||
self.0.insert("start-tunnel", tunnel::cli);
|
||||
self
|
||||
}
|
||||
|
||||
fn select_executable(&self, name: &str) -> Option<fn(VecDeque<OsString>)> {
|
||||
self.bins.get(&name).copied()
|
||||
self.0.get(&name).copied()
|
||||
}
|
||||
|
||||
pub fn execute(&self) {
|
||||
let mut popped = Vec::with_capacity(2);
|
||||
let mut args = std::env::args_os().collect::<VecDeque<_>>();
|
||||
|
||||
for _ in 0..2 {
|
||||
if let Some(s) = args.pop_front() {
|
||||
if let Some(name) = Path::new(&*s).file_name().and_then(|s| s.to_str()) {
|
||||
if name == "--contents" {
|
||||
for name in self.bins.keys() {
|
||||
for name in self.0.keys() {
|
||||
println!("{name}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if let Some(x) = self.select_executable(&name) {
|
||||
args.push_front(s);
|
||||
return x(args);
|
||||
}
|
||||
}
|
||||
popped.push(s);
|
||||
}
|
||||
}
|
||||
if let Some(default) = self.default {
|
||||
while let Some(arg) = popped.pop() {
|
||||
args.push_front(arg);
|
||||
}
|
||||
return self.bins[default](args);
|
||||
}
|
||||
let args = std::env::args().collect::<VecDeque<_>>();
|
||||
eprintln!(
|
||||
"unknown executable: {}",
|
||||
@@ -7,7 +7,6 @@ use std::sync::Arc;
|
||||
use cookie::{Cookie, Expiration, SameSite};
|
||||
use cookie_store::CookieStore;
|
||||
use http::HeaderMap;
|
||||
use imbl::OrdMap;
|
||||
use imbl_value::InternedString;
|
||||
use josekit::jwk::Jwk;
|
||||
use once_cell::sync::OnceCell;
|
||||
@@ -239,16 +238,10 @@ impl CliContext {
|
||||
where
|
||||
Self: CallRemote<RemoteContext>,
|
||||
{
|
||||
<Self as CallRemote<RemoteContext, Empty>>::call_remote(
|
||||
&self,
|
||||
method,
|
||||
OrdMap::new(),
|
||||
params,
|
||||
Empty {},
|
||||
)
|
||||
.await
|
||||
.map_err(Error::from)
|
||||
.with_ctx(|e| (e.kind, method))
|
||||
<Self as CallRemote<RemoteContext, Empty>>::call_remote(&self, method, params, Empty {})
|
||||
.await
|
||||
.map_err(Error::from)
|
||||
.with_ctx(|e| (e.kind, method))
|
||||
}
|
||||
pub async fn call_remote_with<RemoteContext, T>(
|
||||
&self,
|
||||
@@ -259,16 +252,10 @@ impl CliContext {
|
||||
where
|
||||
Self: CallRemote<RemoteContext, T>,
|
||||
{
|
||||
<Self as CallRemote<RemoteContext, T>>::call_remote(
|
||||
&self,
|
||||
method,
|
||||
OrdMap::new(),
|
||||
params,
|
||||
extra,
|
||||
)
|
||||
.await
|
||||
.map_err(Error::from)
|
||||
.with_ctx(|e| (e.kind, method))
|
||||
<Self as CallRemote<RemoteContext, T>>::call_remote(&self, method, params, extra)
|
||||
.await
|
||||
.map_err(Error::from)
|
||||
.with_ctx(|e| (e.kind, method))
|
||||
}
|
||||
}
|
||||
impl AsRef<Jwk> for CliContext {
|
||||
@@ -305,13 +292,7 @@ impl AsRef<Client> for CliContext {
|
||||
}
|
||||
|
||||
impl CallRemote<RpcContext> for CliContext {
|
||||
async fn call_remote(
|
||||
&self,
|
||||
method: &str,
|
||||
_: OrdMap<&'static str, Value>,
|
||||
params: Value,
|
||||
_: Empty,
|
||||
) -> Result<Value, RpcError> {
|
||||
async fn call_remote(&self, method: &str, params: Value, _: Empty) -> Result<Value, RpcError> {
|
||||
if let Ok(local) = read_file_to_string(RpcContext::LOCAL_AUTH_COOKIE_PATH).await {
|
||||
self.cookie_store
|
||||
.lock()
|
||||
@@ -338,13 +319,7 @@ impl CallRemote<RpcContext> for CliContext {
|
||||
}
|
||||
}
|
||||
impl CallRemote<DiagnosticContext> for CliContext {
|
||||
async fn call_remote(
|
||||
&self,
|
||||
method: &str,
|
||||
_: OrdMap<&'static str, Value>,
|
||||
params: Value,
|
||||
_: Empty,
|
||||
) -> Result<Value, RpcError> {
|
||||
async fn call_remote(&self, method: &str, params: Value, _: Empty) -> Result<Value, RpcError> {
|
||||
crate::middleware::auth::signature::call_remote(
|
||||
self,
|
||||
self.rpc_url.clone(),
|
||||
@@ -357,13 +332,7 @@ impl CallRemote<DiagnosticContext> for CliContext {
|
||||
}
|
||||
}
|
||||
impl CallRemote<InitContext> for CliContext {
|
||||
async fn call_remote(
|
||||
&self,
|
||||
method: &str,
|
||||
_: OrdMap<&'static str, Value>,
|
||||
params: Value,
|
||||
_: Empty,
|
||||
) -> Result<Value, RpcError> {
|
||||
async fn call_remote(&self, method: &str, params: Value, _: Empty) -> Result<Value, RpcError> {
|
||||
crate::middleware::auth::signature::call_remote(
|
||||
self,
|
||||
self.rpc_url.clone(),
|
||||
@@ -376,13 +345,7 @@ impl CallRemote<InitContext> for CliContext {
|
||||
}
|
||||
}
|
||||
impl CallRemote<SetupContext> for CliContext {
|
||||
async fn call_remote(
|
||||
&self,
|
||||
method: &str,
|
||||
_: OrdMap<&'static str, Value>,
|
||||
params: Value,
|
||||
_: Empty,
|
||||
) -> Result<Value, RpcError> {
|
||||
async fn call_remote(&self, method: &str, params: Value, _: Empty) -> Result<Value, RpcError> {
|
||||
crate::middleware::auth::signature::call_remote(
|
||||
self,
|
||||
self.rpc_url.clone(),
|
||||
@@ -395,13 +358,7 @@ impl CallRemote<SetupContext> for CliContext {
|
||||
}
|
||||
}
|
||||
impl CallRemote<InstallContext> for CliContext {
|
||||
async fn call_remote(
|
||||
&self,
|
||||
method: &str,
|
||||
_: OrdMap<&'static str, Value>,
|
||||
params: Value,
|
||||
_: Empty,
|
||||
) -> Result<Value, RpcError> {
|
||||
async fn call_remote(&self, method: &str, params: Value, _: Empty) -> Result<Value, RpcError> {
|
||||
crate::middleware::auth::signature::call_remote(
|
||||
self,
|
||||
self.rpc_url.clone(),
|
||||
@@ -15,7 +15,6 @@ use josekit::jwk::Jwk;
|
||||
use reqwest::{Client, Proxy};
|
||||
use rpc_toolkit::yajrc::RpcError;
|
||||
use rpc_toolkit::{CallRemote, Context, Empty};
|
||||
use tokio::process::Command;
|
||||
use tokio::sync::{RwLock, broadcast, oneshot, watch};
|
||||
use tokio::time::Instant;
|
||||
use tracing::instrument;
|
||||
@@ -27,10 +26,6 @@ use crate::context::config::ServerConfig;
|
||||
use crate::db::model::Database;
|
||||
use crate::db::model::package::TaskSeverity;
|
||||
use crate::disk::OsPartitionInfo;
|
||||
use crate::disk::mount::filesystem::bind::Bind;
|
||||
use crate::disk::mount::filesystem::block_dev::BlockDev;
|
||||
use crate::disk::mount::filesystem::{FileSystem, ReadOnly};
|
||||
use crate::disk::mount::guard::MountGuard;
|
||||
use crate::init::{InitResult, check_time_is_synchronized};
|
||||
use crate::install::PKG_ARCHIVE_DIR;
|
||||
use crate::lxc::LxcManager;
|
||||
@@ -46,14 +41,12 @@ use crate::rpc_continuations::{Guid, OpenAuthedContinuations, RpcContinuations};
|
||||
use crate::service::ServiceMap;
|
||||
use crate::service::action::update_tasks;
|
||||
use crate::service::effects::callbacks::ServiceCallbacks;
|
||||
use crate::service::effects::subcontainer::NVIDIA_OVERLAY_PATH;
|
||||
use crate::shutdown::Shutdown;
|
||||
use crate::util::Invoke;
|
||||
use crate::util::future::NonDetachingJoinHandle;
|
||||
use crate::util::io::{TmpDir, delete_file};
|
||||
use crate::util::io::delete_file;
|
||||
use crate::util::lshw::LshwDevice;
|
||||
use crate::util::sync::{SyncMutex, SyncRwLock, Watch};
|
||||
use crate::{ActionId, DATA_DIR, PLATFORM, PackageId};
|
||||
use crate::{ActionId, DATA_DIR, PackageId};
|
||||
|
||||
pub struct RpcContextSeed {
|
||||
is_closed: AtomicBool,
|
||||
@@ -174,124 +167,6 @@ impl RpcContext {
|
||||
init_net_ctrl.complete();
|
||||
tracing::info!("Initialized Net Controller");
|
||||
|
||||
if PLATFORM.ends_with("-nonfree") {
|
||||
if let Err(e) = Command::new("nvidia-smi")
|
||||
.invoke(ErrorKind::ParseSysInfo)
|
||||
.await
|
||||
{
|
||||
tracing::warn!("nvidia-smi: {e}");
|
||||
tracing::info!("The above warning can be ignored if no NVIDIA card is present");
|
||||
} else {
|
||||
async {
|
||||
let version: InternedString = String::from_utf8(
|
||||
Command::new("modinfo")
|
||||
.arg("-F")
|
||||
.arg("version")
|
||||
.arg("nvidia")
|
||||
.invoke(ErrorKind::ParseSysInfo)
|
||||
.await?,
|
||||
)?
|
||||
.trim()
|
||||
.into();
|
||||
|
||||
let nvidia_dir =
|
||||
Path::new("/media/startos/data/package-data/nvidia").join(&*version);
|
||||
|
||||
// Generate single squashfs with both debian and generic overlays
|
||||
let sqfs = nvidia_dir.join("container-overlay.squashfs");
|
||||
if tokio::fs::metadata(&sqfs).await.is_err() {
|
||||
let tmp = TmpDir::new().await?;
|
||||
|
||||
// Generate debian overlay (libs in /usr/lib/aarch64-linux-gnu/)
|
||||
let debian_dir = tmp.join("debian");
|
||||
tokio::fs::create_dir_all(&debian_dir).await?;
|
||||
// Create /etc/debian_version to trigger debian path detection
|
||||
tokio::fs::create_dir_all(debian_dir.join("etc")).await?;
|
||||
tokio::fs::write(debian_dir.join("etc/debian_version"), "").await?;
|
||||
let procfs = MountGuard::mount(
|
||||
&Bind::new("/proc"),
|
||||
debian_dir.join("proc"),
|
||||
ReadOnly,
|
||||
)
|
||||
.await?;
|
||||
Command::new("nvidia-container-cli")
|
||||
.arg("configure")
|
||||
.arg("--no-devbind")
|
||||
.arg("--no-cgroups")
|
||||
.arg("--utility")
|
||||
.arg("--compute")
|
||||
.arg("--graphics")
|
||||
.arg("--video")
|
||||
.arg(&debian_dir)
|
||||
.invoke(ErrorKind::Unknown)
|
||||
.await?;
|
||||
procfs.unmount(true).await?;
|
||||
// Run ldconfig to create proper symlinks for all NVIDIA libraries
|
||||
Command::new("ldconfig")
|
||||
.arg("-r")
|
||||
.arg(&debian_dir)
|
||||
.invoke(ErrorKind::Unknown)
|
||||
.await?;
|
||||
// Remove /etc/debian_version - it was only needed for nvidia-container-cli detection
|
||||
tokio::fs::remove_file(debian_dir.join("etc/debian_version")).await?;
|
||||
|
||||
// Generate generic overlay (libs in /usr/lib64/)
|
||||
let generic_dir = tmp.join("generic");
|
||||
tokio::fs::create_dir_all(&generic_dir).await?;
|
||||
// No /etc/debian_version - will use generic /usr/lib64 paths
|
||||
let procfs = MountGuard::mount(
|
||||
&Bind::new("/proc"),
|
||||
generic_dir.join("proc"),
|
||||
ReadOnly,
|
||||
)
|
||||
.await?;
|
||||
Command::new("nvidia-container-cli")
|
||||
.arg("configure")
|
||||
.arg("--no-devbind")
|
||||
.arg("--no-cgroups")
|
||||
.arg("--utility")
|
||||
.arg("--compute")
|
||||
.arg("--graphics")
|
||||
.arg("--video")
|
||||
.arg(&generic_dir)
|
||||
.invoke(ErrorKind::Unknown)
|
||||
.await?;
|
||||
procfs.unmount(true).await?;
|
||||
// Run ldconfig to create proper symlinks for all NVIDIA libraries
|
||||
Command::new("ldconfig")
|
||||
.arg("-r")
|
||||
.arg(&generic_dir)
|
||||
.invoke(ErrorKind::Unknown)
|
||||
.await?;
|
||||
|
||||
// Create squashfs with UID/GID mapping (avoids chown on readonly mounts)
|
||||
if let Some(p) = sqfs.parent() {
|
||||
tokio::fs::create_dir_all(p)
|
||||
.await
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, format!("mkdir -p {p:?}")))?;
|
||||
}
|
||||
Command::new("mksquashfs")
|
||||
.arg(&*tmp)
|
||||
.arg(&sqfs)
|
||||
.arg("-force-uid")
|
||||
.arg("100000")
|
||||
.arg("-force-gid")
|
||||
.arg("100000")
|
||||
.invoke(ErrorKind::Filesystem)
|
||||
.await?;
|
||||
tmp.unmount_and_delete().await?;
|
||||
}
|
||||
BlockDev::new(&sqfs)
|
||||
.mount(NVIDIA_OVERLAY_PATH, ReadOnly)
|
||||
.await?;
|
||||
|
||||
Ok::<_, Error>(())
|
||||
}
|
||||
.await
|
||||
.log_err();
|
||||
}
|
||||
}
|
||||
|
||||
let services = ServiceMap::default();
|
||||
let metrics_cache = Watch::<Option<crate::system::Metrics>>::new(None);
|
||||
let socks_proxy_url = format!("socks5h://{socks_proxy}");
|
||||
@@ -585,14 +460,8 @@ impl RpcContext {
|
||||
where
|
||||
Self: CallRemote<RemoteContext>,
|
||||
{
|
||||
<Self as CallRemote<RemoteContext, Empty>>::call_remote(
|
||||
&self,
|
||||
method,
|
||||
OrdMap::new(),
|
||||
params,
|
||||
Empty {},
|
||||
)
|
||||
.await
|
||||
<Self as CallRemote<RemoteContext, Empty>>::call_remote(&self, method, params, Empty {})
|
||||
.await
|
||||
}
|
||||
pub async fn call_remote_with<RemoteContext, T>(
|
||||
&self,
|
||||
@@ -603,14 +472,7 @@ impl RpcContext {
|
||||
where
|
||||
Self: CallRemote<RemoteContext, T>,
|
||||
{
|
||||
<Self as CallRemote<RemoteContext, T>>::call_remote(
|
||||
&self,
|
||||
method,
|
||||
OrdMap::new(),
|
||||
params,
|
||||
extra,
|
||||
)
|
||||
.await
|
||||
<Self as CallRemote<RemoteContext, T>>::call_remote(&self, method, params, extra).await
|
||||
}
|
||||
}
|
||||
impl AsRef<Client> for RpcContext {
|
||||
@@ -56,7 +56,8 @@ pub async fn restart(ctx: RpcContext, ControlParams { id }: ControlParams) -> Re
|
||||
.as_idx_mut(&id)
|
||||
.or_not_found(&id)?
|
||||
.as_status_info_mut()
|
||||
.restart()
|
||||
.as_desired_mut()
|
||||
.map_mutate(|s| Ok(s.restart()))
|
||||
})
|
||||
.await
|
||||
.result?;
|
||||
@@ -94,23 +94,7 @@ impl Public {
|
||||
..Default::default()
|
||||
},
|
||||
gateways: OrdMap::new(),
|
||||
acme: {
|
||||
let mut acme: BTreeMap<AcmeProvider, AcmeSettings> = Default::default();
|
||||
acme.insert(
|
||||
"letsencrypt".parse()?,
|
||||
AcmeSettings {
|
||||
contact: Vec::new(),
|
||||
},
|
||||
);
|
||||
#[cfg(feature = "dev")]
|
||||
acme.insert(
|
||||
"letsencrypt-staging".parse()?,
|
||||
AcmeSettings {
|
||||
contact: Vec::new(),
|
||||
},
|
||||
);
|
||||
acme
|
||||
},
|
||||
acme: BTreeMap::new(),
|
||||
dns: Default::default(),
|
||||
},
|
||||
status_info: ServerStatus {
|
||||
@@ -416,51 +416,6 @@ impl<T: Map> Model<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Map> Model<T>
|
||||
where
|
||||
T::Key: FromStr,
|
||||
Error: From<<T::Key as FromStr>::Err>,
|
||||
{
|
||||
/// Retains only the elements specified by the predicate.
|
||||
/// The predicate can mutate the values and returns whether to keep each entry.
|
||||
pub fn retain<F>(&mut self, mut f: F) -> Result<(), Error>
|
||||
where
|
||||
F: FnMut(&T::Key, &mut Model<T::Value>) -> Result<bool, Error>,
|
||||
{
|
||||
let mut to_remove = Vec::new();
|
||||
|
||||
match &mut self.value {
|
||||
Value::Object(o) => {
|
||||
for (k, v) in o.iter_mut() {
|
||||
let key = T::Key::from_str(&**k)?;
|
||||
if !f(&key, patch_db::ModelExt::value_as_mut(v))? {
|
||||
to_remove.push(k.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
v => {
|
||||
use serde::de::Error;
|
||||
return Err(patch_db::value::Error {
|
||||
source: patch_db::value::ErrorSource::custom(format!(
|
||||
"expected object found {v}"
|
||||
)),
|
||||
kind: patch_db::value::ErrorKind::Deserialization,
|
||||
}
|
||||
.into());
|
||||
}
|
||||
}
|
||||
|
||||
// Remove entries that didn't pass the filter
|
||||
if let Value::Object(o) = &mut self.value {
|
||||
for k in to_remove {
|
||||
o.remove(&k);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct JsonKey<T>(pub T);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user