From 58a72e0a1e189430af51e1c37abd33688e6559cc Mon Sep 17 00:00:00 2001 From: Nikolay Govorov Date: Tue, 17 Mar 2026 20:57:20 +0000 Subject: Rename Zorian to Recluse --- .github/workflows/build.yml | 8 +- .github/workflows/cla.yml | 2 +- .gitignore | 2 +- CLA.md | 4 +- Cargo.lock | 92 +- Cargo.toml | 2 +- README.md | 32 +- REUSE.toml | 14 +- crates/recluse/Cargo.toml | 66 + crates/recluse/build.rs | 13 + .../recluse/src/assets/apple-touch-icon.png | Bin 0 -> 715 bytes crates/recluse/src/assets/base.css | 128 ++ crates/recluse/src/assets/favicon-192.png | Bin 0 -> 715 bytes crates/recluse/src/assets/favicon-512.png | Bin 0 -> 2329 bytes crates/recluse/src/assets/favicon.ico | Bin 0 -> 32038 bytes crates/recluse/src/assets/favicon.svg | 4 + .../JetBrainsMono-Italic[wght].woff2 | Bin 0 -> 122452 bytes .../jetbrainsmono/JetBrainsMono[wght].woff2 | Bin 0 -> 113700 bytes .../recluse/src/assets/manifest.webmanifest | 8 + crates/recluse/src/assets/robots.txt | 5 + crates/recluse/src/config.rs | 627 +++++++++ crates/recluse/src/controller_backend.rs | 111 ++ crates/recluse/src/controller_web.rs | 486 +++++++ crates/recluse/src/main.rs | 567 ++++++++ crates/recluse/src/proxy.rs | 78 ++ crates/recluse/src/storage.rs | 1203 +++++++++++++++++ crates/recluse/src/telemetry.rs | 247 ++++ crates/repos/src/go.rs | 4 +- crates/zorian/Cargo.toml | 66 - crates/zorian/build.rs | 13 - crates/zorian/src/assets/apple-touch-icon.png | Bin 715 -> 0 bytes crates/zorian/src/assets/base.css | 128 -- crates/zorian/src/assets/favicon-192.png | Bin 715 -> 0 bytes crates/zorian/src/assets/favicon-512.png | Bin 2329 -> 0 bytes crates/zorian/src/assets/favicon.ico | Bin 32038 -> 0 bytes crates/zorian/src/assets/favicon.svg | 4 - .../JetBrainsMono-Italic[wght].woff2 | Bin 122452 -> 0 bytes .../jetbrainsmono/JetBrainsMono[wght].woff2 | Bin 113700 -> 0 bytes crates/zorian/src/assets/manifest.webmanifest | 8 - crates/zorian/src/assets/robots.txt | 5 - crates/zorian/src/config.rs | 627 --------- crates/zorian/src/controller_backend.rs | 111 -- crates/zorian/src/controller_web.rs | 486 ------- crates/zorian/src/main.rs | 567 -------- crates/zorian/src/proxy.rs | 78 -- crates/zorian/src/storage.rs | 1203 ----------------- crates/zorian/src/telemetry.rs | 247 ---- deny.toml | 2 +- nfpm.yaml | 24 +- pkg/recluse.service | 51 + pkg/recluse.toml | 59 + pkg/scripts/postinstall.sh | 4 +- pkg/scripts/preinstall.sh | 14 +- pkg/scripts/preremove.sh | 6 +- pkg/zorian.service | 51 - pkg/zorian.toml | 59 - tests/smoke/run-local.sh | 24 +- tests/smoke/src/main.rs | 36 +- xtask/src/main.rs | 2 +- 59 files changed, 3789 insertions(+), 3789 deletions(-) create mode 100644 crates/recluse/Cargo.toml create mode 100644 crates/recluse/build.rs create mode 100644 crates/recluse/src/assets/apple-touch-icon.png create mode 100644 crates/recluse/src/assets/base.css create mode 100644 crates/recluse/src/assets/favicon-192.png create mode 100644 crates/recluse/src/assets/favicon-512.png create mode 100644 crates/recluse/src/assets/favicon.ico create mode 100644 crates/recluse/src/assets/favicon.svg create mode 100644 crates/recluse/src/assets/jetbrainsmono/JetBrainsMono-Italic[wght].woff2 create mode 100644 crates/recluse/src/assets/jetbrainsmono/JetBrainsMono[wght].woff2 create mode 100644 crates/recluse/src/assets/manifest.webmanifest create mode 100644 crates/recluse/src/assets/robots.txt create mode 100644 crates/recluse/src/config.rs create mode 100644 crates/recluse/src/controller_backend.rs create mode 100644 crates/recluse/src/controller_web.rs create mode 100644 crates/recluse/src/main.rs create mode 100644 crates/recluse/src/proxy.rs create mode 100644 crates/recluse/src/storage.rs create mode 100644 crates/recluse/src/telemetry.rs delete mode 100644 crates/zorian/Cargo.toml delete mode 100644 crates/zorian/build.rs delete mode 100644 crates/zorian/src/assets/apple-touch-icon.png delete mode 100644 crates/zorian/src/assets/base.css delete mode 100644 crates/zorian/src/assets/favicon-192.png delete mode 100644 crates/zorian/src/assets/favicon-512.png delete mode 100644 crates/zorian/src/assets/favicon.ico delete mode 100644 crates/zorian/src/assets/favicon.svg delete mode 100644 crates/zorian/src/assets/jetbrainsmono/JetBrainsMono-Italic[wght].woff2 delete mode 100644 crates/zorian/src/assets/jetbrainsmono/JetBrainsMono[wght].woff2 delete mode 100644 crates/zorian/src/assets/manifest.webmanifest delete mode 100644 crates/zorian/src/assets/robots.txt delete mode 100644 crates/zorian/src/config.rs delete mode 100644 crates/zorian/src/controller_backend.rs delete mode 100644 crates/zorian/src/controller_web.rs delete mode 100644 crates/zorian/src/main.rs delete mode 100644 crates/zorian/src/proxy.rs delete mode 100644 crates/zorian/src/storage.rs delete mode 100644 crates/zorian/src/telemetry.rs create mode 100644 pkg/recluse.service create mode 100644 pkg/recluse.toml delete mode 100644 pkg/zorian.service delete mode 100644 pkg/zorian.toml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7e70498..e21f530 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -76,7 +76,7 @@ jobs: printf '%s' "$GPG_PRIVATE_KEY" > $SIGNING_PRIVATE_KEY chmod 600 $SIGNING_PRIVATE_KEY - PKG_VERSION=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[] | select(.name == "zorian") | .version') + PKG_VERSION=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[] | select(.name == "recluse") | .version') export VERSION="${PKG_VERSION}~dev.$(git log -1 --format=%ct)" export ARCH=${{ matrix.arch }} @@ -182,9 +182,9 @@ jobs: # Update APT/RPM repos on s3 - name: Create APT repository run: | - aptly repo create -distribution=dev -component=main zorian - aptly repo add zorian dist/*.deb - aptly publish repo -architectures=amd64,arm64 -gpg-key="${{vars.GPG_KEY_ID}}" zorian + aptly repo create -distribution=dev -component=main recluse + aptly repo add recluse dist/*.deb + aptly publish repo -architectures=amd64,arm64 -gpg-key="${{vars.GPG_KEY_ID}}" recluse - name: Create RPM repository run: | mkdir -p rpm-repo diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 754514c..9430337 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -27,4 +27,4 @@ jobs: branch: "main" allowlist: mrdimidium path-to-signatures: "LICENSES/cla.json" - path-to-document: "https://github.com/mrdimidium/Zorian/blob/main/CLA.md" + path-to-document: "https://github.com/mrdimidium/recluse/blob/main/CLA.md" diff --git a/.gitignore b/.gitignore index 0575fa6..4d042ef 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ /target /dist -/.zorian-state +/.recluse-state diff --git a/CLA.md b/CLA.md index 03ff421..e1d891a 100644 --- a/CLA.md +++ b/CLA.md @@ -1,9 +1,9 @@ -# Zorian Grant and Contributor License Agreement +# Recluse Grant and Contributor License Agreement > This agreement is based on the Harmony Combined Contributor Agreement > Version 1.0 licensed under a [Creative Commons Attribution 3.0 Unported License](http://creativecommons.org/licenses/by/3.0/). -Thank you for your interest in contributing to Zorian ("We" or "Us"). In order +Thank you for your interest in contributing to Recluse ("We" or "Us"). In order to clarify the intellectual property license granted with Contributions from any person or entity, We must have a Contributor License Agreement ("CLA") on file that has been signed, accepted or otherwise agreed to by each contributor, diff --git a/Cargo.lock b/Cargo.lock index ee96265..5f7264a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1967,6 +1967,52 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "recluse" +version = "0.1.0" +dependencies = [ + "async-trait", + "axum", + "axum-server", + "base", + "bytes", + "bytesize", + "chrono", + "crc32fast", + "hex", + "http-body-util", + "hyper", + "hyper-tls", + "hyper-util", + "maud", + "opentelemetry", + "opentelemetry-appender-tracing", + "opentelemetry-otlp", + "opentelemetry-semantic-conventions", + "opentelemetry_sdk", + "repos", + "rustls", + "sd-notify", + "serde", + "serde_json", + "sqlx", + "tempfile", + "thiserror 2.0.18", + "tokio", + "tokio-util", + "toml", + "tonic", + "tower", + "tower-http", + "tower_governor", + "tracing", + "tracing-opentelemetry", + "tracing-subscriber", + "url", + "uuid", + "xtask", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -3846,52 +3892,6 @@ version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ff05f8caa9038894637571ae6b9e29466c1f4f829d26c9b28f869a29cbe3445" -[[package]] -name = "zorian" -version = "0.1.0" -dependencies = [ - "async-trait", - "axum", - "axum-server", - "base", - "bytes", - "bytesize", - "chrono", - "crc32fast", - "hex", - "http-body-util", - "hyper", - "hyper-tls", - "hyper-util", - "maud", - "opentelemetry", - "opentelemetry-appender-tracing", - "opentelemetry-otlp", - "opentelemetry-semantic-conventions", - "opentelemetry_sdk", - "repos", - "rustls", - "sd-notify", - "serde", - "serde_json", - "sqlx", - "tempfile", - "thiserror 2.0.18", - "tokio", - "tokio-util", - "toml", - "tonic", - "tower", - "tower-http", - "tower_governor", - "tracing", - "tracing-opentelemetry", - "tracing-subscriber", - "url", - "uuid", - "xtask", -] - [[package]] name = "zstd" version = "0.13.3" diff --git a/Cargo.toml b/Cargo.toml index d073fdc..7b1d537 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ version = "0.1.0" license = "AGPL-3.0-or-later" authors = ["Nikolay Govorov "] homepage = "https://pkg.earth" -repository = "https://github.com/mrdimidium/Zorian" +repository = "https://github.com/mrdimidium/recluse" [workspace.dependencies] # local dependencies diff --git a/README.md b/README.md index 3e75d70..ff9ac52 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Zorian — tiny packages caching proxy +# Recluse — tiny packages caching proxy Soon humanity will go to Mars and in order for the colonists to be able to program, we will need a local mirror of packages. @@ -13,21 +13,21 @@ is **not** intended for production use. ```bash sudo apt install curl gnupg -curl -fsSL https://github.com/mrdimidium/Zorian/releases/download/dev/public.gpg | sudo gpg --dearmor -o /usr/share/keyrings/zorian.gpg -echo "deb [signed-by=/usr/share/keyrings/zorian.gpg] https://zorian.hel1.your-objectstorage.com/apt/ dev main" | sudo tee /etc/apt/sources.list.d/zorian.list -sudo apt update && sudo apt install zorian +curl -fsSL https://github.com/mrdimidium/recluse/releases/download/dev/public.gpg | sudo gpg --dearmor -o /usr/share/keyrings/recluse.gpg +echo "deb [signed-by=/usr/share/keyrings/recluse.gpg] https://recluse.hel1.your-objectstorage.com/apt/ dev main" | sudo tee /etc/apt/sources.list.d/recluse.list +sudo apt update && sudo apt install recluse -sudo systemctl enable --now zorian +sudo systemctl enable --now recluse ``` **Fedora/RedHat:** ```bash -sudo rpm --import https://github.com/mrdimidium/Zorian/releases/download/dev/public.gpg -sudo dnf config-manager --add-repo https://zorian.hel1.your-objectstorage.com/rpm/ -sudo dnf install zorian +sudo rpm --import https://github.com/mrdimidium/recluse/releases/download/dev/public.gpg +sudo dnf config-manager --add-repo https://recluse.hel1.your-objectstorage.com/rpm/ +sudo dnf install recluse -sudo systemctl enable --now zorian +sudo systemctl enable --now recluse ``` ## Build from source @@ -35,19 +35,19 @@ sudo systemctl enable --now zorian 1. Install build dependencies: - Fedora/RedHat: `sudo dnf install gcc openssl-devel pkg-config` - Debian/Ubuntu: `sudo apt install build-essential libssl-dev pkg-config` -1. Clone repo: `git clone https://github.com/mrdimidium/Zorian.git && cd Zorian` +1. Clone repo: `git clone https://github.com/mrdimidium/recluse.git && cd recluse` 1. Build from source: `cargo build --release` 1. Install manually ```bash - sudo groupadd --system zorian - sudo useradd --system --gid zorian --no-create-home --shell /usr/sbin/nologin zorian - sudo install -m 700 -o zorian ./pkg/zorian.toml /etc/ - sudo install -m 755 -o root ./pkg/zorian.service /usr/lib/systemd/system - sudo install -m 755 -o root target/release/zorian /usr/local/bin/ + sudo groupadd --system recluse + sudo useradd --system --gid recluse --no-create-home --shell /usr/sbin/nologin recluse + sudo install -m 700 -o recluse ./pkg/recluse.toml /etc/ + sudo install -m 755 -o root ./pkg/recluse.service /usr/lib/systemd/system + sudo install -m 755 -o root target/release/recluse /usr/local/bin/ ``` -1. start systemd service: `sudo systemctl enable --now zorian` +1. start systemd service: `sudo systemctl enable --now recluse` ## License diff --git a/REUSE.toml b/REUSE.toml index 105cb10..2f5e133 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -9,19 +9,19 @@ path = [ "pkg/*.svg", - "crates/zorian/src/assets/*.svg", - "crates/zorian/src/assets/*.ico", - "crates/zorian/src/assets/*.png", - "crates/zorian/src/assets/robots.txt", - "crates/zorian/src/assets/manifest.webmanifest", + "crates/recluse/src/assets/*.svg", + "crates/recluse/src/assets/*.ico", + "crates/recluse/src/assets/*.png", + "crates/recluse/src/assets/robots.txt", + "crates/recluse/src/assets/manifest.webmanifest", ] SPDX-FileCopyrightText = "2026 Nikolay Govorov " SPDX-License-Identifier = "AGPL-3.0-or-later" [[annotations]] path = [ - "crates/zorian/src/assets/jetbrainsmono/OFL.txt", - "crates/zorian/src/assets/jetbrainsmono/*.woff2", + "crates/recluse/src/assets/jetbrainsmono/OFL.txt", + "crates/recluse/src/assets/jetbrainsmono/*.woff2", ] SPDX-FileCopyrightText = "Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)" SPDX-License-Identifier = "OFL-1.1" diff --git a/crates/recluse/Cargo.toml b/crates/recluse/Cargo.toml new file mode 100644 index 0000000..0605867 --- /dev/null +++ b/crates/recluse/Cargo.toml @@ -0,0 +1,66 @@ +# SPDX-FileCopyrightText: 2026 Nikolay Govorov +# SPDX-License-Identifier: AGPL-3.0-or-later + +[package] +name = "recluse" +description = "recluse web-server and daemon" +version.workspace = true + +authors.workspace = true +edition.workspace = true +license.workspace = true +publish.workspace = true +homepage.workspace = true +repository.workspace = true + +[dependencies] +base.workspace = true +repos.workspace = true + +async-trait.workspace = true +axum.workspace = true +axum-server.workspace = true +bytes.workspace = true +bytesize.workspace = true +chrono.workspace = true +crc32fast.workspace = true +hex.workspace = true +http-body-util.workspace = true +hyper.workspace = true +hyper-tls.workspace = true +hyper-util.workspace = true +maud.workspace = true +rustls.workspace = true +serde.workspace = true +serde_json.workspace = true +sqlx.workspace = true +thiserror.workspace = true +tokio.workspace = true +tokio-util.workspace = true +toml.workspace = true +tonic.workspace = true +tower.workspace = true +tower-http.workspace = true +tower_governor.workspace = true +tracing.workspace = true +tracing-opentelemetry.workspace = true +tracing-subscriber.workspace = true +url.workspace = true +uuid.workspace = true + +# telemetry +opentelemetry.workspace = true +opentelemetry-appender-tracing.workspace = true +opentelemetry-otlp.workspace = true +opentelemetry-semantic-conventions.workspace = true +opentelemetry_sdk.workspace = true + +[target.'cfg(target_os = "linux")'.dependencies] +sd-notify.workspace = true + +[build-dependencies] +xtask = { path = "../../xtask" } +serde_json.workspace = true + +[dev-dependencies] +tempfile.workspace = true diff --git a/crates/recluse/build.rs b/crates/recluse/build.rs new file mode 100644 index 0000000..36e1cd6 --- /dev/null +++ b/crates/recluse/build.rs @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2026 Nikolay Govorov +// SPDX-License-Identifier: AGPL-3.0-or-later + +fn main() { + println!("cargo::rerun-if-changed=../../Cargo.lock"); + + let json = + xtask::licenses::generate_json("Cargo.toml").expect("failed to generate licenses JSON"); + + let out_dir = std::env::var("OUT_DIR").unwrap(); + std::fs::write(format!("{out_dir}/licenses.json"), json) + .expect("failed to write licenses.json"); +} diff --git a/crates/recluse/src/assets/apple-touch-icon.png b/crates/recluse/src/assets/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0f6bb614210c0d59ae108acd732f59175f0ce984 GIT binary patch literal 715 zcmeAS@N?(olHy`uVBq!ia0vp^2SAvE4M+yv$zcaloCO|{#S9G0-5|_ZdRqK9P*AeO zHKHUqKdq!Zu_%?Hyu4g5GcUV1Ik6yBFTW^#_B$IX1_q`GPZ!6KiaBrZZWKIZAj0Z+ zMj(K-H&DJekagyZhBMR7ybb#>Njf$Dw!~wm(Casu6Vwt1>0w|&_q-~O)tNQqfb-!aYo`|j+`@9U3o(;x_mjFxS^hH3c?nR}=fb(r>kV^z5- W|K3?~yAd!UGI+ZBxvX */ +/* SPDX-License-Identifier: AGPL-3.0-or-later */ + +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 100 700; + font-stretch: 100%; + font-display: swap; + src: url(./jetbrainsmono/JetBrainsMono[wght].woff2) format('woff2'); +} + +@font-face { + font-family: 'JetBrains Mono'; + font-style: italic; + font-weight: 100 700; + font-stretch: 100%; + font-display: swap; + src: url(./jetbrainsmono/JetBrainsMono-Italic[wght].woff2) format('woff2'); +} + +*, *::before, *::after { + box-sizing: border-box; +} + +:root { + line-height: 1.4; + font-family: 'JetBrains Mono', monospace; + color-scheme: light dark; + + --color-text: #222; + --color-bg: #fff; + --color-border: #222; + --color-code-bg: #818b981f; + --color-license-bg: antiquewhite; + --color-link: #0969da; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-text: #e0e0e0; + --color-bg: #1a1a1a; + --color-border: #555; + --color-code-bg: #ffffff12; + --color-license-bg: #2a2a2a; + --color-link: #58a6ff; + } +} + +html { + margin: 0; + padding: 0; +} + +body { + margin: 0 auto; + max-width: 80ch; + padding: 1.5em 2em; + color: var(--color-text); + background-color: var(--color-bg); +} + +code { + margin: 0; + padding: .2em .4em; + white-space: break-spaces; + background-color: var(--color-code-bg); +} + +h1, h2, h3, h4 { + margin: 1.5rem 0 0.5rem; + font-weight: 700; + line-height: 1.2; + text-wrap: balance; +} + +h1 { font-size: 2.25rem; line-height: 1.1; } +h2 { font-size: 1.5rem; } +h3 { font-size: 1.15rem; } +h4 { font-size: 1rem; } + +h1:first-child { margin-top: 0; } + +p, details { + margin: 1em 0; + text-wrap: pretty; +} + +table { + border-collapse: collapse; +} + +th, td { + padding: 7px 8px; + border: 2px solid var(--color-border); + text-align: start; + vertical-align: top; +} + +a { + color: var(--color-link); +} + +h3 a { + color: inherit; + text-decoration: none; +} + +h3 a:hover { + text-decoration: underline; +} + +.license { + margin: 1rem 0; +} + +.license-used-by { + margin-top: -10px; +} + +.license-text { + max-height: 280px; + overflow-y: scroll; + white-space: pre-wrap; + background-color: var(--color-license-bg); + border-left: 4px solid var(--color-border); + padding: 0.8em 1em; +} diff --git a/crates/recluse/src/assets/favicon-192.png b/crates/recluse/src/assets/favicon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..0f6bb614210c0d59ae108acd732f59175f0ce984 GIT binary patch literal 715 zcmeAS@N?(olHy`uVBq!ia0vp^2SAvE4M+yv$zcaloCO|{#S9G0-5|_ZdRqK9P*AeO zHKHUqKdq!Zu_%?Hyu4g5GcUV1Ik6yBFTW^#_B$IX1_q`GPZ!6KiaBrZZWKIZAj0Z+ zMj(K-H&DJekagyZhBMR7ybb#>Njf$Dw!~wm(Casu6Vwt1>0w|&_q-~O)tNQqfb-!aYo`|j+`@9U3o(;x_mjFxS^hH3c?nR}=fb(r>kV^z5- W|K3?~yAd!UGI+ZBxvX9gP2NHH*QEc0}645^s&_J(2a5eEU+ zgR>_yFE-eCG(E}fVa~LpWgk`v)U2GmJg)k^J;Q>h^;HZEAF6@YH?c4u|VWXxp&u`@U~q*k%;f%`@HGs3$)f8BN#jRaZIR zs*dMlP?zT+>h87;*|OLJ(g7FGTJB`?E){?S}AIBNGVtQO%)`N1FB?19Z122WQ%mvv4F FO#l|3Ajkj! literal 0 HcmV?d00001 diff --git a/crates/recluse/src/assets/favicon.ico b/crates/recluse/src/assets/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..093e50bda4580e7ef4100b9e057d2e8cc47b2936 GIT binary patch literal 32038 zcmeHPyKWRq5G@N!geD?_$&AU0wTVFPl1Hk84fHD-Mc=} zl)I>HS50s4s^+RyQ?GMQ&D7nCmenOXphJ4}h>~5<`$M8vM6_6}{Vys0HN{R(Z~bRP zZypmZmuvszCDF|bqLb8L7J1F0o?ERCdEUo;)N#w}B%k-em+E&rPU+wO_4)pgs60R45#@u})iF^% zsLwWk&MeYdrjtLfR#*Dq`IK(*!L{4ZXn#H<<2{V^F7esoWn15`7cX#vziq$p+`Mc& z|J{E6{QdF0XwCC_?pyJ-e$K~zt>2pGeB8IN&pVYj~}BjgRMB@uR-&zt8c!_U3t|S9$lkCOZG` zIXgSQE)T1pzCD=!Id>^mk^DVH`pT5vrt{}}il;}dO43pbJ@#rd-ZZE&oV7c$5m-AROm%SVpepyrABhPJF zQ{MAB_+^dd9(deJn7j_YSG|NI#lg?*w(2EbDb97n-&VcEE5)Ig+ilfLyi%O&hQF

R4Zc>LQa$i`TS-rAyti)fwd$1Wf!EtgdRpVXb%U=}XKOupthSZc ztKO;`{a$)nalmi2t-N0KR^90L($k6qeyeTe^{Th(M!%Pyz=^+ih#iO>h#iO>*r6TB zQuA+sZ1!XNol(Y_%U)a^Uu67EZL5wOq7NB=Q)_)*xBdBdTFZ2j+`qrmN`dDG>yyH( zE5DpL@eE=IVh3UeVh3UeVh3UeVh3UeVh3tFfbTX(wKdJ2u~FxSF3(wOSl}7e)--#@ zMx7hFJZG(8foD`()9e`=b#CbLoVA7po>6U0vuAA7xuMH*)*2RgMzuA~p0QEqhAz)p zYgphJ)z&n7#zvhRx;$sCVS#5~^9(9tf^?1f4Uc@yn)Jb;kehpvCOS%ysyz8;(iEH|; z`BCPSbXe!p`X$~`;+lSIev~;S9oG4@eu;OKxTfElA7xHShjl({zog46Zq+w;zt@}+ z&fNN~_>yj~xK-cW{a$lQICJZ_;!C={;#Pfg_j}DL;mobyiZAK*id*%~-S0K0gfqAP zz>nX3#ty^|#16y`#16y`#16y`#18EB4y4yR<8_(;Hv>o0v^9Hlnf^)q_q9g-dGJKP NdI0ybGrpSy{TrMyi)R1; literal 0 HcmV?d00001 diff --git a/crates/recluse/src/assets/favicon.svg b/crates/recluse/src/assets/favicon.svg new file mode 100644 index 0000000..ed7cc17 --- /dev/null +++ b/crates/recluse/src/assets/favicon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/crates/recluse/src/assets/jetbrainsmono/JetBrainsMono-Italic[wght].woff2 b/crates/recluse/src/assets/jetbrainsmono/JetBrainsMono-Italic[wght].woff2 new file mode 100644 index 0000000000000000000000000000000000000000..98adc803f58f81df8410f4ad433e46b773e1b8d5 GIT binary patch literal 122452 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 literal 0 HcmV?d00001 diff --git a/crates/recluse/src/assets/jetbrainsmono/JetBrainsMono[wght].woff2 b/crates/recluse/src/assets/jetbrainsmono/JetBrainsMono[wght].woff2 new file mode 100644 index 0000000000000000000000000000000000000000..4cd1413366e027b0929706deb3ac04baf7328526 GIT binary patch literal 113700 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 z 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 +// SPDX-License-Identifier: AGPL-3.0-or-later + +use std::collections::HashMap; +use std::fs; +use std::net::SocketAddr; +use std::path::{Path, PathBuf}; +use std::time::Duration; + +use bytesize::ByteSize; +use serde::Deserialize; +use thiserror::Error; +use tracing::info; + +use base::serde::{deserialize_duration, deserialize_listener_addr}; +use repos::{GoConfig, ZigConfig}; + +#[derive(Debug, Error)] +pub enum ConfigError { + #[error("failed to read config file: {0}")] + Io(#[from] std::io::Error), + + #[error("failed to parse config file: {0}")] + Parse(#[from] toml::de::Error), + + #[error("appname '{0}' contains invalid characters (only a-z, A-Z, 0-9, -, _ allowed)")] + InvalidAppname(String), + + #[error("dirname '{0}' does not exist")] + DirNotFound(PathBuf), + + #[error("dirname '{0}' is not a directory")] + NotADirectory(PathBuf), + + #[error("dirname '{0}' is not writable: {1}")] + NotWritable(PathBuf, std::io::Error), + + #[error("listener '{0}': tls_crt is set but tls_key is missing")] + TlsKeyMissing(SocketAddr), + + #[error("listener '{0}': tls_key is set but tls_crt is missing")] + TlsCrtMissing(SocketAddr), + + #[error("listener '{0}': TLS crtificate file not found: {1}")] + TlsCrtNotFound(SocketAddr, PathBuf), + + #[error("listener '{0}': TLS key file not found: {1}")] + TlsKeyNotFound(SocketAddr, PathBuf), +} + +#[derive(Debug, Clone, Deserialize)] +pub struct ServerConfig { + /// When receiving a SIGINT/SIGTERM signal, we will wait for the proposed timeout before terminating workers + #[serde(deserialize_with = "deserialize_duration")] + pub shutdown_timeout: Duration, + + /// Request timeout - maximum time to process a request (protects against Slowloris) + #[serde(deserialize_with = "deserialize_duration")] + pub request_timeout: Duration, + + /// Maximum request body size + pub max_body_size: ByteSize, + + /// Maximum number of concurrent requests across all clients + pub max_concurrent_requests: usize, + + /// Rate limit: requests per second per client IP + #[serde(deserialize_with = "deserialize_duration")] + pub rate_limit_period: Duration, + + /// Rate limit: burst size (max requests allowed in a burst) per client IP + pub rate_limit_burst_size: u32, +} + +impl Default for ServerConfig { + fn default() -> Self { + Self { + shutdown_timeout: Duration::from_secs(60), + request_timeout: Duration::from_secs(30), + max_body_size: ByteSize::mb(64), + max_concurrent_requests: 512, + rate_limit_period: Duration::from_secs(10), + rate_limit_burst_size: 50, + } + } +} + +#[derive(Debug, Clone, Deserialize)] +pub struct ListenerConfig { + #[serde(deserialize_with = "deserialize_listener_addr")] + pub addr: SocketAddr, + + /// Hostnames to accept for this listener. Empty means accept all. + pub hostnames: Vec, + + /// Path to TLS certificate file (PEM format). If set, tls_key must also be set. + pub tls_crt: Option, + + /// Path to TLS private key file (PEM format). If set, tls_crt must also be set. + pub tls_key: Option, +} + +impl Default for ListenerConfig { + fn default() -> Self { + Self { + addr: "127.0.0.1:2025".parse().unwrap(), + hostnames: vec![ + String::from("[::1]"), + String::from("127.0.0.1"), + String::from("localhost"), + ], + tls_crt: None, + tls_key: None, + } + } +} + +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq, PartialOrd, Ord)] +#[serde(rename_all = "lowercase")] +pub enum LogLevel { + Trace, + Debug, + Info, + Warning, + Error, +} + +#[derive(Debug, Clone, Copy, Deserialize, Default, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +pub enum StdoutFormat { + #[default] + Pretty, + Json, +} + +#[derive(Debug, Clone, Deserialize)] +#[serde(default)] +pub struct StdoutConfig { + /// Enables sending logs to the stdout + pub enabled: bool, + + /// Controls which logs will be sent to stdout + pub log_level: LogLevel, + + /// Controls the format of logs in stdout + pub log_format: StdoutFormat, +} + +impl Default for StdoutConfig { + fn default() -> Self { + Self { + enabled: true, + log_level: LogLevel::Info, + log_format: StdoutFormat::Pretty, + } + } +} + +#[derive(Debug, Clone, Deserialize)] +#[serde(default)] +pub struct OtelcolConfig { + /// Enables sending telemetry to the otlp collector + pub enabled: bool, + + /// Send logs to OTLP at this level (None = disabled) + pub logs: bool, + + /// Send traces to OTLP + pub traces: bool, + + /// Send traces to OTLP + pub metrics: bool, + + /// OTLP endpoint (grpc:// or http://) + pub endpoint: String, + + /// Export timeout in seconds + #[serde(deserialize_with = "deserialize_duration")] + pub timeout: Duration, + + /// Controls which logs will be sent to otlp + pub log_level: LogLevel, + + /// Path to CA certificate for TLS (required for grpcs://) + pub tls_ca: Option, + + /// Path to client certificate for mTLS + pub tls_crt: Option, + + /// Path to client key for mTLS + pub tls_key: Option, + + /// HTTP headers for authentication + pub headers: HashMap, +} + +impl Default for OtelcolConfig { + fn default() -> Self { + Self { + enabled: true, + logs: true, + traces: true, + metrics: true, + timeout: Duration::from_secs(10), + endpoint: "http://localhost:4317".into(), + log_level: LogLevel::Info, + tls_ca: None, + tls_crt: None, + tls_key: None, + headers: HashMap::new(), + } + } +} + +#[derive(Debug, Clone, Deserialize, Default)] +#[serde(default)] +pub struct TelemetryConfig { + pub stdout: StdoutConfig, + pub otelcol: Option, +} + +#[derive(Debug, Clone, Deserialize, Default)] +#[serde(default)] +pub struct BackendsConfig { + pub go: GoConfig, + pub zig: ZigConfig, +} + +#[derive(Debug, Deserialize)] +#[serde(default)] +pub struct ConfigService { + appname: String, + dirname: PathBuf, + listen: Vec, + server: ServerConfig, + telemetry: TelemetryConfig, + backends: BackendsConfig, +} + +impl Default for ConfigService { + fn default() -> Self { + Self { + appname: "recluse".to_string(), + dirname: PathBuf::from("./.recluse-state"), + listen: vec![ListenerConfig::default()], + server: ServerConfig::default(), + telemetry: TelemetryConfig::default(), + backends: BackendsConfig::default(), + } + } +} + +impl ConfigService { + pub fn load(config_path: Option) -> Result { + let config = match config_path { + Some(path) => { + info!("use config file from {}", path.to_str().unwrap()); + + let content = fs::read_to_string(path)?; + toml::from_str(&content)? + } + None => { + info!("configuration file path not provided"); + Self::default() + } + }; + + config.validate() + } + + fn validate(self) -> Result { + let mut chars = self.appname.chars(); + if !chars.all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_') { + return Err(ConfigError::InvalidAppname(self.appname.clone())); + } + + let metadata = fs::metadata(&self.dirname).map_err(|e| { + if e.kind() == std::io::ErrorKind::NotFound { + ConfigError::DirNotFound(self.dirname.clone()) + } else { + ConfigError::Io(e) + } + })?; + + if !metadata.is_dir() { + return Err(ConfigError::NotADirectory(self.dirname.clone())); + } + + let testfile = self.dirname.join(".health"); + fs::write(&testfile, std::process::id().to_string()) + .map_err(|e| ConfigError::NotWritable(self.dirname.clone(), e))?; + fs::remove_file(&testfile)?; + + // Validate listener configuration + for listener in &self.listen { + match (&listener.tls_crt, &listener.tls_key) { + (Some(_crt), None) => { + return Err(ConfigError::TlsKeyMissing(listener.addr)); + } + (None, Some(_)) => { + return Err(ConfigError::TlsCrtMissing(listener.addr)); + } + (Some(crt), Some(key)) => { + if !crt.exists() { + return Err(ConfigError::TlsCrtNotFound(listener.addr, crt.clone())); + } + if !key.exists() { + return Err(ConfigError::TlsKeyNotFound(listener.addr, key.clone())); + } + } + (None, None) => {} + } + } + + Ok(self) + } + + pub fn appname(&self) -> &str { + &self.appname + } + + pub fn dirname(&self) -> &Path { + &self.dirname + } + + pub fn server(&self) -> &ServerConfig { + &self.server + } + + pub fn listeners(&self) -> &[ListenerConfig] { + &self.listen + } + + pub fn telemetry(&self) -> &TelemetryConfig { + &self.telemetry + } + + pub fn backends(&self) -> &BackendsConfig { + &self.backends + } +} + +#[cfg(test)] +impl ConfigService { + pub fn for_test(dirname: PathBuf) -> Self { + Self { + appname: "test".to_string(), + dirname, + server: ServerConfig::default(), + listen: vec![ListenerConfig { + addr: "127.0.0.1:0".parse().unwrap(), + hostnames: Vec::new(), + tls_crt: None, + tls_key: None, + }], + telemetry: TelemetryConfig::default(), + backends: BackendsConfig::default(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::TempDir; + + fn base_config(dir: PathBuf) -> ConfigService { + ConfigService { + appname: "valid-name".to_string(), + dirname: dir, + server: ServerConfig::default(), + listen: vec![ListenerConfig { + addr: "127.0.0.1:0".parse().unwrap(), + hostnames: Vec::new(), + tls_crt: None, + tls_key: None, + }], + telemetry: TelemetryConfig::default(), + backends: BackendsConfig::default(), + } + } + + fn write_temp_file(dir: &Path, name: &str) -> PathBuf { + let path = dir.join(name); + std::fs::write(&path, "x").unwrap(); + path + } + + mod defaults_tests { + use super::*; + + #[test] + fn test_for_test_config() { + let dir = TempDir::new().unwrap(); + let cfg = ConfigService::for_test(dir.path().to_path_buf()); + assert_eq!(cfg.appname(), "test"); + assert_eq!(cfg.dirname(), dir.path()); + } + + #[test] + fn test_listener_default() { + let cfg = ListenerConfig::default(); + assert!(cfg.hostnames.contains(&"localhost".to_string())); + } + } + + mod load_tests { + use super::*; + + #[test] + fn test_load_none_defaults() { + let temp = TempDir::new().unwrap(); + let state = temp.path().join(".recluse-state"); + std::fs::create_dir_all(&state).unwrap(); + let cwd = std::env::current_dir().unwrap(); + std::env::set_current_dir(temp.path()).unwrap(); + + let cfg = ConfigService::load(None).unwrap(); + assert_eq!(cfg.appname(), "recluse"); + + std::env::set_current_dir(cwd).unwrap(); + } + + #[test] + fn test_load_some_and_parse_error() { + let dir = TempDir::new().unwrap(); + let good = dir.path().join("good.toml"); + let bad = dir.path().join("bad.toml"); + let missing = dir.path().join("missing.toml"); + let state = dir.path().join("state"); + std::fs::create_dir_all(&state).unwrap(); + + std::fs::write( + &good, + format!( + "appname = \"ok\"\n\ + dirname = \"{}\"\n\ + listen = []\n\ + [server]\n\ + shutdown_timeout = 1\n\ + request_timeout = 1\n\ + max_body_size = \"1 MB\"\n\ + max_concurrent_requests = 1\n\ + rate_limit_period = 1\n\ + rate_limit_burst_size = 1\n\ + [telemetry]\n\ + [telemetry.stdout]\n\ + enabled = true\n\ + log_level = \"info\"\n\ + log_format = \"pretty\"\n\ + [backends]\n\ + [backends.go]\n\ + [backends.zig]\n", + state.display() + ), + ) + .unwrap(); + + std::fs::write(&bad, "not = [valid").unwrap(); + + let cfg = ConfigService::load(Some(good)).unwrap(); + assert_eq!(cfg.appname(), "ok"); + + let err = ConfigService::load(Some(missing)).unwrap_err(); + assert!(err.to_string().contains("failed to read")); + + let err = ConfigService::load(Some(bad)).unwrap_err(); + assert!(err.to_string().contains("failed to parse")); + } + } + + mod validation_tests { + use super::*; + + #[test] + fn test_validate_invalid_appname() { + let dir = TempDir::new().unwrap(); + let mut cfg = base_config(dir.path().to_path_buf()); + cfg.appname = "bad name!".to_string(); + let err = cfg.validate().unwrap_err(); + assert!(err.to_string().contains("appname 'bad name!'")); + } + + #[test] + fn test_validate_dir_not_found() { + let temp = TempDir::new().unwrap(); + let missing = temp.path().join("missing-dir"); + let cfg = base_config(missing); + let err = cfg.validate().unwrap_err(); + assert!(err.to_string().contains("does not exist")); + } + + #[test] + fn test_validate_not_a_directory() { + let dir = TempDir::new().unwrap(); + let file_path = dir.path().join("file"); + std::fs::write(&file_path, "x").unwrap(); + let cfg = base_config(file_path); + let err = cfg.validate().unwrap_err(); + assert!(err.to_string().contains("is not a directory")); + } + + #[cfg(unix)] + #[test] + fn test_validate_metadata_io_error() { + use std::os::unix::fs::PermissionsExt; + + let dir = TempDir::new().unwrap(); + let child = dir.path().join("child"); + std::fs::create_dir_all(&child).unwrap(); + + let mut perms = std::fs::metadata(dir.path()).unwrap().permissions(); + perms.set_mode(0o000); + std::fs::set_permissions(dir.path(), perms).unwrap(); + + let cfg = base_config(child.clone()); + let err = cfg.validate().unwrap_err(); + assert!(err.to_string().contains("failed to read")); + + let mut perms = std::fs::metadata(dir.path()).unwrap().permissions(); + perms.set_mode(0o700); + std::fs::set_permissions(dir.path(), perms).unwrap(); + } + + #[cfg(unix)] + #[test] + fn test_validate_not_writable() { + use std::os::unix::fs::PermissionsExt; + + let dir = TempDir::new().unwrap(); + let mut perms = std::fs::metadata(dir.path()).unwrap().permissions(); + perms.set_mode(0o400); + std::fs::set_permissions(dir.path(), perms).unwrap(); + + let cfg = base_config(dir.path().to_path_buf()); + let err = cfg.validate().unwrap_err(); + assert!(err.to_string().contains("not writable")); + } + + #[test] + fn test_validate_tls_key_missing() { + let dir = TempDir::new().unwrap(); + let mut cfg = base_config(dir.path().to_path_buf()); + cfg.listen = vec![ListenerConfig { + addr: "127.0.0.1:0".parse().unwrap(), + hostnames: Vec::new(), + tls_crt: Some(PathBuf::from("/tmp/does-not-matter.crt")), + tls_key: None, + }]; + let err = cfg.validate().unwrap_err(); + assert!(err.to_string().contains("tls_key is missing")); + } + + #[test] + fn test_validate_tls_crt_missing() { + let dir = TempDir::new().unwrap(); + let mut cfg = base_config(dir.path().to_path_buf()); + cfg.listen = vec![ListenerConfig { + addr: "127.0.0.1:0".parse().unwrap(), + hostnames: Vec::new(), + tls_crt: None, + tls_key: Some(PathBuf::from("/tmp/does-not-matter.key")), + }]; + let err = cfg.validate().unwrap_err(); + assert!(err.to_string().contains("tls_crt is missing")); + } + + #[test] + fn test_validate_tls_files_not_found() { + let dir = TempDir::new().unwrap(); + let mut cfg = base_config(dir.path().to_path_buf()); + cfg.listen = vec![ListenerConfig { + addr: "127.0.0.1:0".parse().unwrap(), + hostnames: Vec::new(), + tls_crt: Some(PathBuf::from("/tmp/missing.crt")), + tls_key: Some(PathBuf::from("/tmp/missing.key")), + }]; + let err = cfg.validate().unwrap_err(); + assert!(err.to_string().contains("TLS crtificate file not found")); + } + + #[test] + fn test_validate_tls_key_not_found() { + let dir = TempDir::new().unwrap(); + let mut cfg = base_config(dir.path().to_path_buf()); + let crt = write_temp_file(dir.path(), "cert.pem"); + cfg.listen = vec![ListenerConfig { + addr: "127.0.0.1:0".parse().unwrap(), + hostnames: Vec::new(), + tls_crt: Some(crt), + tls_key: Some(dir.path().join("missing.key")), + }]; + let err = cfg.validate().unwrap_err(); + assert!(err.to_string().contains("TLS key file not found")); + } + + #[test] + fn test_validate_tls_files_exist() { + let dir = TempDir::new().unwrap(); + let mut cfg = base_config(dir.path().to_path_buf()); + let crt = write_temp_file(dir.path(), "cert.pem"); + let key = write_temp_file(dir.path(), "key.pem"); + cfg.listen = vec![ListenerConfig { + addr: "127.0.0.1:0".parse().unwrap(), + hostnames: Vec::new(), + tls_crt: Some(crt), + tls_key: Some(key), + }]; + cfg.validate().unwrap(); + } + + #[test] + fn test_validate_ok_and_getters() { + let dir = TempDir::new().unwrap(); + let mut cfg = base_config(dir.path().to_path_buf()); + cfg.listen = vec![ListenerConfig::default()]; + + let cfg = cfg.validate().unwrap(); + assert_eq!(cfg.appname(), "valid-name"); + assert_eq!(cfg.dirname(), dir.path()); + let _ = cfg.server(); + let _ = cfg.listeners(); + let _ = cfg.telemetry(); + let _ = cfg.backends(); + } + } +} diff --git a/crates/recluse/src/controller_backend.rs b/crates/recluse/src/controller_backend.rs new file mode 100644 index 0000000..d14d93b --- /dev/null +++ b/crates/recluse/src/controller_backend.rs @@ -0,0 +1,111 @@ +// SPDX-FileCopyrightText: 2026 Nikolay Govorov +// SPDX-License-Identifier: AGPL-3.0-or-later + +use std::sync::Arc; + +use axum::{Router, body, extract, http, response, routing}; +use tracing::error; + +use crate::proxy; +use crate::storage; +use repos::{Backend, BackendError, BackendSpec, ResolvedFile}; + +/// Generic controller for backend HTTP handling. +pub struct BackendController { + backend: Arc>, + storage: Arc, + upstream: Arc, +} + +impl BackendController { + pub fn new( + backend: Arc>, + storage: Arc, + upstream: Arc, + ) -> Self { + Self { + backend, + storage, + upstream, + } + } + + pub fn router(self: Arc) -> Router { + Router::new() + .route("/{filename}", routing::get(Self::handle)) + .with_state(self) + } + + async fn handle( + extract::State(controller): extract::State>, + extract::Path(filename): extract::Path, + ) -> Result { + let (url, mime) = match controller.backend.resolve_file(&filename).await { + Ok(ResolvedFile::Content { data, mime }) => { + return Ok(Self::build_response(http::StatusCode::OK, data, mime)); + } + Ok(ResolvedFile::Upstream { url, mime }) => (url, mime), + Err(BackendError::NotFound) => { + error!(backend = S::ID, filename, "file not found"); + return Err(http::StatusCode::NOT_FOUND); + } + Err(e) => { + error!(backend = S::ID, filename, "error resolving file: {e}"); + return Err(http::StatusCode::INTERNAL_SERVER_ERROR); + } + }; + + match controller.storage.get(S::ID, &filename).await { + Ok(Some(entry)) => { + return Ok(Self::build_response( + http::StatusCode::OK, + entry.file_bytes.0, + mime, + )); + } + Ok(None) => {} + Err(err) => { + error!( + backend = S::ID, + filename, "failed to get file from storage: {err}" + ); + return Err(http::StatusCode::INTERNAL_SERVER_ERROR); + } + } + + let entry = controller + .upstream + .fetch(proxy::DownloadRequest { url }) + .await?; + + match controller.storage.put(S::ID, &filename, &entry.bytes).await { + Ok(()) => {} + Err(err) => { + error!( + backend = S::ID, + filename, "failed to put file to storage: {err}" + ); + return Err(http::StatusCode::INTERNAL_SERVER_ERROR); + } + } + + Ok(Self::build_response( + http::StatusCode::OK, + entry.bytes, + mime, + )) + } + + fn build_response( + status: http::StatusCode, + bytes: bytes::Bytes, + mime: repos::ContentType, + ) -> response::Response { + response::Response::builder() + .status(status) + .header(http::header::CONTENT_TYPE, mime.as_str()) + .header(http::header::CONTENT_LENGTH, bytes.len()) + .body(body::Body::from(bytes)) + .unwrap() + } +} diff --git a/crates/recluse/src/controller_web.rs b/crates/recluse/src/controller_web.rs new file mode 100644 index 0000000..6d4d176 --- /dev/null +++ b/crates/recluse/src/controller_web.rs @@ -0,0 +1,486 @@ +// SPDX-FileCopyrightText: 2026 Nikolay Govorov +// SPDX-License-Identifier: AGPL-3.0-or-later + +use std::future::Future; +use std::pin::Pin; +use std::sync::{Arc, LazyLock}; +use std::task::{Context, Poll}; + +use axum::body::Body; +use axum::http::{HeaderValue, Method, Request, Response, StatusCode, header}; +use axum::{extract, routing}; +use maud::{Markup, html}; +use serde::Deserialize; +use tower::{Layer, Service}; +use tracing::error; + +use base::ContentType; +use repos::{GoBackend, ZigBackend}; + +fn get_asset(path: &str) -> Option<(&'static [u8], ContentType)> { + Some(match path { + "base.css" => (include_bytes!("assets/base.css"), ContentType::TextCss), + "favicon.svg" => ( + include_bytes!("assets/favicon.svg"), + ContentType::ImageSvgXml, + ), + "favicon.ico" => ( + include_bytes!("assets/favicon.ico"), + ContentType::ImageXIcon, + ), + "favicon-192.png" | "apple-touch-icon.png" => ( + include_bytes!("assets/favicon-192.png"), + ContentType::ImagePng, + ), + "favicon-512.png" => ( + include_bytes!("assets/favicon-512.png"), + ContentType::ImagePng, + ), + "manifest.webmanifest" => ( + include_bytes!("assets/manifest.webmanifest"), + ContentType::ApplicationManifestJson, + ), + "jetbrainsmono/JetBrainsMono[wght].woff2" => ( + include_bytes!("assets/jetbrainsmono/JetBrainsMono[wght].woff2"), + ContentType::FontWoff2, + ), + "jetbrainsmono/JetBrainsMono-Italic[wght].woff2" => ( + include_bytes!("assets/jetbrainsmono/JetBrainsMono-Italic[wght].woff2"), + ContentType::FontWoff2, + ), + "robots.txt" => (include_bytes!("assets/robots.txt"), ContentType::TextPlain), + _ => return None, + }) +} + +const CSP: &str = "default-src 'self'; base-uri 'none'; img-src 'self'; font-src 'self'; style-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none'"; + +#[derive(Deserialize)] +struct LicenseList { + overview: Vec, + licenses: Vec, +} + +#[derive(Deserialize)] +struct LicenseOverview { + id: String, + name: String, + count: usize, +} + +#[derive(Deserialize)] +struct LicenseEntry { + id: String, + name: String, + text: String, + first_of_kind: bool, + used_by: Vec, +} + +#[derive(Deserialize)] +struct LicenseUsedBy { + #[serde(rename = "crate")] + crate_: LicenseCrate, +} + +#[derive(Deserialize)] +#[allow(dead_code)] +struct LicenseCrate { + name: String, + version: String, + repository: Option, +} + +static LICENSES: LazyLock = LazyLock::new(|| { + let json = include_str!(concat!(env!("OUT_DIR"), "/licenses.json")); + serde_json::from_str(json).expect("failed to parse licenses.json") +}); + +/// Handles html pages rendering and static files +pub struct WebController { + zig: Option>, + go: Option>, +} + +impl WebController { + pub fn new(zig: Option>, go: Option>) -> Self { + Self { zig, go } + } +} + +impl WebController { + pub fn router(self: Arc) -> axum::Router { + axum::Router::new() + .route("/", axum::routing::get(Self::index)) + .route("/{*path}", routing::get(Self::assets)) + .route("/about/licenses", axum::routing::get(Self::licenses)) + .layer(CacheLayer) + .layer(tower_http::set_header::SetResponseHeaderLayer::overriding( + header::CONTENT_SECURITY_POLICY, + HeaderValue::from_static(CSP), + )) + .with_state(self.clone()) + } + + async fn assets(extract::Path(path): extract::Path) -> Response { + let Some((data, content_type)) = get_asset(&path) else { + return Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Body::empty()) + .unwrap(); + }; + + let mut builder = Response::builder() + .status(StatusCode::OK) + .header(header::CONTENT_TYPE, content_type.as_str()); + + if matches!(content_type, ContentType::FontWoff2) { + builder = builder.header(header::CACHE_CONTROL, "public, max-age=31536000, immutable"); + } + + builder.body(Body::from(data)).unwrap() + } + + async fn index(extract::State(ctrl): extract::State>) -> Markup { + let zig_versions = if let Some(ref backend) = ctrl.zig { + match backend.get_releases().await { + Ok(v) => v, + Err(e) => { + error!("failed to get zig versions: {e}"); + Vec::new() + } + } + } else { + Vec::new() + }; + + let go_versions = if let Some(ref backend) = ctrl.go { + match backend.get_releases().await { + Ok(v) => v, + Err(e) => { + error!("failed to get go versions: {e}"); + Vec::new() + } + } + } else { + Vec::new() + }; + + WebController::layout( + "Recluse — tiny & opinionated packages mirror", + html! { + h1 { "Recluse — tiny & opinionated packages mirror." } + + p { + r#"This site provides a caching proxy for downloading Zig and Go installation files. + It reduces load on upstream servers and makes your infrastructure more reliable by adding redundancy."# + } + + p { + "Recluse is open source software licensed under " a href="https://www.gnu.org/licenses/agpl-3.0.html" { "AGPL-3.0" } ". " + "Source code is available on " a href="https://github.com/mrdimidium/recluse" { "GitHub" } ". " + "A list of dependency licenses " a href="/about/licenses" { "is available" } "." + } + + h2 { "Usage" } + + p { + "Replace official download URLs with " code { "https://pkg.earth/{tool}/{filename}" } ". " + "Files are cached automatically after the first download." + } + + h3 id="zig" { + a href="#zig" { "Zig" } + } + + @if !zig_versions.is_empty() { + details { + summary { "Available versions (" (zig_versions.len()) ")" } + + p { "You can take actual minisig public key at " a href="https://ziglang.org/download/" { "ziglang.org/download" } "." } + table { + thead { + tr { + th { "Version" } + th { "Date" } + th { "Docs" } + th { "Targets" } + } + } + tbody { + @for v in zig_versions.iter().rev() { + tr { + td { (v.version) } + td { (v.meta.date.as_deref().unwrap_or("-")) } + td { + @if let Some(ref url) = v.meta.docs { + a href=(url) { "docs" } + } + " " + @if let Some(ref url) = v.meta.std_docs { + a href=(url) { "std" } + } + " " + @if let Some(ref url) = v.meta.notes { + a href=(url) { "notes" } + } + } + td { + @for file in &v.files { + a href=(format!("/zig/{}", file.filename)) { (&file.meta.target) } + " " + } + } + } + } + } + } + } + } + + p { + "Read more about community mirrors in the " a href="https://ziglang.org/download/community-mirrors/" { "blog post" } ". " + "Information on how to deploy your own mirror is available " a href="https://github.com/ziglang/www.ziglang.org/blob/main/MIRRORS.md" { "in the documentation" } "." + } + + p { + "For simplicity, you can use tools like " a href="https://github.com/prantlf/zigup" { "prantlf/zigup" } + " and " a href="https://github.com/mlugg/setup-zig" { "mlugg/setup-zig" } "." + } + + p { + "To install manually:" + ol { + li { "download zig dist file:" br; code { "wget https://pkg.earth/zig/zig-x86_64-linux-0.15.1.tar.xz" } ";" } + li { "download zig minisig file:" br; code { "wget https://pkg.earth/zig/zig-x86_64-linux-0.15.1.tar.xz.minisig" } ";" } + li { "check archive integrity:" br; code { "minisign -Vm zig-x86_64-linux-0.15.1.tar.xz -P RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U" } ";" } + li { "unpack archive:" br; code { "tar -xf 'zig-x86_64-linux-0.15.1.tar.xz'" } ";" } + li { "check installed zig:" br; code { "./zig-x86_64-linux-0.15.1/zig --version" } ";" } + } + } + + h3 id="go" { a href="#go" { "Go" } } + + @if !go_versions.is_empty() { + details { + summary { "Available versions (" (go_versions.len()) ")" } + + p { "You can find available versions at " a href="https://go.dev/dl/" { "go.dev/dl" } "." } + table { + thead { + tr { + th { "Version" } + th { "Stable" } + th { "Files" } + } + } + tbody { + @for v in go_versions.iter().rev() { + tr { + td { (v.version) } + td { @if v.meta.stable { "✓" } @else { "" } } + td { + @for file in &v.files { + a href=(format!("/go/{}", file.filename)) { (file.filename) } + " " + } + } + } + } + } + } + } + } + + p { "To install manually:" } + + ol { + li { "download go dist file:" br; code { "wget https://pkg.earth/go/go1.23.0.linux-amd64.tar.gz" } ";" } + li { "download go sha256 file:" br; code { "wget https://pkg.earth/go/go1.23.0.linux-amd64.tar.gz.sha256" } ";" } + li { "check archive integrity:" br; code { "sha256sum -c go1.23.0.linux-amd64.tar.gz.sha256" } ";" } + li { "unpack archive:" br; code { "tar -xzf go1.23.0.linux-amd64.tar.gz" } ";" } + li { "check installed go:" br; code { "./go/bin/go version" } ";" } + } + + h2 { "Privacy policy" } + + p { "This mirror is a non-profit project available on a voluntary basis. The author has no plans to fund it." } + + p { r#"Since the mirror is hosted on hardware, we collect access logs to combat bots and brute-force attacks. + The logs are used for security purposes and load planning, are not shared with third parties, + and are deleted after 30 days."# } + + p { "Third-party analytics systems are not used, same as client-side trackers." } + }, + ) + } + + async fn licenses() -> Markup { + let data = &*LICENSES; + + WebController::layout( + "Third Party Licenses", + html! { + h1 { "Licenses" } + + h2 { "Recluse" } + + p { + "Recluse is licensed under the " b { "GNU Affero General Public License v3.0 (AGPL-3.0)" } ". " + "This means you are free to use, modify, and distribute the software. " + "If you run a modified version of Recluse as a network service, " + "you must make the source code of your modifications available to its users. " + "The software is provided as-is, without warranty of any kind." + } + + p { + "Source code is available on " + a href="https://github.com/mrdimidium/recluse" { "GitHub" } + ". The full license text is included below." + } + + pre .license-text { (include_str!("../../../LICENSE")) } + + h2 { "Third party licenses" } + + ul { + @for ov in &data.overview { + li { a href=(format!("#{}", ov.id)) { (&ov.name) } " (" (ov.count) ")" } + } + } + + @for (i, lic) in data.licenses.iter().enumerate() { + @if lic.first_of_kind { + h3 id=(&lic.id) { (&lic.name) } + } + + section.license { + h4 id=(format!("{}-{}", lic.id, i)) { (&lic.name) } + + p { "Used by:" } + + ul .license-used-by { + @for usage in &lic.used_by { + li { + a href=( + usage.crate_.repository.as_deref() + .unwrap_or(&format!("https://crates.io/crates/{}", usage.crate_.name)) + ) { + (&usage.crate_.name) "@" (&usage.crate_.version) + } + } + } + } + + pre .license-text { (&lic.text) } + } + } + }, + ) + } + + fn layout(title: &str, content: Markup) -> Markup { + html! { + (maud::DOCTYPE) + + html lang="en" { + head { + meta charset="UTF-8"; + meta http-equiv="X-UA-Compatible" content="ie=edge"; + meta name="viewport" content="width=device-width,initial-scale=1"; + + title { (title) } + link rel="stylesheet" href="/base.css"; + + link rel="manifest" href="/manifest.webmanifest"; + link rel="icon" href="/favicon.ico" sizes="32x32"; + link rel="icon" href="/favicon.svg" type="image/svg+xml"; + link rel="apple-touch-icon" href="/apple-touch-icon.png"; + } + + body { + article { (content) } + } + } + } + } +} + +#[derive(Clone)] +struct CacheLayer; + +impl Layer for CacheLayer { + type Service = CacheService; + fn layer(&self, inner: S) -> Self::Service { + CacheService { inner } + } +} + +#[derive(Clone)] +struct CacheService { + inner: S, +} + +impl Service> for CacheService +where + S: Service, Response = Response> + Clone + Send + 'static, + S::Future: Send + 'static, + S::Error: Send + 'static, +{ + type Response = Response; + type Error = S::Error; + type Future = Pin> + Send>>; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_ready(cx) + } + + fn call(&mut self, req: Request) -> Self::Future { + let method = req.method().clone(); + let if_none_match = req.headers().get(header::IF_NONE_MATCH).cloned(); + + let mut inner = self.inner.clone(); + Box::pin(async move { + let resp = inner.call(req).await?; + + if !resp.status().is_success() { + return Ok(resp); + } + + let (parts, body) = resp.into_parts(); + let bytes = axum::body::to_bytes(body, usize::MAX).await.unwrap(); + + let mut hasher = crc32fast::Hasher::new(); + hasher.update(&bytes); + let etag = format!("\"{}\"", hex::encode(hasher.finalize().to_be_bytes())); + let etag_header = HeaderValue::from_str(&etag).unwrap(); + let cache_control = parts + .headers + .get(header::CACHE_CONTROL) + .cloned() + .unwrap_or(HeaderValue::from_static("no-cache")); + + if (method == Method::GET || method == Method::HEAD) + && if_none_match + .as_ref() + .is_some_and(|v| v.as_bytes() == etag.as_bytes()) + { + let mut resp = Response::builder() + .status(StatusCode::NOT_MODIFIED) + .body(Body::empty()) + .unwrap(); + resp.headers_mut().insert(header::ETAG, etag_header); + resp.headers_mut() + .insert(header::CACHE_CONTROL, cache_control); + return Ok(resp); + } + + let mut resp = Response::from_parts(parts, Body::from(bytes)); + resp.headers_mut().insert(header::ETAG, etag_header); + resp.headers_mut() + .entry(header::CACHE_CONTROL) + .or_insert(HeaderValue::from_static("no-cache")); + Ok(resp) + }) + } +} diff --git a/crates/recluse/src/main.rs b/crates/recluse/src/main.rs new file mode 100644 index 0000000..27f3824 --- /dev/null +++ b/crates/recluse/src/main.rs @@ -0,0 +1,567 @@ +// SPDX-FileCopyrightText: 2026 Nikolay Govorov +// SPDX-License-Identifier: AGPL-3.0-or-later + +mod config; +mod proxy; +mod storage; +mod telemetry; + +mod controller_backend; +mod controller_web; + +use std::future::Future; +use std::net::{SocketAddr, TcpListener}; +use std::path::PathBuf; +use std::pin::Pin; +use std::sync::Arc; +use std::task::{Context, Poll}; + +use axum::{ + body::Body, + extract::{self, ConnectInfo}, + http::{self, Request, Response}, +}; +use axum_server::Handle; +use axum_server::tls_rustls::RustlsConfig; +#[cfg(target_os = "linux")] +use sd_notify::NotifyState; +use tokio::signal; +use tracing::{error, info, trace}; +use tracing_subscriber::registry::LookupSpan; + +use crate::controller_backend::BackendController; +use crate::controller_web::WebController; +use repos::{Backend, BackendSpec, GoBackend, ZigBackend}; + +async fn init_backend( + backend: Backend, + index_tasks: &mut tokio::task::JoinSet<()>, + index_cancel: tokio_util::sync::CancellationToken, +) -> Option>> { + if !backend.enabled() { + return None; + } + let backend = Arc::new(backend); + let interval = backend.refresh_interval(); + if !interval.is_zero() { + index_tasks.spawn(run_index_refresh( + S::ID, + backend.clone(), + interval, + index_cancel, + )); + } + Some(backend) +} + +async fn run_index_refresh( + name: &'static str, + backend: Arc>, + interval: std::time::Duration, + cancel: tokio_util::sync::CancellationToken, +) { + let mut ticker = tokio::time::interval(interval); + ticker.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); + + loop { + tokio::select! { + _ = cancel.cancelled() => { + info!(backend = name, "index refresh stopped"); + break; + } + _ = ticker.tick() => { + info!(backend = name, "refreshing index"); + match backend.refresh().await { + Ok(()) => info!(backend = name, "index refreshed"), + Err(e) => error!(backend = name, "index refresh failed: {e}"), + } + } + } + } +} + +const VERSION: &str = env!("CARGO_PKG_VERSION"); +const HELP: &str = "\ +Usage: recluse [--config=] + +Options: + --config= Path to config file (optional) + --help Show this help message + --version Show version +"; + +/// Contains metainfo about one server interface +#[derive(Clone)] +struct ListenerInfo { + addr: SocketAddr, + hosts: Vec, +} + +/// Request info stored in span extensions for logging +#[derive(Clone)] +struct RequestInfo { + method: http::Method, + version: http::Version, + path: http::Uri, + host: Option, + user_agent: Option, +} + +/// Key extractor for tower-governor that uses ConnectInfo to get the client IP. +#[derive(Clone)] +struct ClientIpKeyExtractor; +impl tower_governor::key_extractor::KeyExtractor for ClientIpKeyExtractor { + type Key = std::net::IpAddr; + + fn name(&self) -> &'static str { + "ClientIpKeyExtractor" + } + + fn extract(&self, req: &Request) -> Result { + req.extensions() + .get::>() + .map(|ci| ci.0.ip()) + .ok_or(tower_governor::GovernorError::UnableToExtractKey) + } +} + +#[tokio::main] +async fn main() { + let mut config_path = None; + for arg in std::env::args().skip(1) { + if arg == "--help" || arg == "-h" { + print!("{HELP}"); + return; + } + if arg == "--version" || arg == "-V" { + println!("recluse {VERSION}"); + return; + } + if let Some(path) = arg.strip_prefix("--config=") { + config_path = Some(PathBuf::from(path)); + } + } + + let config = Arc::new( + config::ConfigService::load(config_path).unwrap_or_else(|e| { + eprintln!("invalid config: {e}"); + std::process::exit(1); + }), + ); + + let mut telemetry = + telemetry::TelemetryService::init(config.telemetry(), config.appname(), VERSION); + + let storage = Arc::new(storage::StorageService::new(config.clone()).await.unwrap()); + let network = Arc::new(proxy::ProxyService::new()); + + let source = format!("recluse:{}", config.appname()); + let backends = config.backends(); + + const REQUEST_ID_HEADER: http::HeaderName = http::HeaderName::from_static("x-request-id"); + + let trace_layer = tower_http::trace::TraceLayer::new_for_http() + .make_span_with(|req: &http::Request| { + let request_id = req + .headers() + .get(&REQUEST_ID_HEADER) + .and_then(|v| v.to_str().ok()) + .unwrap_or(""); + let local_addr = req.extensions().get::().map(|a| a.addr); + let remote_addr = req + .extensions() + .get::>() + .map(|ci| ci.0.ip()); + + tracing::info_span!( + "http_request", + request_id = %request_id, + local_addr = ?local_addr, + remote_addr = ?remote_addr, + ) + }) + .on_request(|req: &Request, span: &tracing::Span| { + let info = RequestInfo { + method: req.method().clone(), + path: req.uri().clone(), + version: req.version(), + host: extract_host(req), + user_agent: req + .headers() + .get(http::header::USER_AGENT) + .and_then(|v| v.to_str().ok()) + .map(String::from), + }; + + span.with_subscriber(|(id, dispatch)| { + if let Some(reg) = dispatch.downcast_ref::() + && let Some(span_ref) = reg.span(id) + { + span_ref.extensions_mut().insert(info); + } + }); + }) + .on_response( + |res: &Response, latency: std::time::Duration, span: &tracing::Span| { + use axum::body::HttpBody as _; + + let status = res.status().as_u16(); + let content_length = res.body().size_hint().exact(); + let content_type = res + .headers() + .get(http::header::CONTENT_TYPE) + .and_then(|v| v.to_str().ok()); + + let req_info = span.with_subscriber(|(id, dispatch)| { + dispatch + .downcast_ref::() + .and_then(|reg| reg.span(id)) + .and_then(|span_ref| span_ref.extensions().get::().cloned()) + }); + + if let Some(Some(req_info)) = req_info { + info!( + method = %req_info.method, + version = ?req_info.version, + path = %req_info.path, + host = req_info.host, + user_agent = req_info.user_agent, + status, + latency = latency.as_nanos() as u64, + content_type, + content_length, + "on_response", + ); + } else { + info!( + status, + latency = latency.as_nanos() as u64, + content_type, + content_length, + "on_response", + ); + } + }, + ) + .on_failure(tower_http::trace::DefaultOnFailure::new().level(tracing::Level::ERROR)); + + let governor_config = tower_governor::governor::GovernorConfigBuilder::default() + .period(config.server().rate_limit_period) + .burst_size(config.server().rate_limit_burst_size) + .key_extractor(ClientIpKeyExtractor) + .finish() + .unwrap(); + + let mut index_tasks = tokio::task::JoinSet::new(); + let index_cancel = tokio_util::sync::CancellationToken::new(); + + let zig_backend = init_backend( + ZigBackend::new( + backends.zig.clone(), + source.clone(), + storage.clone(), + network.clone(), + ), + &mut index_tasks, + index_cancel.clone(), + ) + .await; + + let go_backend = init_backend( + GoBackend::new( + backends.go.clone(), + source.clone(), + storage.clone(), + network.clone(), + ), + &mut index_tasks, + index_cancel.clone(), + ) + .await; + + let web_controller = Arc::new(WebController::new(zig_backend.clone(), go_backend.clone())); + let mut app = axum::Router::new().merge(web_controller.router()); + + if let Some(ref backend) = zig_backend { + let ctrl = Arc::new(BackendController::new( + backend.clone(), + storage.clone(), + network.clone(), + )); + app = app.nest("/zig", ctrl.router()); + } + + if let Some(ref backend) = go_backend { + let ctrl = Arc::new(BackendController::new( + backend.clone(), + storage.clone(), + network.clone(), + )); + app = app.nest("/go", ctrl.router()); + } + + let app = app + // Opt-in layers + .layer(tower_http::compression::CompressionLayer::new()) + // request limits + .layer(HostValidationLayer) + .layer(tower_http::limit::RequestBodyLimitLayer::new( + config.server().max_body_size.as_u64() as usize, + )) + .layer(tower_http::timeout::TimeoutLayer::with_status_code( + http::StatusCode::REQUEST_TIMEOUT, + config.server().request_timeout, + )) + // logging + .layer(trace_layer) + // rate-limits + .layer(tower_governor::GovernorLayer::new(Arc::new( + governor_config, + ))) + .layer(tower::limit::ConcurrencyLimitLayer::new( + config.server().max_concurrent_requests, + )) + // global headers + .layer(tower_http::request_id::PropagateRequestIdLayer::new( + REQUEST_ID_HEADER.clone(), + )) + .layer(tower_http::request_id::SetRequestIdLayer::new( + REQUEST_ID_HEADER.clone(), + tower_http::request_id::MakeRequestUuid, + )) + .layer(tower_http::set_header::SetResponseHeaderLayer::overriding( + http::header::SERVER, + http::HeaderValue::from_static(concat!("recluse/", env!("CARGO_PKG_VERSION"))), + )); + + let mut tasks = tokio::task::JoinSet::new(); + let handle = Handle::new(); + + for listener_config in config.listeners() { + let std_listener = TcpListener::bind(listener_config.addr).unwrap(); + std_listener.set_nonblocking(true).unwrap(); + + let addr = std_listener.local_addr().unwrap(); + + let app = app + .clone() + .layer(axum::Extension(ListenerInfo { + addr, + hosts: listener_config.hostnames.clone(), + })) + .into_make_service_with_connect_info::(); + + let handle = handle.clone(); + + let tls_enabled = + if let (Some(crt), Some(key)) = (&listener_config.tls_crt, &listener_config.tls_key) { + let rustls_config = RustlsConfig::from_pem_file(crt, key) + .await + .expect("failed to load TLS config"); + + tasks.spawn(async move { + let server = axum_server::from_tcp_rustls(std_listener, rustls_config).unwrap(); + server.handle(handle).serve(app).await.unwrap(); + }); + + true + } else { + tasks.spawn(async move { + let server = axum_server::from_tcp(std_listener).unwrap(); + server.handle(handle).serve(app).await.unwrap(); + }); + + false + }; + + info!( + "listening {} on {} (hostnames: {})", + if tls_enabled { "HTTPS" } else { "HTTP" }, + addr, + if listener_config.hostnames.is_empty() { + "*".to_string() + } else { + listener_config.hostnames.join(", ") + }, + ); + } + + let mut watchdog_ticker = tokio::time::interval(std::time::Duration::from_secs(60)); + + #[cfg(target_os = "linux")] + if sd_notify::booted().unwrap_or(false) { + sd_notify::notify(false, &[NotifyState::Ready]).ok(); + + let mut usec = 0u64; + (sd_notify::watchdog_enabled(true, &mut usec) && usec > 0).then(|| { + let interval = std::time::Duration::from_micros(usec) / 2; + info!( + interval_ms = interval.as_millis() as u64, + "watchdog enabled" + ); + watchdog_ticker = tokio::time::interval(interval); + }); + }; + + #[cfg(unix)] + let mut sigint = signal::unix::signal(signal::unix::SignalKind::interrupt()) + .expect("failed to install signal handler"); + #[cfg(windows)] + let mut sigint = signal::windows::signal(signal::windows::SignalKind::interrupt()) + .expect("failed to install signal handler"); + + #[cfg(unix)] + let mut sigterm = signal::unix::signal(signal::unix::SignalKind::terminate()) + .expect("failed to install signal handler"); + + loop { + let watchdog = watchdog_ticker.tick(); + + #[cfg(unix)] + let sigterm = sigterm.recv(); + #[cfg(not(unix))] + let sigterm = std::future::pending::<()>(); + + tokio::select! { + _ = sigint.recv() => { + info!("received SIGINT, shutting down"); + break; + }, + _ = sigterm => { + info!("received SIGTERM, shutting down"); + break; + }, + _ = watchdog => { + trace!("server is alive"); + + #[cfg(target_os = "linux")] + sd_notify::notify(false, &[NotifyState::Watchdog]).ok(); + }, + result = tasks.join_next() => { + match result { + Some(Ok(())) => error!("listener exited unexpectedly, shutting down"), + Some(Err(e)) => error!("listener failed: {e}, shutting down"), + None => { + error!("no listeners running"); + return; + } + } + break; + }, + } + } + + #[cfg(target_os = "linux")] + sd_notify::notify(false, &[NotifyState::Stopping]).ok(); + + index_cancel.cancel(); + handle.graceful_shutdown(None); + + // Wait for all tasks to finish with timeout + let shutdown_result = tokio::time::timeout(config.server().shutdown_timeout, async { + while let Some(result) = tasks.join_next().await { + if let Err(e) = result { + error!("listener task failed: {e}"); + } + } + while let Some(result) = index_tasks.join_next().await { + if let Err(e) = result { + error!("index task failed: {e}"); + } + } + }) + .await; + + if shutdown_result.is_err() { + error!( + "shutdown timeout after {:?}, aborting remaining tasks", + config.server().shutdown_timeout, + ); + tasks.abort_all(); + index_tasks.abort_all(); + } else { + info!("shutdown complete"); + } + + telemetry.shutdown(); +} + +/// Layer that validates the Host header against configured hostnames. +#[derive(Clone)] +struct HostValidationLayer; +impl tower::Layer for HostValidationLayer { + type Service = HostValidationService; + + fn layer(&self, inner: S) -> Self::Service { + HostValidationService { inner } + } +} + +#[derive(Clone)] +struct HostValidationService { + inner: S, +} +impl tower::Service> for HostValidationService +where + S: tower::Service, Response = Response> + Clone + Send + 'static, + S::Future: Send, +{ + type Response = S::Response; + type Error = S::Error; + type Future = Pin> + Send>>; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_ready(cx) + } + + fn call(&mut self, req: Request) -> Self::Future { + let interface = req.extensions().get::().cloned(); + + if let Some(iface) = interface + && !iface.hosts.is_empty() + { + let is_valid = extract_host(&req) + .map(|h| { + iface + .hosts + .iter() + .any(|allowed| allowed.eq_ignore_ascii_case(&h)) + }) + .unwrap_or(false); + + if !is_valid { + return Box::pin(async move { + Ok(Response::builder() + .status(http::StatusCode::MISDIRECTED_REQUEST) + .body(Body::empty()) + .unwrap()) + }); + } + } + + let clone = self.inner.clone(); + let mut inner = std::mem::replace(&mut self.inner, clone); + Box::pin(async move { inner.call(req).await }) + } +} + +fn extract_host(req: &Request) -> Option { + // HTTP/1.1 uses HOST header, HTTP/2 uses :authority (available via URI) + let raw = if let Some(host) = req.headers().get(http::header::HOST) { + host.to_str().ok().map(|raw| { + if let Some((host, port)) = raw.rsplit_once(':') + && port.parse::().is_ok() + && (host.ends_with(']') || !host.contains('[')) + { + host + } else { + raw + } + }) + } else { + req.uri().host() + }; + + raw.and_then(|raw| url::Host::parse(raw).ok()) + .map(|h| h.to_string().trim_end_matches('.').to_string()) +} diff --git a/crates/recluse/src/proxy.rs b/crates/recluse/src/proxy.rs new file mode 100644 index 0000000..9a2c73d --- /dev/null +++ b/crates/recluse/src/proxy.rs @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: 2026 Nikolay Govorov +// SPDX-License-Identifier: AGPL-3.0-or-later + +use bytes::Bytes; +use http_body_util::{BodyExt, Empty}; +use hyper::{Request, http}; +use hyper_tls::HttpsConnector; +use hyper_util::client::legacy::{Client, connect::HttpConnector}; +use hyper_util::rt::TokioExecutor; +use tower::ServiceExt; +use tower_http::follow_redirect::FollowRedirect; +use url::Url; + +use repos::{BackendError, BackendNetwork}; + +#[derive(Clone)] +pub struct DownloadRequest { + pub url: Url, +} + +#[derive(Clone)] +pub struct File { + pub bytes: Bytes, +} + +pub struct ProxyService { + client: FollowRedirect, Empty>>, +} + +impl ProxyService { + pub fn new() -> Self { + let https = HttpsConnector::new(); + let client = Client::builder(TokioExecutor::new()).build(https); + Self { + client: FollowRedirect::new(client), + } + } + + pub async fn fetch(&self, request: DownloadRequest) -> Result { + let request = Request::builder() + .method(http::Method::GET) + .uri(request.url.as_str()) + .header(http::header::USER_AGENT, "recluse/0.1") + .body(Empty::::new()) + .unwrap(); + + let response = self + .client + .clone() + .oneshot(request) + .await + .map_err(|_| http::StatusCode::GATEWAY_TIMEOUT)?; + + let (parts, body) = response.into_parts(); + let status = parts.status; + if !status.is_success() { + return Err(status); + } + + let bytes = body + .collect() + .await + .map_err(|_| http::StatusCode::GATEWAY_TIMEOUT)? + .to_bytes(); + + Ok(File { bytes }) + } +} + +#[async_trait::async_trait] +impl BackendNetwork for ProxyService { + async fn http_get(&self, url: &url::Url) -> Result { + self.fetch(DownloadRequest { url: url.clone() }) + .await + .map(|f| f.bytes) + .map_err(|e| BackendError::Network(e.to_string())) + } +} diff --git a/crates/recluse/src/storage.rs b/crates/recluse/src/storage.rs new file mode 100644 index 0000000..0e7f3ac --- /dev/null +++ b/crates/recluse/src/storage.rs @@ -0,0 +1,1203 @@ +// SPDX-FileCopyrightText: 2026 Nikolay Govorov +// SPDX-License-Identifier: AGPL-3.0-or-later + +// This class stores uploaded files and associated metadata. +// Files are immutable but can be deleted. +// +// A unique file is defined by a `scope` and a `filename`. +// The filename can be any valid UTF-8 string up to 1KB +// in size and does not have to be a valid filesystem name. +// +// The list of files and their metadata are stored in a single +// SQLite database table. Small files are stored in a BLOB column +// in SQLite; for larger files, a checksum is stored in the database, +// and the file itself is stored on disk. +// +// On disk new files are written in two steps: +// - the file is written to a temporary file in the same directory; +// - a transaction is opened and a new file entry is created +// - temp file is renamed to the final filename +// - the transaction is committed. +// +// This scheme guarantees that if a record exists in the table, the file is written. +// However if the server crashes after rename but before commit, an orphan file will remain on the disk. +// To combat this, when the server starts, we check that there is an entry +// in the database for each file on the disk, and we also delete all temporary (non-renamed) files. + +use std::path::{Path, PathBuf}; +use std::sync; + +use bytes::Bytes; +use crc32fast::Hasher as Crc32Hasher; +use sqlx::encode::{Encode, IsNull}; +use sqlx::error::BoxDynError; +use sqlx::{FromRow, Pool, Sqlite, query, query_as, query_scalar, sqlite}; +use thiserror::Error; +use tokio::fs; +use tokio::io::AsyncWriteExt; +use tracing::{debug, error, instrument, warn}; +use uuid::Uuid; + +use crate::config::ConfigService; +use repos::{BackendError, BackendStorage, RawRelease, RawReleaseFile, Release}; + +const SQLITE_POOL_SIZE: u32 = 16; +const INLINE_THRESHOLD: usize = 256 * 1024; // 256 KB + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Id(pub Uuid); + +impl std::ops::Deref for Id { + type Target = Uuid; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl sqlx::Type for Id { + fn type_info() -> sqlite::SqliteTypeInfo { + as sqlx::Type>::type_info() + } + + fn compatible(ty: &sqlite::SqliteTypeInfo) -> bool { + as sqlx::Type>::compatible(ty) + } +} + +impl<'r> sqlx::decode::Decode<'r, Sqlite> for Id { + fn decode( + value: sqlite::SqliteValueRef<'r>, + ) -> Result> { + let value: Vec = as sqlx::decode::Decode>::decode(value)?; + let uuid = Uuid::from_slice(&value)?; + Ok(Id(uuid)) + } +} + +impl<'q> Encode<'q, Sqlite> for Id { + fn encode_by_ref( + &self, + buf: &mut ::ArgumentBuffer<'q>, + ) -> Result { + let value = self.0.as_bytes().to_vec(); + as Encode>::encode(value, buf) + } +} + +#[derive(Debug, Clone)] +pub struct Blob(pub Bytes); + +impl std::ops::Deref for Blob { + type Target = Bytes; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl sqlx::Type for Blob { + fn type_info() -> sqlite::SqliteTypeInfo { + as sqlx::Type>::type_info() // BLOB + } + + fn compatible(ty: &sqlite::SqliteTypeInfo) -> bool { + as sqlx::Type>::compatible(ty) + } +} + +impl<'r> sqlx::decode::Decode<'r, Sqlite> for Blob { + fn decode( + value: sqlite::SqliteValueRef<'r>, + ) -> Result> { + let slice: &'r [u8] = <&'r [u8] as sqlx::decode::Decode>::decode(value)?; + Ok(Blob(Bytes::copy_from_slice(slice))) + } +} + +#[derive(Debug, Error)] +pub enum StorageError { + #[error("file already exists: {0}/{1}")] + AlreadyExists(String, String), + + #[error("blob integrity check failed")] + IntegrityError, + + #[error("blob file missing on disk: {0}")] + BlobNotFound(PathBuf), + + #[error("failed to connect index db: {0}")] + DbError(#[from] sqlx::Error), + + #[error("io error: {0}")] + IoError(#[from] std::io::Error), +} + +/// Cached file entry (datafiles table) +#[allow(unused)] +#[derive(Debug, Clone, FromRow)] +pub struct Object { + pub id: Id, + pub scope: String, + pub created_at: chrono::DateTime, + + pub file_name: String, + pub file_size: i64, + pub file_bytes: Blob, + pub inlined: bool, +} + +impl Object { + // You cannot change this ID, this will desynchronize the records in the database and the files on the disk. + const UUID_ROOT_NAMESPACE: Uuid = Uuid::from_bytes([ + 0x8b, 0x06, 0x3c, 0x4c, 0x6b, 0x5c, 0x4a, 0x8b, 0x92, 0x8f, 0x75, 0x8b, 0x0e, 0x63, 0xc3, + 0x5d, + ]); + + fn uuid(scope: &str, file: &str) -> Id { + let scope_ns = Uuid::new_v5(&Object::UUID_ROOT_NAMESPACE, scope.as_bytes()); + Id(Uuid::new_v5(&scope_ns, file.as_bytes())) + } + + fn hash(scope: &str, file: &str, blob: &[u8]) -> Vec { + let mut hasher = Crc32Hasher::new(); + + hasher.update(b"/"); + hasher.update(scope.as_bytes()); + + hasher.update(b"/"); + hasher.update(file.as_bytes()); + + hasher.update(b"/"); + hasher.update(blob); + hasher.update(b"\0"); + + hasher.finalize().to_be_bytes().to_vec() + } +} + +/// Builder for file query SQL +pub struct FileQuery<'a> { + backend: &'a str, + version: Option<&'a str>, + filename: Option<&'a str>, + meta_null: Option<&'a str>, +} + +impl<'a> FileQuery<'a> { + pub fn new(backend: &'a str) -> Self { + Self { + backend, + version: None, + filename: None, + meta_null: None, + } + } + + pub fn version(mut self, version: &'a str) -> Self { + self.version = Some(version); + self + } + + pub fn filename(mut self, filename: &'a str) -> Self { + self.filename = Some(filename); + self + } + + pub fn where_meta_null(mut self, field: &'a str) -> Self { + self.meta_null = Some(field); + self + } + + pub fn build_sql(&self) -> String { + let mut sql = String::from( + "SELECT backend, version, filename, checksum, size, os, arch, meta FROM files WHERE backend = ?1", + ); + let mut param_idx = 1; + + if self.version.is_some() { + param_idx += 1; + sql.push_str(&format!(" AND version = ?{}", param_idx)); + } + if self.filename.is_some() { + param_idx += 1; + sql.push_str(&format!(" AND filename = ?{}", param_idx)); + } + if let Some(field) = self.meta_null { + sql.push_str(&format!( + " AND (meta IS NULL OR json_extract(meta, '$.{}') IS NULL)", + field + )); + } + + sql + } +} + +struct FileSystem { + objects: PathBuf, + database: PathBuf, +} + +impl FileSystem { + fn new(root: &Path) -> Self { + Self { + objects: root.join("objects"), + database: root.join("index.sqlite"), + } + } + + fn database(&self) -> &Path { + &self.database + } + + fn objects_root(&self) -> &Path { + &self.objects + } + + fn object(&self, scope: &str, file: &str) -> PathBuf { + let id = Object::uuid(scope, file); + let hash_hex = hex::encode(id.0.as_bytes()); + self.objects_root() + .join(&hash_hex[0..2]) + .join(&hash_hex[2..4]) + .join(&hash_hex) + } + + async fn objects_walk(&self, mut f: F) -> Result<(), StorageError> + where + F: FnMut(PathBuf) -> Fut, + Fut: std::future::Future>, + { + if !self.objects.exists() { + return Ok(()); + } + + let mut stack = vec![self.objects.to_path_buf()]; + while let Some(dir) = stack.pop() { + let mut entries = fs::read_dir(&dir).await?; + while let Some(entry) = entries.next_entry().await? { + let path = entry.path(); + let file_type = entry.file_type().await?; + + if file_type.is_dir() { + stack.push(path); + } else if file_type.is_file() { + f(path).await?; + } + } + } + + Ok(()) + } +} + +pub struct StorageService { + blobfs: FileSystem, + sqlite: Pool, +} + +impl StorageService { + pub async fn new(config: sync::Arc) -> Result { + let blobfs = FileSystem::new(config.dirname()); + + let connection = format!("sqlite:{}?mode=rwc", blobfs.database().to_str().unwrap()); + let sqlite: Pool = sqlite::SqlitePoolOptions::new() + .max_connections(SQLITE_POOL_SIZE) + .after_connect(|conn, _meta| { + Box::pin(async move { + // Connection-specific PRAGMAs (must be set on each connection) + sqlx::query("PRAGMA foreign_keys = ON;") + .execute(&mut *conn) + .await?; + sqlx::query("PRAGMA busy_timeout = 5000;") + .execute(&mut *conn) + .await?; + Ok(()) + }) + }) + .connect(&connection) + .await?; + + // WAL mode is database-wide and persists, only needs to be set once + query("PRAGMA journal_mode = WAL;").execute(&sqlite).await?; + + let storage = Self { sqlite, blobfs }; + storage.migrations().await?; + storage.doctor().await?; + + Ok(storage) + } + + /// Synchronously traverses the tree and removes temporary files. + /// Must run before the application starts. + async fn doctor(&self) -> Result<(), StorageError> { + let result = self.blobfs.objects_walk(|path| async move { + let name = match path.file_name().and_then(|name| name.to_str()) { + Some(name) => name.to_string(), + None => { + warn!(path = %path.display(), "cleanup: invalid blob name"); + let _ = fs::remove_file(path).await; + return Ok(()); + } + }; + + if name.ends_with(".part") { + warn!(path = %path.display(), "cleanup: removing temp file"); + let _ = fs::remove_file(path).await; + return Ok(()); + } + + if name.len() != 32 { + warn!(path = %path.display(), "cleanup: invalid blob name length"); + let _ = fs::remove_file(path).await; + return Ok(()); + } + + let id_bytes = match hex::decode(&name) { + Ok(bytes) => bytes, + Err(_) => { + warn!(path = %path.display(), "cleanup: invalid blob name hex"); + let _ = fs::remove_file(path).await; + return Ok(()); + } + }; + + let id = match Uuid::from_slice(&id_bytes) { + Ok(uuid) => Id(uuid), + Err(_) => { + warn!(path = %path.display(), "cleanup: invalid blob uuid"); + let _ = fs::remove_file(path).await; + return Ok(()); + } + }; + + let exists: Option = query_scalar("SELECT 1 FROM datafiles WHERE id = ?1") + .bind(id) + .fetch_optional(&self.sqlite) + .await?; + + if exists.is_none() { + warn!(path = %path.display(), "cleanup: removing orphan blob"); + let _ = fs::remove_file(path).await; + } + + Ok(()) + }); + result.await?; + + Ok(()) + } + + async fn migrations(&self) -> Result<(), StorageError> { + // Object storage table + query( + "CREATE TABLE IF NOT EXISTS datafiles( + id BLOB PRIMARY KEY CHECK (length(id) = 16), + scope TEXT NOT NULL, + created_at TEXT DEFAULT (datetime('now')), + file_name TEXT NOT NULL, + file_size INTEGER NOT NULL, + file_bytes BLOB, + inlined INTEGER NOT NULL, + UNIQUE (scope, file_name) + ) STRICT", + ) + .execute(&self.sqlite) + .await?; + + // Drop old backend-specific tables (data will be re-fetched from upstream) + query("DROP TABLE IF EXISTS go_files") + .execute(&self.sqlite) + .await?; + query("DROP TABLE IF EXISTS go_versions") + .execute(&self.sqlite) + .await?; + query("DROP TABLE IF EXISTS zig_files") + .execute(&self.sqlite) + .await?; + query("DROP TABLE IF EXISTS zig_versions") + .execute(&self.sqlite) + .await?; + + // Unified versions table + query( + "CREATE TABLE IF NOT EXISTS versions ( + backend TEXT NOT NULL, + version TEXT NOT NULL, + sort_key INTEGER NOT NULL, + meta BLOB CHECK (meta IS NULL OR (json_valid(meta) AND json_type(meta) = 'object')), + PRIMARY KEY (backend, version) + ) STRICT", + ) + .execute(&self.sqlite) + .await?; + + // Unified files table + query( + "CREATE TABLE IF NOT EXISTS files ( + backend TEXT NOT NULL, + version TEXT NOT NULL, + filename TEXT NOT NULL, + checksum TEXT NOT NULL, + size INTEGER NOT NULL, + os TEXT, + arch TEXT, + meta BLOB CHECK (meta IS NULL OR (json_valid(meta) AND json_type(meta) = 'object')), + PRIMARY KEY (backend, version, filename), + FOREIGN KEY (backend, version) REFERENCES versions(backend, version) + ) STRICT", + ) + .execute(&self.sqlite) + .await?; + + // Index for fast filename lookups + query("CREATE INDEX IF NOT EXISTS idx_files_backend_filename ON files(backend, filename)") + .execute(&self.sqlite) + .await?; + + Ok(()) + } + + #[instrument(skip(self))] + pub async fn get(&self, scope: &str, filename: &str) -> Result, StorageError> { + let file: Option = + query_as("SELECT * FROM datafiles WHERE scope = ?1 AND file_name = ?2") + .bind(scope) + .bind(filename) + .fetch_optional(&self.sqlite) + .await?; + + match file { + None => { + debug!("get: file not found"); + Ok(None) + } + Some(mut file) if !file.inlined => { + let obj = self.blobfs.object(scope, filename); + let bytes = match fs::read(&obj).await { + Ok(b) => Bytes::from(b), + Err(e) if e.kind() == std::io::ErrorKind::NotFound => { + return Err(StorageError::BlobNotFound(obj)); + } + Err(e) => return Err(e.into()), + }; + + let hash = Object::hash(scope, filename, &bytes); + if hash != file.file_bytes.to_vec() { + return Err(StorageError::IntegrityError); + } + + file.file_bytes = Blob(bytes); + debug!(size = file.file_size, "get: loaded from disk"); + Ok(Some(file)) + } + Some(file) => { + debug!(size = file.file_size, "get: loaded inline"); + Ok(Some(file)) + } + } + } + + #[instrument(skip(self, bytes), fields(size = bytes.len()))] + pub async fn put( + &self, + scope: &str, + filename: &str, + bytes: &Bytes, + ) -> Result<(), StorageError> { + let inlined = bytes.len() <= INLINE_THRESHOLD; + + let obj = self.blobfs.object(scope, filename); + let tmp = obj.with_extension(format!("{}.part", Uuid::new_v4())); + + // write temp file + if !inlined { + if let Some(parent) = obj.parent() { + fs::create_dir_all(parent).await?; + } + + let mut file = fs::OpenOptions::new() + .write(true) + .create_new(true) + .open(&tmp) + .await?; + + file.write_all(bytes).await?; + file.sync_all().await?; + } + + // bytes for small files or hash for large ones + let payload: Vec = if inlined { + bytes.to_vec() + } else { + Object::hash(scope, filename, bytes) + }; + + let result = async { + let mut tx = self.sqlite.begin().await?; + let id = Object::uuid(scope, filename); + + let result = query( + " + INSERT INTO datafiles ( + id, scope, file_name, file_size, file_bytes, inlined + ) VALUES ( + ?1, ?2, ?3, ?4, ?5, ?6 + ); + ", + ) + .bind(id) + .bind(scope) + .bind(filename) + .bind(bytes.len() as i64) + .bind(&payload) + .bind(inlined) + .execute(tx.as_mut()) + .await; + + match result { + Ok(_) => { + if !inlined { + fs::rename(&tmp, &obj).await?; + if let Some(parent) = obj.parent() { + let dir = fs::File::open(parent).await?; + dir.sync_all().await?; + } + } + + tx.commit().await?; + debug!("put: a new file has been commited"); + Ok(()) + } + Err(sqlx::Error::Database(ref db_err)) if db_err.is_unique_violation() => { + let existing: Option = + query_as("SELECT * FROM datafiles WHERE scope = ?1 AND file_name = ?2") + .bind(scope) + .bind(filename) + .fetch_optional(tx.as_mut()) + .await?; + + match existing { + Some(file) if file.file_bytes.to_vec() == payload => { + if !inlined { + let _ = fs::remove_file(&tmp).await; + tx.rollback().await?; + } + + debug!("put: identical file already exists"); + return Ok(()); + } + Some(_) => { + warn!("put: file already exists with different content"); + } + None => { + // unique_violation but row doesn't exist - shouldn't happen + warn!("corrupted! 'is_unique_violation' received, but data cannot be selected"); + } + } + + Err(StorageError::AlreadyExists( + scope.to_string(), + filename.to_string(), + )) + } + Err(e) => Err(e.into()), + } + }.await; + + if result.is_err() && !inlined { + let _ = fs::remove_file(&tmp).await; + } + + result + } + + /// Insert or update releases with their files in a single transaction. + pub async fn insert_releases( + &self, + releases: &[(RawRelease, Vec)], + ) -> Result<(), StorageError> { + for (release, files) in releases { + let mut tx = match self.sqlite.begin().await { + Ok(tx) => tx, + Err(e) => { + error!( + backend = release.backend, + version = release.version, + "failed to start transaction: {e}" + ); + return Err(e.into()); + } + }; + + let meta_json = release + .meta + .as_ref() + .map(|m| serde_json::to_vec(m).unwrap()); + + let result = async { + // Insert/update version + query( + "INSERT INTO versions (backend, version, sort_key, meta) + VALUES (?1, ?2, ?3, ?4) + ON CONFLICT(backend, version) DO UPDATE SET + sort_key = excluded.sort_key, + meta = excluded.meta + WHERE sort_key IS NOT excluded.sort_key OR meta IS NOT excluded.meta", + ) + .bind(&release.backend) + .bind(&release.version) + .bind(release.sort_key) + .bind(meta_json.as_deref()) + .execute(&mut *tx) + .await?; + + // Insert/update files + for file in files { + let changed = + Self::insert_file(&mut tx, &release.backend, &release.version, file) + .await?; + if changed { + warn!( + backend = release.backend, + version = release.version, + filename = file.filename, + "index file changed" + ); + } + } + + Ok::<(), StorageError>(()) + } + .await; + + match result { + Ok(()) => { + if let Err(e) = tx.commit().await { + error!( + backend = release.backend, + version = release.version, + "failed to commit release: {e}" + ); + } + } + Err(e) => { + error!( + backend = release.backend, + version = release.version, + "failed to store release, skipping: {e}" + ); + let _ = tx.rollback().await; + } + } + } + + Ok(()) + } + + /// Insert or update a single file within a transaction. + /// Returns `true` if an existing file was modified. + async fn insert_file( + tx: &mut sqlx::Transaction<'_, Sqlite>, + backend: &str, + version: &str, + file: &RawReleaseFile, + ) -> Result { + let meta_json = file.meta.as_ref().map(|m| serde_json::to_vec(m).unwrap()); + let os_str = file.os.as_ref().map(AsRef::as_ref); + let arch_str = file.arch.as_ref().map(AsRef::as_ref); + + let existed: Option<(i32,)> = + query_as("SELECT 1 FROM files WHERE backend = ?1 AND version = ?2 AND filename = ?3") + .bind(backend) + .bind(version) + .bind(&file.filename) + .fetch_optional(&mut **tx) + .await?; + + let changed: Option<(i32,)> = query_as( + "INSERT INTO files (backend, version, filename, checksum, size, os, arch, meta) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8) + ON CONFLICT(backend, version, filename) DO UPDATE SET + checksum = excluded.checksum, + size = excluded.size, + os = excluded.os, + arch = excluded.arch + WHERE checksum IS NOT excluded.checksum + OR size IS NOT excluded.size + OR os IS NOT excluded.os + OR arch IS NOT excluded.arch + RETURNING 1", + ) + .bind(backend) + .bind(version) + .bind(&file.filename) + .bind(&file.checksum) + .bind(file.size) + .bind(os_str) + .bind(arch_str) + .bind(meta_json.as_deref()) + .fetch_optional(&mut **tx) + .await?; + + Ok(existed.is_some() && changed.is_some()) + } + + /// Execute a file query. + pub async fn query_files_filtered( + &self, + q: FileQuery<'_>, + ) -> Result, StorageError> { + let sql = q.build_sql(); + + let mut query = sqlx::query_as::< + _, + ( + String, + String, + String, + String, + i64, + Option, + Option, + Option>, + ), + >(&sql) + .bind(q.backend); + + if let Some(v) = q.version { + query = query.bind(v); + } + if let Some(f) = q.filename { + query = query.bind(f); + } + + let rows = query.fetch_all(&self.sqlite).await?; + + rows.into_iter() + .map( + |(backend, version, filename, checksum, size, os_str, arch_str, meta_bytes)| { + let meta = meta_bytes + .map(|b| serde_json::from_slice(&b)) + .transpose() + .map_err(|e| StorageError::DbError(sqlx::Error::Decode(Box::new(e))))?; + + Ok(RawReleaseFile { + backend, + version, + filename, + checksum, + size, + os: os_str.and_then(|s| s.parse().ok()), + arch: arch_str.and_then(|s| s.parse().ok()), + meta, + }) + }, + ) + .collect() + } + + /// Query all versions for a backend, ordered by sort_key. + pub async fn query_releases(&self, backend: &str) -> Result, StorageError> { + let rows = query_as::<_, (String, String, i64, Option>)>( + "SELECT backend, version, sort_key, meta FROM versions WHERE backend = ?1 ORDER BY sort_key", + ) + .bind(backend) + .fetch_all(&self.sqlite) + .await?; + + rows.into_iter() + .map(|(backend, version, sort_key, meta_bytes)| { + let meta = meta_bytes + .map(|b| serde_json::from_slice(&b)) + .transpose() + .map_err(|e| StorageError::DbError(sqlx::Error::Decode(Box::new(e))))?; + + Ok(Release { + backend, + version, + sort_key, + meta, + }) + }) + .collect() + } + + /// Update file metadata (e.g. after fetching a signature). + pub async fn update_file_meta(&self, file: &RawReleaseFile) -> Result { + let meta_json = file.meta.as_ref().map(|m| serde_json::to_vec(m).unwrap()); + + let result = query( + "UPDATE files SET meta = ?1 + WHERE backend = ?2 AND version = ?3 AND filename = ?4", + ) + .bind(meta_json.as_deref()) + .bind(&file.backend) + .bind(&file.version) + .bind(&file.filename) + .execute(&self.sqlite) + .await?; + + Ok(result.rows_affected() > 0) + } +} + +#[async_trait::async_trait] +impl BackendStorage for StorageService { + async fn insert_releases( + &self, + releases: &[(RawRelease, Vec)], + ) -> Result<(), BackendError> { + StorageService::insert_releases(self, releases) + .await + .map_err(|e| BackendError::Storage(e.to_string())) + } + + async fn query_releases(&self, backend: &str) -> Result, BackendError> { + StorageService::query_releases(self, backend) + .await + .map_err(|e| BackendError::Storage(e.to_string())) + } + + async fn query_files( + &self, + backend: &str, + version: Option<&str>, + filename: Option<&str>, + meta_null_field: Option<&str>, + ) -> Result, BackendError> { + let mut q = FileQuery::new(backend); + if let Some(v) = version { + q = q.version(v); + } + if let Some(f) = filename { + q = q.filename(f); + } + if let Some(field) = meta_null_field { + q = q.where_meta_null(field); + } + self.query_files_filtered(q) + .await + .map_err(|e| BackendError::Storage(e.to_string())) + } + + async fn update_file_meta(&self, file: &RawReleaseFile) -> Result { + StorageService::update_file_meta(self, file) + .await + .map_err(|e| BackendError::Storage(e.to_string())) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::TempDir; + + const BIG_FILE_SIZE: usize = INLINE_THRESHOLD * 64; + + async fn create_storage_at(path: &Path) -> StorageService { + let config = sync::Arc::new(ConfigService::for_test(path.to_path_buf())); + StorageService::new(config).await.unwrap() + } + + async fn create_test_storage() -> (StorageService, TempDir) { + let tmp = TempDir::new().unwrap(); + let storage = create_storage_at(tmp.path()).await; + (storage, tmp) + } + + /// Count files in a directory recursively + fn count_files(dir: &Path, ext: Option<&str>) -> usize { + let mut count = 0; + if let Ok(entries) = std::fs::read_dir(dir) { + for entry in entries.flatten() { + let path = entry.path(); + if path.is_dir() { + count += count_files(&path, ext); + } else if let Some(extension) = ext { + if path.extension().is_some_and(|ext| ext == extension) { + count += 1; + } + } else { + count += 1; + } + } + } + count + } + + /// Recursively delete or corrupt all files in a directory + fn damage_blobs(dir: &Path, corrupt: bool) { + if let Ok(entries) = std::fs::read_dir(dir) { + for entry in entries.flatten() { + let path = entry.path(); + if path.is_dir() { + damage_blobs(&path, corrupt); + } else if corrupt { + if let Ok(meta) = path.metadata() { + let _ = std::fs::write(&path, vec![0x00; meta.len() as usize]); + } + } else { + let _ = std::fs::remove_file(&path); + } + } + } + } + + #[tokio::test] + async fn test_write_read_small_file() { + let (storage, _tmp) = create_test_storage().await; + + // 1 KB file - should be stored inline + let data = Bytes::from(vec![0xAB; 1024]); + storage.put("test-scope", "small.bin", &data).await.unwrap(); + + let file = storage.get("test-scope", "small.bin").await.unwrap(); + assert!(file.is_some()); + + let file = file.unwrap(); + assert!(file.inlined); + assert_eq!(file.file_bytes.0, data); + assert_eq!(file.file_size, 1024); + } + + #[tokio::test] + async fn test_write_read_large_file() { + let (storage, tmp) = create_test_storage().await; + + // Large file - should be stored on disk + let data = Bytes::from(vec![0xCD; BIG_FILE_SIZE]); + storage.put("test-scope", "large.bin", &data).await.unwrap(); + + let file = storage.get("test-scope", "large.bin").await.unwrap(); + assert!(file.is_some()); + + let file = file.unwrap(); + assert!(!file.inlined); + assert_eq!(file.file_bytes.0, data); + assert_eq!(file.file_size, (BIG_FILE_SIZE) as i64); + + // Verify file is stored on disk, not inline in SQLite + let db_size = std::fs::metadata(tmp.path().join("index.sqlite")) + .unwrap() + .len(); + assert!( + db_size < data.len() as u64, + "database ({db_size} bytes) should be smaller than file ({} bytes)", + data.len() + ); + } + + #[tokio::test] + async fn test_write_read_boundary_file() { + let (storage, _tmp) = create_test_storage().await; + + // Exactly 256 KB - should be stored inline (threshold is <=) + let data = Bytes::from(vec![0xEF; INLINE_THRESHOLD]); + storage + .put("test-scope", "boundary.bin", &data) + .await + .unwrap(); + + let file = storage.get("test-scope", "boundary.bin").await.unwrap(); + assert!(file.is_some()); + + let file = file.unwrap(); + assert!(file.inlined); + assert_eq!(file.file_bytes.0, data); + assert_eq!(file.file_size, INLINE_THRESHOLD as i64); + } + + #[tokio::test] + async fn test_read_nonexistent_file() { + let (storage, _tmp) = create_test_storage().await; + + let file = storage.get("test-scope", "nonexistent.bin").await.unwrap(); + assert!(file.is_none()); + } + + #[tokio::test] + async fn test_persistence_after_restart() { + let tmp = TempDir::new().unwrap(); + + let small_data = Bytes::from(vec![0x11; 1024]); + let large_data = Bytes::from(vec![0x22; BIG_FILE_SIZE]); + + // First "session": write files + { + let storage = create_storage_at(tmp.path()).await; + storage + .put("persist", "small.bin", &small_data) + .await + .unwrap(); + storage + .put("persist", "large.bin", &large_data) + .await + .unwrap(); + // storage is dropped here, simulating shutdown + } + + // Second "session": verify files persist + { + let storage = create_storage_at(tmp.path()).await; + + let small = storage.get("persist", "small.bin").await.unwrap(); + assert!(small.is_some()); + assert_eq!(small.unwrap().file_bytes.0, small_data); + + let large = storage.get("persist", "large.bin").await.unwrap(); + assert!(large.is_some()); + assert_eq!(large.unwrap().file_bytes.0, large_data); + } + } + + #[tokio::test] + async fn test_error_blob_not_found() { + let (storage, tmp) = create_test_storage().await; + + // Write a large file (stored on disk) + let data = Bytes::from(vec![0xAA; BIG_FILE_SIZE]); + storage + .put("test-scope", "to-delete.bin", &data) + .await + .unwrap(); + + // Delete all blob files from disk + damage_blobs(&tmp.path().join("objects"), false); + + // Reading should fail with BlobNotFound + let result = storage.get("test-scope", "to-delete.bin").await; + assert!(matches!(result, Err(StorageError::BlobNotFound(_)))); + } + + #[tokio::test] + async fn test_error_blob_corrupted() { + let (storage, tmp) = create_test_storage().await; + + // Write a large file (stored on disk) + let data = Bytes::from(vec![0xBB; BIG_FILE_SIZE]); + storage + .put("test-scope", "to-corrupt.bin", &data) + .await + .unwrap(); + + // Corrupt all blob files on disk + damage_blobs(&tmp.path().join("objects"), true); + + // Reading should fail with IntegrityError + let result = storage.get("test-scope", "to-corrupt.bin").await; + assert!(matches!(result, Err(StorageError::IntegrityError))); + } + + #[tokio::test] + async fn test_duplicate_put_same_content() { + let (storage, tmp) = create_test_storage().await; + + // Write a large file + let data = Bytes::from(vec![0xCC; BIG_FILE_SIZE]); + storage.put("test-scope", "dup.bin", &data).await.unwrap(); + + // Write the same file again with identical content - should succeed + let result = storage.put("test-scope", "dup.bin", &data).await; + assert!(result.is_ok()); + + // Verify no temp files left behind + assert_eq!(count_files(&tmp.path().join("objects"), Some("part")), 0); + + // Verify file is still readable with correct content + let file = storage.get("test-scope", "dup.bin").await.unwrap(); + assert!(file.is_some()); + assert_eq!(file.unwrap().file_bytes.0, data); + } + + #[tokio::test] + async fn test_duplicate_put_different_content() { + let (storage, tmp) = create_test_storage().await; + + // Write a large file + let data1 = Bytes::from(vec![0xDD; BIG_FILE_SIZE]); + storage.put("test-scope", "dup.bin", &data1).await.unwrap(); + + // Write the same filename with different content - should fail + let data2 = Bytes::from(vec![0xEE; BIG_FILE_SIZE]); + let result = storage.put("test-scope", "dup.bin", &data2).await; + assert!(matches!(result, Err(StorageError::AlreadyExists(_, _)))); + + // Verify no temp files left behind + assert_eq!(count_files(&tmp.path().join("objects"), Some("part")), 0); + + // Verify original file is still intact + let file = storage.get("test-scope", "dup.bin").await.unwrap(); + assert!(file.is_some()); + assert_eq!(file.unwrap().file_bytes.0, data1); + } + + #[tokio::test] + async fn test_doctor_removes_temp_files() { + let tmp = TempDir::new().unwrap(); + + // First session: write a large file + let data = Bytes::from(vec![0xAA; BIG_FILE_SIZE]); + { + let storage = create_storage_at(tmp.path()).await; + storage.put("test-scope", "valid.bin", &data).await.unwrap(); + } + + // Manually create temp files in the objects directory + let objects_dir = tmp.path().join("objects"); + std::fs::create_dir_all(objects_dir.join("ab/cd")).unwrap(); + std::fs::write(objects_dir.join("ab/cd/test.part"), b"temp1").unwrap(); + std::fs::write(objects_dir.join("ab/cd/another.12345.part"), b"temp2").unwrap(); + + assert_eq!(count_files(&objects_dir, Some("part")), 2); + + // Second session: doctor should clean up temp files + { + let storage = create_storage_at(tmp.path()).await; + + // Temp files should be gone + assert_eq!(count_files(&objects_dir, Some("part")), 0); + + // Valid file should still be readable + let file = storage.get("test-scope", "valid.bin").await.unwrap(); + assert!(file.is_some()); + assert_eq!(file.unwrap().file_bytes.0, data); + } + } + + #[tokio::test] + async fn test_doctor_removes_orphan_blobs() { + let tmp = TempDir::new().unwrap(); + + // First session: write a large file + let data = Bytes::from(vec![0xBB; BIG_FILE_SIZE]); + { + let storage = create_storage_at(tmp.path()).await; + storage.put("test-scope", "valid.bin", &data).await.unwrap(); + } + + // Count files before adding orphan + let objects_dir = tmp.path().join("objects"); + let files_before = count_files(&objects_dir, None); + assert_eq!(files_before, 1); // Only the valid blob + + // Manually create an orphan blob (valid hex name but no DB record) + std::fs::create_dir_all(objects_dir.join("de/ad")).unwrap(); + let orphan_name = "deadbeefdeadbeefdeadbeefdeadbeef"; // 32 hex chars + std::fs::write(objects_dir.join("de/ad").join(orphan_name), b"orphan").unwrap(); + + assert_eq!(count_files(&objects_dir, None), 2); + + // Second session: doctor should clean up orphan blob + { + let storage = create_storage_at(tmp.path()).await; + + // Only the valid file should remain + assert_eq!(count_files(&objects_dir, None), 1); + + // Valid file should still be readable + let file = storage.get("test-scope", "valid.bin").await.unwrap(); + assert!(file.is_some()); + assert_eq!(file.unwrap().file_bytes.0, data); + } + } +} diff --git a/crates/recluse/src/telemetry.rs b/crates/recluse/src/telemetry.rs new file mode 100644 index 0000000..b805483 --- /dev/null +++ b/crates/recluse/src/telemetry.rs @@ -0,0 +1,247 @@ +// SPDX-FileCopyrightText: 2026 Nikolay Govorov +// SPDX-License-Identifier: AGPL-3.0-or-later + +use std::fmt::Debug; +use std::time::SystemTime; + +use opentelemetry::InstrumentationScope; +use opentelemetry::KeyValue; +use opentelemetry::logs::LogRecord as _; +use opentelemetry::trace::TracerProvider as _; +use opentelemetry_otlp::{ + LogExporter, Protocol, SpanExporter, WithExportConfig, WithHttpConfig, WithTonicConfig, +}; +use opentelemetry_sdk::Resource; +use opentelemetry_sdk::error::OTelSdkResult; +use opentelemetry_sdk::logs::{BatchLogProcessor, LogProcessor, SdkLogRecord, SdkLoggerProvider}; +use opentelemetry_sdk::trace::SdkTracerProvider; +use tonic::metadata::{MetadataKey, MetadataMap, MetadataValue}; +use tonic::transport::{Certificate, ClientTlsConfig, Identity}; +use tracing_subscriber::Layer; +use tracing_subscriber::layer::SubscriberExt; +use tracing_subscriber::util::SubscriberInitExt; + +use crate::config::{LogLevel, OtelcolConfig, StdoutFormat, TelemetryConfig}; + +/// LogProcessor wrapper that sets timestamp from observed_timestamp. +/// +/// opentelemetry-appender-tracing intentionally doesn't set timestamp because +/// tracing doesn't provide it. This causes some backends to show epoch (1970-01-01). +/// See: https://github.com/open-telemetry/opentelemetry-rust/issues/1479 +#[derive(Debug)] +struct TimestampLogProcessor

(P); +impl LogProcessor for TimestampLogProcessor

{ + fn emit(&self, record: &mut SdkLogRecord, scope: &InstrumentationScope) { + if record.timestamp().is_none() { + let ts = record.observed_timestamp().unwrap_or_else(SystemTime::now); + record.set_timestamp(ts); + } + self.0.emit(record, scope); + } + + fn force_flush(&self) -> OTelSdkResult { + self.0.force_flush() + } + + fn shutdown(&self) -> OTelSdkResult { + self.0.shutdown() + } +} + +macro_rules! build_exporter { + ($Exporter:ident, $cfg:expr, $url:expr, $tls:expr, $path:expr) => { + if $cfg.endpoint.starts_with("http://") { + // with_endpoint() requires full path for HTTP protocol + $Exporter::builder() + .with_http() + .with_protocol(Protocol::HttpBinary) + .with_endpoint(format!("{}{}", $url, $path)) + .with_timeout($cfg.timeout) + .with_headers($cfg.headers.clone()) + .build() + .expect(concat!("failed to build ", stringify!($Exporter))) + } else if $cfg.endpoint.starts_with("grpc://") { + $Exporter::builder() + .with_tonic() + .with_endpoint($url) + .with_timeout($cfg.timeout) + .with_tls_config($tls) + .with_metadata(build_metadata($cfg)) + .build() + .expect(concat!("failed to build ", stringify!($Exporter))) + } else { + panic!( + "invalid OTLP endpoint: {}. Expected http:// or grpc://", + $cfg.endpoint + ) + } + }; +} + +fn build_metadata(cfg: &OtelcolConfig) -> MetadataMap { + let mut metadata = MetadataMap::new(); + for (key, value) in &cfg.headers { + if let (Ok(k), Ok(v)) = ( + key.parse::>(), + value.parse::>(), + ) { + metadata.insert(k, v); + } + } + metadata +} + +pub struct TelemetryService { + logger_provider: Option, + tracer_provider: Option, +} +impl Drop for TelemetryService { + fn drop(&mut self) { + self.shutdown(); + } +} +impl TelemetryService { + pub fn init(config: &TelemetryConfig, service_name: &str, service_version: &str) -> Self { + let env_filter = match std::env::var_os("RECLUSE_LOG") { + Some(val) => tracing_subscriber::EnvFilter::try_new(val.to_string_lossy()) + .expect("Invalid RECLUSE_LOG"), + None => tracing_subscriber::EnvFilter::new(Self::log_level_to_filter( + config.stdout.log_level, + )), + }; + + let mut tracer_provider = None; + let mut logger_provider = None; + + let stdout = config + .stdout + .enabled + .then(|| match config.stdout.log_format { + StdoutFormat::Json => tracing_subscriber::fmt::layer().json().boxed(), + StdoutFormat::Pretty => tracing_subscriber::fmt::layer().pretty().boxed(), + }); + + let (otel_logs, otel_traces) = match &config.otelcol { + Some(cfg) if cfg.enabled => { + let tls = Self::build_tls(cfg); + let url = Self::parse_endpoint(&cfg.endpoint); + let resource = Resource::builder() + .with_service_name(service_name.to_string()) + .with_attribute(KeyValue::new( + opentelemetry_semantic_conventions::attribute::SERVICE_VERSION, + service_version.to_string(), + )) + .build(); + + let logs = cfg.logs.then(|| { + let exporter = + build_exporter!(LogExporter, cfg, url.clone(), tls.clone(), "/v1/logs"); + let provider = SdkLoggerProvider::builder() + .with_resource(resource.clone()) + .with_log_processor(TimestampLogProcessor( + BatchLogProcessor::builder(exporter).build(), + )) + .build(); + let layer = + opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge::new( + &provider, + ) + .with_filter(Self::to_level_filter(cfg.log_level)); + logger_provider = Some(provider); + layer + }); + + let traces = cfg.traces.then(|| { + let provider = SdkTracerProvider::builder() + .with_resource(resource.clone()) + .with_batch_exporter(build_exporter!( + SpanExporter, + cfg, + url.clone(), + tls.clone(), + "/v1/traces" + )) + .build(); + let layer = tracing_opentelemetry::layer() + .with_tracer(provider.tracer(service_name.to_string())); + tracer_provider = Some(provider); + layer + }); + + (logs, traces) + } + _ => (None, None), + }; + + tracing_subscriber::registry() + .with(stdout) + .with(otel_logs) + .with(otel_traces) + .with(env_filter) + .init(); + + Self { + tracer_provider, + logger_provider, + } + } + + fn parse_endpoint(endpoint: &str) -> String { + if endpoint.starts_with("http://") { + endpoint.to_string() + } else if let Some(rest) = endpoint.strip_prefix("grpc://") { + format!("https://{rest}") + } else { + panic!("invalid OTLP endpoint: {endpoint}. Expected http:// or grpc://") + } + } + + fn build_tls(cfg: &OtelcolConfig) -> ClientTlsConfig { + let mut tls = ClientTlsConfig::new().with_native_roots(); + if let Some(path) = &cfg.tls_ca { + tls = tls.ca_certificate(Certificate::from_pem( + std::fs::read_to_string(path).expect("failed to read CA"), + )); + } + if let (Some(crt), Some(key)) = (&cfg.tls_crt, &cfg.tls_key) { + tls = tls.identity(Identity::from_pem( + std::fs::read_to_string(crt).expect("failed to read cert"), + std::fs::read_to_string(key).expect("failed to read key"), + )); + } + tls + } + + fn to_level_filter(level: LogLevel) -> tracing_subscriber::filter::LevelFilter { + match level { + LogLevel::Trace => tracing_subscriber::filter::LevelFilter::TRACE, + LogLevel::Debug => tracing_subscriber::filter::LevelFilter::DEBUG, + LogLevel::Info => tracing_subscriber::filter::LevelFilter::INFO, + LogLevel::Warning => tracing_subscriber::filter::LevelFilter::WARN, + LogLevel::Error => tracing_subscriber::filter::LevelFilter::ERROR, + } + } + + fn log_level_to_filter(level: LogLevel) -> &'static str { + match level { + LogLevel::Trace => "trace", + LogLevel::Debug => "debug", + LogLevel::Info => "info", + LogLevel::Warning => "warn", + LogLevel::Error => "error", + } + } + + pub fn shutdown(&mut self) { + if let Some(p) = self.tracer_provider.take() + && let Err(e) = p.shutdown() + { + tracing::error!("failed to shutdown tracer provider: {e}"); + } + if let Some(p) = self.logger_provider.take() + && let Err(e) = p.shutdown() + { + tracing::error!("failed to shutdown logger provider: {e}"); + } + } +} diff --git a/crates/repos/src/go.rs b/crates/repos/src/go.rs index d591e7d..2637d79 100644 --- a/crates/repos/src/go.rs +++ b/crates/repos/src/go.rs @@ -487,10 +487,10 @@ mod tests_go_filename { upstream: Url::parse("https://dl.google.com/go/").unwrap(), ..Default::default() }; - let url = t.upstream_url(&config, "zorian:test").unwrap(); + let url = t.upstream_url(&config, "recluse:test").unwrap(); assert_eq!( url.as_str(), - "https://dl.google.com/go/go1.25.6.linux-amd64.tar.gz?source=zorian%3Atest" + "https://dl.google.com/go/go1.25.6.linux-amd64.tar.gz?source=recluse%3Atest" ); } diff --git a/crates/zorian/Cargo.toml b/crates/zorian/Cargo.toml deleted file mode 100644 index 4317d22..0000000 --- a/crates/zorian/Cargo.toml +++ /dev/null @@ -1,66 +0,0 @@ -# SPDX-FileCopyrightText: 2026 Nikolay Govorov -# SPDX-License-Identifier: AGPL-3.0-or-later - -[package] -name = "zorian" -description = "Zorian web-server and daemon" -version.workspace = true - -authors.workspace = true -edition.workspace = true -license.workspace = true -publish.workspace = true -homepage.workspace = true -repository.workspace = true - -[dependencies] -base.workspace = true -repos.workspace = true - -async-trait.workspace = true -axum.workspace = true -axum-server.workspace = true -bytes.workspace = true -bytesize.workspace = true -chrono.workspace = true -crc32fast.workspace = true -hex.workspace = true -http-body-util.workspace = true -hyper.workspace = true -hyper-tls.workspace = true -hyper-util.workspace = true -maud.workspace = true -rustls.workspace = true -serde.workspace = true -serde_json.workspace = true -sqlx.workspace = true -thiserror.workspace = true -tokio.workspace = true -tokio-util.workspace = true -toml.workspace = true -tonic.workspace = true -tower.workspace = true -tower-http.workspace = true -tower_governor.workspace = true -tracing.workspace = true -tracing-opentelemetry.workspace = true -tracing-subscriber.workspace = true -url.workspace = true -uuid.workspace = true - -# telemetry -opentelemetry.workspace = true -opentelemetry-appender-tracing.workspace = true -opentelemetry-otlp.workspace = true -opentelemetry-semantic-conventions.workspace = true -opentelemetry_sdk.workspace = true - -[target.'cfg(target_os = "linux")'.dependencies] -sd-notify.workspace = true - -[build-dependencies] -xtask = { path = "../../xtask" } -serde_json.workspace = true - -[dev-dependencies] -tempfile.workspace = true diff --git a/crates/zorian/build.rs b/crates/zorian/build.rs deleted file mode 100644 index 36e1cd6..0000000 --- a/crates/zorian/build.rs +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-FileCopyrightText: 2026 Nikolay Govorov -// SPDX-License-Identifier: AGPL-3.0-or-later - -fn main() { - println!("cargo::rerun-if-changed=../../Cargo.lock"); - - let json = - xtask::licenses::generate_json("Cargo.toml").expect("failed to generate licenses JSON"); - - let out_dir = std::env::var("OUT_DIR").unwrap(); - std::fs::write(format!("{out_dir}/licenses.json"), json) - .expect("failed to write licenses.json"); -} diff --git a/crates/zorian/src/assets/apple-touch-icon.png b/crates/zorian/src/assets/apple-touch-icon.png deleted file mode 100644 index 0f6bb614210c0d59ae108acd732f59175f0ce984..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 715 zcmeAS@N?(olHy`uVBq!ia0vp^2SAvE4M+yv$zcaloCO|{#S9G0-5|_ZdRqK9P*AeO zHKHUqKdq!Zu_%?Hyu4g5GcUV1Ik6yBFTW^#_B$IX1_q`GPZ!6KiaBrZZWKIZAj0Z+ zMj(K-H&DJekagyZhBMR7ybb#>Njf$Dw!~wm(Casu6Vwt1>0w|&_q-~O)tNQqfb-!aYo`|j+`@9U3o(;x_mjFxS^hH3c?nR}=fb(r>kV^z5- W|K3?~yAd!UGI+ZBxvX */ -/* SPDX-License-Identifier: AGPL-3.0-or-later */ - -@font-face { - font-family: 'JetBrains Mono'; - font-style: normal; - font-weight: 100 700; - font-stretch: 100%; - font-display: swap; - src: url(./jetbrainsmono/JetBrainsMono[wght].woff2) format('woff2'); -} - -@font-face { - font-family: 'JetBrains Mono'; - font-style: italic; - font-weight: 100 700; - font-stretch: 100%; - font-display: swap; - src: url(./jetbrainsmono/JetBrainsMono-Italic[wght].woff2) format('woff2'); -} - -*, *::before, *::after { - box-sizing: border-box; -} - -:root { - line-height: 1.4; - font-family: 'JetBrains Mono', monospace; - color-scheme: light dark; - - --color-text: #222; - --color-bg: #fff; - --color-border: #222; - --color-code-bg: #818b981f; - --color-license-bg: antiquewhite; - --color-link: #0969da; -} - -@media (prefers-color-scheme: dark) { - :root { - --color-text: #e0e0e0; - --color-bg: #1a1a1a; - --color-border: #555; - --color-code-bg: #ffffff12; - --color-license-bg: #2a2a2a; - --color-link: #58a6ff; - } -} - -html { - margin: 0; - padding: 0; -} - -body { - margin: 0 auto; - max-width: 80ch; - padding: 1.5em 2em; - color: var(--color-text); - background-color: var(--color-bg); -} - -code { - margin: 0; - padding: .2em .4em; - white-space: break-spaces; - background-color: var(--color-code-bg); -} - -h1, h2, h3, h4 { - margin: 1.5rem 0 0.5rem; - font-weight: 700; - line-height: 1.2; - text-wrap: balance; -} - -h1 { font-size: 2.25rem; line-height: 1.1; } -h2 { font-size: 1.5rem; } -h3 { font-size: 1.15rem; } -h4 { font-size: 1rem; } - -h1:first-child { margin-top: 0; } - -p, details { - margin: 1em 0; - text-wrap: pretty; -} - -table { - border-collapse: collapse; -} - -th, td { - padding: 7px 8px; - border: 2px solid var(--color-border); - text-align: start; - vertical-align: top; -} - -a { - color: var(--color-link); -} - -h3 a { - color: inherit; - text-decoration: none; -} - -h3 a:hover { - text-decoration: underline; -} - -.license { - margin: 1rem 0; -} - -.license-used-by { - margin-top: -10px; -} - -.license-text { - max-height: 280px; - overflow-y: scroll; - white-space: pre-wrap; - background-color: var(--color-license-bg); - border-left: 4px solid var(--color-border); - padding: 0.8em 1em; -} diff --git a/crates/zorian/src/assets/favicon-192.png b/crates/zorian/src/assets/favicon-192.png deleted file mode 100644 index 0f6bb614210c0d59ae108acd732f59175f0ce984..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 715 zcmeAS@N?(olHy`uVBq!ia0vp^2SAvE4M+yv$zcaloCO|{#S9G0-5|_ZdRqK9P*AeO zHKHUqKdq!Zu_%?Hyu4g5GcUV1Ik6yBFTW^#_B$IX1_q`GPZ!6KiaBrZZWKIZAj0Z+ zMj(K-H&DJekagyZhBMR7ybb#>Njf$Dw!~wm(Casu6Vwt1>0w|&_q-~O)tNQqfb-!aYo`|j+`@9U3o(;x_mjFxS^hH3c?nR}=fb(r>kV^z5- W|K3?~yAd!UGI+ZBxvX9gP2NHH*QEc0}645^s&_J(2a5eEU+ zgR>_yFE-eCG(E}fVa~LpWgk`v)U2GmJg)k^J;Q>h^;HZEAF6@YH?c4u|VWXxp&u`@U~q*k%;f%`@HGs3$)f8BN#jRaZIR zs*dMlP?zT+>h87;*|OLJ(g7FGTJB`?E){?S}AIBNGVtQO%)`N1FB?19Z122WQ%mvv4F FO#l|3Ajkj! diff --git a/crates/zorian/src/assets/favicon.ico b/crates/zorian/src/assets/favicon.ico deleted file mode 100644 index 093e50bda4580e7ef4100b9e057d2e8cc47b2936..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32038 zcmeHPyKWRq5G@N!geD?_$&AU0wTVFPl1Hk84fHD-Mc=} zl)I>HS50s4s^+RyQ?GMQ&D7nCmenOXphJ4}h>~5<`$M8vM6_6}{Vys0HN{R(Z~bRP zZypmZmuvszCDF|bqLb8L7J1F0o?ERCdEUo;)N#w}B%k-em+E&rPU+wO_4)pgs60R45#@u})iF^% zsLwWk&MeYdrjtLfR#*Dq`IK(*!L{4ZXn#H<<2{V^F7esoWn15`7cX#vziq$p+`Mc& z|J{E6{QdF0XwCC_?pyJ-e$K~zt>2pGeB8IN&pVYj~}BjgRMB@uR-&zt8c!_U3t|S9$lkCOZG` zIXgSQE)T1pzCD=!Id>^mk^DVH`pT5vrt{}}il;}dO43pbJ@#rd-ZZE&oV7c$5m-AROm%SVpepyrABhPJF zQ{MAB_+^dd9(deJn7j_YSG|NI#lg?*w(2EbDb97n-&VcEE5)Ig+ilfLyi%O&hQF

R4Zc>LQa$i`TS-rAyti)fwd$1Wf!EtgdRpVXb%U=}XKOupthSZc ztKO;`{a$)nalmi2t-N0KR^90L($k6qeyeTe^{Th(M!%Pyz=^+ih#iO>h#iO>*r6TB zQuA+sZ1!XNol(Y_%U)a^Uu67EZL5wOq7NB=Q)_)*xBdBdTFZ2j+`qrmN`dDG>yyH( zE5DpL@eE=IVh3UeVh3UeVh3UeVh3UeVh3tFfbTX(wKdJ2u~FxSF3(wOSl}7e)--#@ zMx7hFJZG(8foD`()9e`=b#CbLoVA7po>6U0vuAA7xuMH*)*2RgMzuA~p0QEqhAz)p zYgphJ)z&n7#zvhRx;$sCVS#5~^9(9tf^?1f4Uc@yn)Jb;kehpvCOS%ysyz8;(iEH|; z`BCPSbXe!p`X$~`;+lSIev~;S9oG4@eu;OKxTfElA7xHShjl({zog46Zq+w;zt@}+ z&fNN~_>yj~xK-cW{a$lQICJZ_;!C={;#Pfg_j}DL;mobyiZAK*id*%~-S0K0gfqAP zz>nX3#ty^|#16y`#16y`#16y`#18EB4y4yR<8_(;Hv>o0v^9Hlnf^)q_q9g-dGJKP NdI0ybGrpSy{TrMyi)R1; diff --git a/crates/zorian/src/assets/favicon.svg b/crates/zorian/src/assets/favicon.svg deleted file mode 100644 index ed7cc17..0000000 --- a/crates/zorian/src/assets/favicon.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/crates/zorian/src/assets/jetbrainsmono/JetBrainsMono-Italic[wght].woff2 b/crates/zorian/src/assets/jetbrainsmono/JetBrainsMono-Italic[wght].woff2 deleted file mode 100644 index 98adc803f58f81df8410f4ad433e46b773e1b8d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 122452 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 diff --git a/crates/zorian/src/assets/jetbrainsmono/JetBrainsMono[wght].woff2 b/crates/zorian/src/assets/jetbrainsmono/JetBrainsMono[wght].woff2 deleted file mode 100644 index 4cd1413366e027b0929706deb3ac04baf7328526..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 113700 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 z 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 -// SPDX-License-Identifier: AGPL-3.0-or-later - -use std::collections::HashMap; -use std::fs; -use std::net::SocketAddr; -use std::path::{Path, PathBuf}; -use std::time::Duration; - -use bytesize::ByteSize; -use serde::Deserialize; -use thiserror::Error; -use tracing::info; - -use base::serde::{deserialize_duration, deserialize_listener_addr}; -use repos::{GoConfig, ZigConfig}; - -#[derive(Debug, Error)] -pub enum ConfigError { - #[error("failed to read config file: {0}")] - Io(#[from] std::io::Error), - - #[error("failed to parse config file: {0}")] - Parse(#[from] toml::de::Error), - - #[error("appname '{0}' contains invalid characters (only a-z, A-Z, 0-9, -, _ allowed)")] - InvalidAppname(String), - - #[error("dirname '{0}' does not exist")] - DirNotFound(PathBuf), - - #[error("dirname '{0}' is not a directory")] - NotADirectory(PathBuf), - - #[error("dirname '{0}' is not writable: {1}")] - NotWritable(PathBuf, std::io::Error), - - #[error("listener '{0}': tls_crt is set but tls_key is missing")] - TlsKeyMissing(SocketAddr), - - #[error("listener '{0}': tls_key is set but tls_crt is missing")] - TlsCrtMissing(SocketAddr), - - #[error("listener '{0}': TLS crtificate file not found: {1}")] - TlsCrtNotFound(SocketAddr, PathBuf), - - #[error("listener '{0}': TLS key file not found: {1}")] - TlsKeyNotFound(SocketAddr, PathBuf), -} - -#[derive(Debug, Clone, Deserialize)] -pub struct ServerConfig { - /// When receiving a SIGINT/SIGTERM signal, we will wait for the proposed timeout before terminating workers - #[serde(deserialize_with = "deserialize_duration")] - pub shutdown_timeout: Duration, - - /// Request timeout - maximum time to process a request (protects against Slowloris) - #[serde(deserialize_with = "deserialize_duration")] - pub request_timeout: Duration, - - /// Maximum request body size - pub max_body_size: ByteSize, - - /// Maximum number of concurrent requests across all clients - pub max_concurrent_requests: usize, - - /// Rate limit: requests per second per client IP - #[serde(deserialize_with = "deserialize_duration")] - pub rate_limit_period: Duration, - - /// Rate limit: burst size (max requests allowed in a burst) per client IP - pub rate_limit_burst_size: u32, -} - -impl Default for ServerConfig { - fn default() -> Self { - Self { - shutdown_timeout: Duration::from_secs(60), - request_timeout: Duration::from_secs(30), - max_body_size: ByteSize::mb(64), - max_concurrent_requests: 512, - rate_limit_period: Duration::from_secs(10), - rate_limit_burst_size: 50, - } - } -} - -#[derive(Debug, Clone, Deserialize)] -pub struct ListenerConfig { - #[serde(deserialize_with = "deserialize_listener_addr")] - pub addr: SocketAddr, - - /// Hostnames to accept for this listener. Empty means accept all. - pub hostnames: Vec, - - /// Path to TLS certificate file (PEM format). If set, tls_key must also be set. - pub tls_crt: Option, - - /// Path to TLS private key file (PEM format). If set, tls_crt must also be set. - pub tls_key: Option, -} - -impl Default for ListenerConfig { - fn default() -> Self { - Self { - addr: "127.0.0.1:2025".parse().unwrap(), - hostnames: vec![ - String::from("[::1]"), - String::from("127.0.0.1"), - String::from("localhost"), - ], - tls_crt: None, - tls_key: None, - } - } -} - -#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq, PartialOrd, Ord)] -#[serde(rename_all = "lowercase")] -pub enum LogLevel { - Trace, - Debug, - Info, - Warning, - Error, -} - -#[derive(Debug, Clone, Copy, Deserialize, Default, PartialEq, Eq)] -#[serde(rename_all = "lowercase")] -pub enum StdoutFormat { - #[default] - Pretty, - Json, -} - -#[derive(Debug, Clone, Deserialize)] -#[serde(default)] -pub struct StdoutConfig { - /// Enables sending logs to the stdout - pub enabled: bool, - - /// Controls which logs will be sent to stdout - pub log_level: LogLevel, - - /// Controls the format of logs in stdout - pub log_format: StdoutFormat, -} - -impl Default for StdoutConfig { - fn default() -> Self { - Self { - enabled: true, - log_level: LogLevel::Info, - log_format: StdoutFormat::Pretty, - } - } -} - -#[derive(Debug, Clone, Deserialize)] -#[serde(default)] -pub struct OtelcolConfig { - /// Enables sending telemetry to the otlp collector - pub enabled: bool, - - /// Send logs to OTLP at this level (None = disabled) - pub logs: bool, - - /// Send traces to OTLP - pub traces: bool, - - /// Send traces to OTLP - pub metrics: bool, - - /// OTLP endpoint (grpc:// or http://) - pub endpoint: String, - - /// Export timeout in seconds - #[serde(deserialize_with = "deserialize_duration")] - pub timeout: Duration, - - /// Controls which logs will be sent to otlp - pub log_level: LogLevel, - - /// Path to CA certificate for TLS (required for grpcs://) - pub tls_ca: Option, - - /// Path to client certificate for mTLS - pub tls_crt: Option, - - /// Path to client key for mTLS - pub tls_key: Option, - - /// HTTP headers for authentication - pub headers: HashMap, -} - -impl Default for OtelcolConfig { - fn default() -> Self { - Self { - enabled: true, - logs: true, - traces: true, - metrics: true, - timeout: Duration::from_secs(10), - endpoint: "http://localhost:4317".into(), - log_level: LogLevel::Info, - tls_ca: None, - tls_crt: None, - tls_key: None, - headers: HashMap::new(), - } - } -} - -#[derive(Debug, Clone, Deserialize, Default)] -#[serde(default)] -pub struct TelemetryConfig { - pub stdout: StdoutConfig, - pub otelcol: Option, -} - -#[derive(Debug, Clone, Deserialize, Default)] -#[serde(default)] -pub struct BackendsConfig { - pub go: GoConfig, - pub zig: ZigConfig, -} - -#[derive(Debug, Deserialize)] -#[serde(default)] -pub struct ConfigService { - appname: String, - dirname: PathBuf, - listen: Vec, - server: ServerConfig, - telemetry: TelemetryConfig, - backends: BackendsConfig, -} - -impl Default for ConfigService { - fn default() -> Self { - Self { - appname: "zorian".to_string(), - dirname: PathBuf::from("./.zorian-state"), - listen: vec![ListenerConfig::default()], - server: ServerConfig::default(), - telemetry: TelemetryConfig::default(), - backends: BackendsConfig::default(), - } - } -} - -impl ConfigService { - pub fn load(config_path: Option) -> Result { - let config = match config_path { - Some(path) => { - info!("use config file from {}", path.to_str().unwrap()); - - let content = fs::read_to_string(path)?; - toml::from_str(&content)? - } - None => { - info!("configuration file path not provided"); - Self::default() - } - }; - - config.validate() - } - - fn validate(self) -> Result { - let mut chars = self.appname.chars(); - if !chars.all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_') { - return Err(ConfigError::InvalidAppname(self.appname.clone())); - } - - let metadata = fs::metadata(&self.dirname).map_err(|e| { - if e.kind() == std::io::ErrorKind::NotFound { - ConfigError::DirNotFound(self.dirname.clone()) - } else { - ConfigError::Io(e) - } - })?; - - if !metadata.is_dir() { - return Err(ConfigError::NotADirectory(self.dirname.clone())); - } - - let testfile = self.dirname.join(".health"); - fs::write(&testfile, std::process::id().to_string()) - .map_err(|e| ConfigError::NotWritable(self.dirname.clone(), e))?; - fs::remove_file(&testfile)?; - - // Validate listener configuration - for listener in &self.listen { - match (&listener.tls_crt, &listener.tls_key) { - (Some(_crt), None) => { - return Err(ConfigError::TlsKeyMissing(listener.addr)); - } - (None, Some(_)) => { - return Err(ConfigError::TlsCrtMissing(listener.addr)); - } - (Some(crt), Some(key)) => { - if !crt.exists() { - return Err(ConfigError::TlsCrtNotFound(listener.addr, crt.clone())); - } - if !key.exists() { - return Err(ConfigError::TlsKeyNotFound(listener.addr, key.clone())); - } - } - (None, None) => {} - } - } - - Ok(self) - } - - pub fn appname(&self) -> &str { - &self.appname - } - - pub fn dirname(&self) -> &Path { - &self.dirname - } - - pub fn server(&self) -> &ServerConfig { - &self.server - } - - pub fn listeners(&self) -> &[ListenerConfig] { - &self.listen - } - - pub fn telemetry(&self) -> &TelemetryConfig { - &self.telemetry - } - - pub fn backends(&self) -> &BackendsConfig { - &self.backends - } -} - -#[cfg(test)] -impl ConfigService { - pub fn for_test(dirname: PathBuf) -> Self { - Self { - appname: "test".to_string(), - dirname, - server: ServerConfig::default(), - listen: vec![ListenerConfig { - addr: "127.0.0.1:0".parse().unwrap(), - hostnames: Vec::new(), - tls_crt: None, - tls_key: None, - }], - telemetry: TelemetryConfig::default(), - backends: BackendsConfig::default(), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use tempfile::TempDir; - - fn base_config(dir: PathBuf) -> ConfigService { - ConfigService { - appname: "valid-name".to_string(), - dirname: dir, - server: ServerConfig::default(), - listen: vec![ListenerConfig { - addr: "127.0.0.1:0".parse().unwrap(), - hostnames: Vec::new(), - tls_crt: None, - tls_key: None, - }], - telemetry: TelemetryConfig::default(), - backends: BackendsConfig::default(), - } - } - - fn write_temp_file(dir: &Path, name: &str) -> PathBuf { - let path = dir.join(name); - std::fs::write(&path, "x").unwrap(); - path - } - - mod defaults_tests { - use super::*; - - #[test] - fn test_for_test_config() { - let dir = TempDir::new().unwrap(); - let cfg = ConfigService::for_test(dir.path().to_path_buf()); - assert_eq!(cfg.appname(), "test"); - assert_eq!(cfg.dirname(), dir.path()); - } - - #[test] - fn test_listener_default() { - let cfg = ListenerConfig::default(); - assert!(cfg.hostnames.contains(&"localhost".to_string())); - } - } - - mod load_tests { - use super::*; - - #[test] - fn test_load_none_defaults() { - let temp = TempDir::new().unwrap(); - let state = temp.path().join(".zorian-state"); - std::fs::create_dir_all(&state).unwrap(); - let cwd = std::env::current_dir().unwrap(); - std::env::set_current_dir(temp.path()).unwrap(); - - let cfg = ConfigService::load(None).unwrap(); - assert_eq!(cfg.appname(), "zorian"); - - std::env::set_current_dir(cwd).unwrap(); - } - - #[test] - fn test_load_some_and_parse_error() { - let dir = TempDir::new().unwrap(); - let good = dir.path().join("good.toml"); - let bad = dir.path().join("bad.toml"); - let missing = dir.path().join("missing.toml"); - let state = dir.path().join("state"); - std::fs::create_dir_all(&state).unwrap(); - - std::fs::write( - &good, - format!( - "appname = \"ok\"\n\ - dirname = \"{}\"\n\ - listen = []\n\ - [server]\n\ - shutdown_timeout = 1\n\ - request_timeout = 1\n\ - max_body_size = \"1 MB\"\n\ - max_concurrent_requests = 1\n\ - rate_limit_period = 1\n\ - rate_limit_burst_size = 1\n\ - [telemetry]\n\ - [telemetry.stdout]\n\ - enabled = true\n\ - log_level = \"info\"\n\ - log_format = \"pretty\"\n\ - [backends]\n\ - [backends.go]\n\ - [backends.zig]\n", - state.display() - ), - ) - .unwrap(); - - std::fs::write(&bad, "not = [valid").unwrap(); - - let cfg = ConfigService::load(Some(good)).unwrap(); - assert_eq!(cfg.appname(), "ok"); - - let err = ConfigService::load(Some(missing)).unwrap_err(); - assert!(err.to_string().contains("failed to read")); - - let err = ConfigService::load(Some(bad)).unwrap_err(); - assert!(err.to_string().contains("failed to parse")); - } - } - - mod validation_tests { - use super::*; - - #[test] - fn test_validate_invalid_appname() { - let dir = TempDir::new().unwrap(); - let mut cfg = base_config(dir.path().to_path_buf()); - cfg.appname = "bad name!".to_string(); - let err = cfg.validate().unwrap_err(); - assert!(err.to_string().contains("appname 'bad name!'")); - } - - #[test] - fn test_validate_dir_not_found() { - let temp = TempDir::new().unwrap(); - let missing = temp.path().join("missing-dir"); - let cfg = base_config(missing); - let err = cfg.validate().unwrap_err(); - assert!(err.to_string().contains("does not exist")); - } - - #[test] - fn test_validate_not_a_directory() { - let dir = TempDir::new().unwrap(); - let file_path = dir.path().join("file"); - std::fs::write(&file_path, "x").unwrap(); - let cfg = base_config(file_path); - let err = cfg.validate().unwrap_err(); - assert!(err.to_string().contains("is not a directory")); - } - - #[cfg(unix)] - #[test] - fn test_validate_metadata_io_error() { - use std::os::unix::fs::PermissionsExt; - - let dir = TempDir::new().unwrap(); - let child = dir.path().join("child"); - std::fs::create_dir_all(&child).unwrap(); - - let mut perms = std::fs::metadata(dir.path()).unwrap().permissions(); - perms.set_mode(0o000); - std::fs::set_permissions(dir.path(), perms).unwrap(); - - let cfg = base_config(child.clone()); - let err = cfg.validate().unwrap_err(); - assert!(err.to_string().contains("failed to read")); - - let mut perms = std::fs::metadata(dir.path()).unwrap().permissions(); - perms.set_mode(0o700); - std::fs::set_permissions(dir.path(), perms).unwrap(); - } - - #[cfg(unix)] - #[test] - fn test_validate_not_writable() { - use std::os::unix::fs::PermissionsExt; - - let dir = TempDir::new().unwrap(); - let mut perms = std::fs::metadata(dir.path()).unwrap().permissions(); - perms.set_mode(0o400); - std::fs::set_permissions(dir.path(), perms).unwrap(); - - let cfg = base_config(dir.path().to_path_buf()); - let err = cfg.validate().unwrap_err(); - assert!(err.to_string().contains("not writable")); - } - - #[test] - fn test_validate_tls_key_missing() { - let dir = TempDir::new().unwrap(); - let mut cfg = base_config(dir.path().to_path_buf()); - cfg.listen = vec![ListenerConfig { - addr: "127.0.0.1:0".parse().unwrap(), - hostnames: Vec::new(), - tls_crt: Some(PathBuf::from("/tmp/does-not-matter.crt")), - tls_key: None, - }]; - let err = cfg.validate().unwrap_err(); - assert!(err.to_string().contains("tls_key is missing")); - } - - #[test] - fn test_validate_tls_crt_missing() { - let dir = TempDir::new().unwrap(); - let mut cfg = base_config(dir.path().to_path_buf()); - cfg.listen = vec![ListenerConfig { - addr: "127.0.0.1:0".parse().unwrap(), - hostnames: Vec::new(), - tls_crt: None, - tls_key: Some(PathBuf::from("/tmp/does-not-matter.key")), - }]; - let err = cfg.validate().unwrap_err(); - assert!(err.to_string().contains("tls_crt is missing")); - } - - #[test] - fn test_validate_tls_files_not_found() { - let dir = TempDir::new().unwrap(); - let mut cfg = base_config(dir.path().to_path_buf()); - cfg.listen = vec![ListenerConfig { - addr: "127.0.0.1:0".parse().unwrap(), - hostnames: Vec::new(), - tls_crt: Some(PathBuf::from("/tmp/missing.crt")), - tls_key: Some(PathBuf::from("/tmp/missing.key")), - }]; - let err = cfg.validate().unwrap_err(); - assert!(err.to_string().contains("TLS crtificate file not found")); - } - - #[test] - fn test_validate_tls_key_not_found() { - let dir = TempDir::new().unwrap(); - let mut cfg = base_config(dir.path().to_path_buf()); - let crt = write_temp_file(dir.path(), "cert.pem"); - cfg.listen = vec![ListenerConfig { - addr: "127.0.0.1:0".parse().unwrap(), - hostnames: Vec::new(), - tls_crt: Some(crt), - tls_key: Some(dir.path().join("missing.key")), - }]; - let err = cfg.validate().unwrap_err(); - assert!(err.to_string().contains("TLS key file not found")); - } - - #[test] - fn test_validate_tls_files_exist() { - let dir = TempDir::new().unwrap(); - let mut cfg = base_config(dir.path().to_path_buf()); - let crt = write_temp_file(dir.path(), "cert.pem"); - let key = write_temp_file(dir.path(), "key.pem"); - cfg.listen = vec![ListenerConfig { - addr: "127.0.0.1:0".parse().unwrap(), - hostnames: Vec::new(), - tls_crt: Some(crt), - tls_key: Some(key), - }]; - cfg.validate().unwrap(); - } - - #[test] - fn test_validate_ok_and_getters() { - let dir = TempDir::new().unwrap(); - let mut cfg = base_config(dir.path().to_path_buf()); - cfg.listen = vec![ListenerConfig::default()]; - - let cfg = cfg.validate().unwrap(); - assert_eq!(cfg.appname(), "valid-name"); - assert_eq!(cfg.dirname(), dir.path()); - let _ = cfg.server(); - let _ = cfg.listeners(); - let _ = cfg.telemetry(); - let _ = cfg.backends(); - } - } -} diff --git a/crates/zorian/src/controller_backend.rs b/crates/zorian/src/controller_backend.rs deleted file mode 100644 index d14d93b..0000000 --- a/crates/zorian/src/controller_backend.rs +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-FileCopyrightText: 2026 Nikolay Govorov -// SPDX-License-Identifier: AGPL-3.0-or-later - -use std::sync::Arc; - -use axum::{Router, body, extract, http, response, routing}; -use tracing::error; - -use crate::proxy; -use crate::storage; -use repos::{Backend, BackendError, BackendSpec, ResolvedFile}; - -/// Generic controller for backend HTTP handling. -pub struct BackendController { - backend: Arc>, - storage: Arc, - upstream: Arc, -} - -impl BackendController { - pub fn new( - backend: Arc>, - storage: Arc, - upstream: Arc, - ) -> Self { - Self { - backend, - storage, - upstream, - } - } - - pub fn router(self: Arc) -> Router { - Router::new() - .route("/{filename}", routing::get(Self::handle)) - .with_state(self) - } - - async fn handle( - extract::State(controller): extract::State>, - extract::Path(filename): extract::Path, - ) -> Result { - let (url, mime) = match controller.backend.resolve_file(&filename).await { - Ok(ResolvedFile::Content { data, mime }) => { - return Ok(Self::build_response(http::StatusCode::OK, data, mime)); - } - Ok(ResolvedFile::Upstream { url, mime }) => (url, mime), - Err(BackendError::NotFound) => { - error!(backend = S::ID, filename, "file not found"); - return Err(http::StatusCode::NOT_FOUND); - } - Err(e) => { - error!(backend = S::ID, filename, "error resolving file: {e}"); - return Err(http::StatusCode::INTERNAL_SERVER_ERROR); - } - }; - - match controller.storage.get(S::ID, &filename).await { - Ok(Some(entry)) => { - return Ok(Self::build_response( - http::StatusCode::OK, - entry.file_bytes.0, - mime, - )); - } - Ok(None) => {} - Err(err) => { - error!( - backend = S::ID, - filename, "failed to get file from storage: {err}" - ); - return Err(http::StatusCode::INTERNAL_SERVER_ERROR); - } - } - - let entry = controller - .upstream - .fetch(proxy::DownloadRequest { url }) - .await?; - - match controller.storage.put(S::ID, &filename, &entry.bytes).await { - Ok(()) => {} - Err(err) => { - error!( - backend = S::ID, - filename, "failed to put file to storage: {err}" - ); - return Err(http::StatusCode::INTERNAL_SERVER_ERROR); - } - } - - Ok(Self::build_response( - http::StatusCode::OK, - entry.bytes, - mime, - )) - } - - fn build_response( - status: http::StatusCode, - bytes: bytes::Bytes, - mime: repos::ContentType, - ) -> response::Response { - response::Response::builder() - .status(status) - .header(http::header::CONTENT_TYPE, mime.as_str()) - .header(http::header::CONTENT_LENGTH, bytes.len()) - .body(body::Body::from(bytes)) - .unwrap() - } -} diff --git a/crates/zorian/src/controller_web.rs b/crates/zorian/src/controller_web.rs deleted file mode 100644 index ebd9ce1..0000000 --- a/crates/zorian/src/controller_web.rs +++ /dev/null @@ -1,486 +0,0 @@ -// SPDX-FileCopyrightText: 2026 Nikolay Govorov -// SPDX-License-Identifier: AGPL-3.0-or-later - -use std::future::Future; -use std::pin::Pin; -use std::sync::{Arc, LazyLock}; -use std::task::{Context, Poll}; - -use axum::body::Body; -use axum::http::{HeaderValue, Method, Request, Response, StatusCode, header}; -use axum::{extract, routing}; -use maud::{Markup, html}; -use serde::Deserialize; -use tower::{Layer, Service}; -use tracing::error; - -use base::ContentType; -use repos::{GoBackend, ZigBackend}; - -fn get_asset(path: &str) -> Option<(&'static [u8], ContentType)> { - Some(match path { - "base.css" => (include_bytes!("assets/base.css"), ContentType::TextCss), - "favicon.svg" => ( - include_bytes!("assets/favicon.svg"), - ContentType::ImageSvgXml, - ), - "favicon.ico" => ( - include_bytes!("assets/favicon.ico"), - ContentType::ImageXIcon, - ), - "favicon-192.png" | "apple-touch-icon.png" => ( - include_bytes!("assets/favicon-192.png"), - ContentType::ImagePng, - ), - "favicon-512.png" => ( - include_bytes!("assets/favicon-512.png"), - ContentType::ImagePng, - ), - "manifest.webmanifest" => ( - include_bytes!("assets/manifest.webmanifest"), - ContentType::ApplicationManifestJson, - ), - "jetbrainsmono/JetBrainsMono[wght].woff2" => ( - include_bytes!("assets/jetbrainsmono/JetBrainsMono[wght].woff2"), - ContentType::FontWoff2, - ), - "jetbrainsmono/JetBrainsMono-Italic[wght].woff2" => ( - include_bytes!("assets/jetbrainsmono/JetBrainsMono-Italic[wght].woff2"), - ContentType::FontWoff2, - ), - "robots.txt" => (include_bytes!("assets/robots.txt"), ContentType::TextPlain), - _ => return None, - }) -} - -const CSP: &str = "default-src 'self'; base-uri 'none'; img-src 'self'; font-src 'self'; style-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none'"; - -#[derive(Deserialize)] -struct LicenseList { - overview: Vec, - licenses: Vec, -} - -#[derive(Deserialize)] -struct LicenseOverview { - id: String, - name: String, - count: usize, -} - -#[derive(Deserialize)] -struct LicenseEntry { - id: String, - name: String, - text: String, - first_of_kind: bool, - used_by: Vec, -} - -#[derive(Deserialize)] -struct LicenseUsedBy { - #[serde(rename = "crate")] - crate_: LicenseCrate, -} - -#[derive(Deserialize)] -#[allow(dead_code)] -struct LicenseCrate { - name: String, - version: String, - repository: Option, -} - -static LICENSES: LazyLock = LazyLock::new(|| { - let json = include_str!(concat!(env!("OUT_DIR"), "/licenses.json")); - serde_json::from_str(json).expect("failed to parse licenses.json") -}); - -/// Handles html pages rendering and static files -pub struct WebController { - zig: Option>, - go: Option>, -} - -impl WebController { - pub fn new(zig: Option>, go: Option>) -> Self { - Self { zig, go } - } -} - -impl WebController { - pub fn router(self: Arc) -> axum::Router { - axum::Router::new() - .route("/", axum::routing::get(Self::index)) - .route("/{*path}", routing::get(Self::assets)) - .route("/about/licenses", axum::routing::get(Self::licenses)) - .layer(CacheLayer) - .layer(tower_http::set_header::SetResponseHeaderLayer::overriding( - header::CONTENT_SECURITY_POLICY, - HeaderValue::from_static(CSP), - )) - .with_state(self.clone()) - } - - async fn assets(extract::Path(path): extract::Path) -> Response { - let Some((data, content_type)) = get_asset(&path) else { - return Response::builder() - .status(StatusCode::NOT_FOUND) - .body(Body::empty()) - .unwrap(); - }; - - let mut builder = Response::builder() - .status(StatusCode::OK) - .header(header::CONTENT_TYPE, content_type.as_str()); - - if matches!(content_type, ContentType::FontWoff2) { - builder = builder.header(header::CACHE_CONTROL, "public, max-age=31536000, immutable"); - } - - builder.body(Body::from(data)).unwrap() - } - - async fn index(extract::State(ctrl): extract::State>) -> Markup { - let zig_versions = if let Some(ref backend) = ctrl.zig { - match backend.get_releases().await { - Ok(v) => v, - Err(e) => { - error!("failed to get zig versions: {e}"); - Vec::new() - } - } - } else { - Vec::new() - }; - - let go_versions = if let Some(ref backend) = ctrl.go { - match backend.get_releases().await { - Ok(v) => v, - Err(e) => { - error!("failed to get go versions: {e}"); - Vec::new() - } - } - } else { - Vec::new() - }; - - WebController::layout( - "Zorian — tiny & opinionated packages mirror", - html! { - h1 { "Zorian — tiny & opinionated packages mirror." } - - p { - r#"This site provides a caching proxy for downloading Zig and Go installation files. - It reduces load on upstream servers and makes your infrastructure more reliable by adding redundancy."# - } - - p { - "Zorian is open source software licensed under " a href="https://www.gnu.org/licenses/agpl-3.0.html" { "AGPL-3.0" } ". " - "Source code is available on " a href="https://github.com/mrdimidium/zorian" { "GitHub" } ". " - "A list of dependency licenses " a href="/about/licenses" { "is available" } "." - } - - h2 { "Usage" } - - p { - "Replace official download URLs with " code { "https://pkg.earth/{tool}/{filename}" } ". " - "Files are cached automatically after the first download." - } - - h3 id="zig" { - a href="#zig" { "Zig" } - } - - @if !zig_versions.is_empty() { - details { - summary { "Available versions (" (zig_versions.len()) ")" } - - p { "You can take actual minisig public key at " a href="https://ziglang.org/download/" { "ziglang.org/download" } "." } - table { - thead { - tr { - th { "Version" } - th { "Date" } - th { "Docs" } - th { "Targets" } - } - } - tbody { - @for v in zig_versions.iter().rev() { - tr { - td { (v.version) } - td { (v.meta.date.as_deref().unwrap_or("-")) } - td { - @if let Some(ref url) = v.meta.docs { - a href=(url) { "docs" } - } - " " - @if let Some(ref url) = v.meta.std_docs { - a href=(url) { "std" } - } - " " - @if let Some(ref url) = v.meta.notes { - a href=(url) { "notes" } - } - } - td { - @for file in &v.files { - a href=(format!("/zig/{}", file.filename)) { (&file.meta.target) } - " " - } - } - } - } - } - } - } - } - - p { - "Read more about community mirrors in the " a href="https://ziglang.org/download/community-mirrors/" { "blog post" } ". " - "Information on how to deploy your own mirror is available " a href="https://github.com/ziglang/www.ziglang.org/blob/main/MIRRORS.md" { "in the documentation" } "." - } - - p { - "For simplicity, you can use tools like " a href="https://github.com/prantlf/zigup" { "prantlf/zigup" } - " and " a href="https://github.com/mlugg/setup-zig" { "mlugg/setup-zig" } "." - } - - p { - "To install manually:" - ol { - li { "download zig dist file:" br; code { "wget https://pkg.earth/zig/zig-x86_64-linux-0.15.1.tar.xz" } ";" } - li { "download zig minisig file:" br; code { "wget https://pkg.earth/zig/zig-x86_64-linux-0.15.1.tar.xz.minisig" } ";" } - li { "check archive integrity:" br; code { "minisign -Vm zig-x86_64-linux-0.15.1.tar.xz -P RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U" } ";" } - li { "unpack archive:" br; code { "tar -xf 'zig-x86_64-linux-0.15.1.tar.xz'" } ";" } - li { "check installed zig:" br; code { "./zig-x86_64-linux-0.15.1/zig --version" } ";" } - } - } - - h3 id="go" { a href="#go" { "Go" } } - - @if !go_versions.is_empty() { - details { - summary { "Available versions (" (go_versions.len()) ")" } - - p { "You can find available versions at " a href="https://go.dev/dl/" { "go.dev/dl" } "." } - table { - thead { - tr { - th { "Version" } - th { "Stable" } - th { "Files" } - } - } - tbody { - @for v in go_versions.iter().rev() { - tr { - td { (v.version) } - td { @if v.meta.stable { "✓" } @else { "" } } - td { - @for file in &v.files { - a href=(format!("/go/{}", file.filename)) { (file.filename) } - " " - } - } - } - } - } - } - } - } - - p { "To install manually:" } - - ol { - li { "download go dist file:" br; code { "wget https://pkg.earth/go/go1.23.0.linux-amd64.tar.gz" } ";" } - li { "download go sha256 file:" br; code { "wget https://pkg.earth/go/go1.23.0.linux-amd64.tar.gz.sha256" } ";" } - li { "check archive integrity:" br; code { "sha256sum -c go1.23.0.linux-amd64.tar.gz.sha256" } ";" } - li { "unpack archive:" br; code { "tar -xzf go1.23.0.linux-amd64.tar.gz" } ";" } - li { "check installed go:" br; code { "./go/bin/go version" } ";" } - } - - h2 { "Privacy policy" } - - p { "This mirror is a non-profit project available on a voluntary basis. The author has no plans to fund it." } - - p { r#"Since the mirror is hosted on hardware, we collect access logs to combat bots and brute-force attacks. - The logs are used for security purposes and load planning, are not shared with third parties, - and are deleted after 30 days."# } - - p { "Third-party analytics systems are not used, same as client-side trackers." } - }, - ) - } - - async fn licenses() -> Markup { - let data = &*LICENSES; - - WebController::layout( - "Third Party Licenses", - html! { - h1 { "Licenses" } - - h2 { "Zorian" } - - p { - "Zorian is licensed under the " b { "GNU Affero General Public License v3.0 (AGPL-3.0)" } ". " - "This means you are free to use, modify, and distribute the software. " - "If you run a modified version of Zorian as a network service, " - "you must make the source code of your modifications available to its users. " - "The software is provided as-is, without warranty of any kind." - } - - p { - "Source code is available on " - a href="https://github.com/mrdimidium/zorian" { "GitHub" } - ". The full license text is included below." - } - - pre .license-text { (include_str!("../../../LICENSE")) } - - h2 { "Third party licenses" } - - ul { - @for ov in &data.overview { - li { a href=(format!("#{}", ov.id)) { (&ov.name) } " (" (ov.count) ")" } - } - } - - @for (i, lic) in data.licenses.iter().enumerate() { - @if lic.first_of_kind { - h3 id=(&lic.id) { (&lic.name) } - } - - section.license { - h4 id=(format!("{}-{}", lic.id, i)) { (&lic.name) } - - p { "Used by:" } - - ul .license-used-by { - @for usage in &lic.used_by { - li { - a href=( - usage.crate_.repository.as_deref() - .unwrap_or(&format!("https://crates.io/crates/{}", usage.crate_.name)) - ) { - (&usage.crate_.name) "@" (&usage.crate_.version) - } - } - } - } - - pre .license-text { (&lic.text) } - } - } - }, - ) - } - - fn layout(title: &str, content: Markup) -> Markup { - html! { - (maud::DOCTYPE) - - html lang="en" { - head { - meta charset="UTF-8"; - meta http-equiv="X-UA-Compatible" content="ie=edge"; - meta name="viewport" content="width=device-width,initial-scale=1"; - - title { (title) } - link rel="stylesheet" href="/base.css"; - - link rel="manifest" href="/manifest.webmanifest"; - link rel="icon" href="/favicon.ico" sizes="32x32"; - link rel="icon" href="/favicon.svg" type="image/svg+xml"; - link rel="apple-touch-icon" href="/apple-touch-icon.png"; - } - - body { - article { (content) } - } - } - } - } -} - -#[derive(Clone)] -struct CacheLayer; - -impl Layer for CacheLayer { - type Service = CacheService; - fn layer(&self, inner: S) -> Self::Service { - CacheService { inner } - } -} - -#[derive(Clone)] -struct CacheService { - inner: S, -} - -impl Service> for CacheService -where - S: Service, Response = Response> + Clone + Send + 'static, - S::Future: Send + 'static, - S::Error: Send + 'static, -{ - type Response = Response; - type Error = S::Error; - type Future = Pin> + Send>>; - - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - fn call(&mut self, req: Request) -> Self::Future { - let method = req.method().clone(); - let if_none_match = req.headers().get(header::IF_NONE_MATCH).cloned(); - - let mut inner = self.inner.clone(); - Box::pin(async move { - let resp = inner.call(req).await?; - - if !resp.status().is_success() { - return Ok(resp); - } - - let (parts, body) = resp.into_parts(); - let bytes = axum::body::to_bytes(body, usize::MAX).await.unwrap(); - - let mut hasher = crc32fast::Hasher::new(); - hasher.update(&bytes); - let etag = format!("\"{}\"", hex::encode(hasher.finalize().to_be_bytes())); - let etag_header = HeaderValue::from_str(&etag).unwrap(); - let cache_control = parts - .headers - .get(header::CACHE_CONTROL) - .cloned() - .unwrap_or(HeaderValue::from_static("no-cache")); - - if (method == Method::GET || method == Method::HEAD) - && if_none_match - .as_ref() - .is_some_and(|v| v.as_bytes() == etag.as_bytes()) - { - let mut resp = Response::builder() - .status(StatusCode::NOT_MODIFIED) - .body(Body::empty()) - .unwrap(); - resp.headers_mut().insert(header::ETAG, etag_header); - resp.headers_mut() - .insert(header::CACHE_CONTROL, cache_control); - return Ok(resp); - } - - let mut resp = Response::from_parts(parts, Body::from(bytes)); - resp.headers_mut().insert(header::ETAG, etag_header); - resp.headers_mut() - .entry(header::CACHE_CONTROL) - .or_insert(HeaderValue::from_static("no-cache")); - Ok(resp) - }) - } -} diff --git a/crates/zorian/src/main.rs b/crates/zorian/src/main.rs deleted file mode 100644 index c43c9d6..0000000 --- a/crates/zorian/src/main.rs +++ /dev/null @@ -1,567 +0,0 @@ -// SPDX-FileCopyrightText: 2026 Nikolay Govorov -// SPDX-License-Identifier: AGPL-3.0-or-later - -mod config; -mod proxy; -mod storage; -mod telemetry; - -mod controller_backend; -mod controller_web; - -use std::future::Future; -use std::net::{SocketAddr, TcpListener}; -use std::path::PathBuf; -use std::pin::Pin; -use std::sync::Arc; -use std::task::{Context, Poll}; - -use axum::{ - body::Body, - extract::{self, ConnectInfo}, - http::{self, Request, Response}, -}; -use axum_server::Handle; -use axum_server::tls_rustls::RustlsConfig; -#[cfg(target_os = "linux")] -use sd_notify::NotifyState; -use tokio::signal; -use tracing::{error, info, trace}; -use tracing_subscriber::registry::LookupSpan; - -use crate::controller_backend::BackendController; -use crate::controller_web::WebController; -use repos::{Backend, BackendSpec, GoBackend, ZigBackend}; - -async fn init_backend( - backend: Backend, - index_tasks: &mut tokio::task::JoinSet<()>, - index_cancel: tokio_util::sync::CancellationToken, -) -> Option>> { - if !backend.enabled() { - return None; - } - let backend = Arc::new(backend); - let interval = backend.refresh_interval(); - if !interval.is_zero() { - index_tasks.spawn(run_index_refresh( - S::ID, - backend.clone(), - interval, - index_cancel, - )); - } - Some(backend) -} - -async fn run_index_refresh( - name: &'static str, - backend: Arc>, - interval: std::time::Duration, - cancel: tokio_util::sync::CancellationToken, -) { - let mut ticker = tokio::time::interval(interval); - ticker.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); - - loop { - tokio::select! { - _ = cancel.cancelled() => { - info!(backend = name, "index refresh stopped"); - break; - } - _ = ticker.tick() => { - info!(backend = name, "refreshing index"); - match backend.refresh().await { - Ok(()) => info!(backend = name, "index refreshed"), - Err(e) => error!(backend = name, "index refresh failed: {e}"), - } - } - } - } -} - -const VERSION: &str = env!("CARGO_PKG_VERSION"); -const HELP: &str = "\ -Usage: zorian [--config=] - -Options: - --config= Path to config file (optional) - --help Show this help message - --version Show version -"; - -/// Contains metainfo about one server interface -#[derive(Clone)] -struct ListenerInfo { - addr: SocketAddr, - hosts: Vec, -} - -/// Request info stored in span extensions for logging -#[derive(Clone)] -struct RequestInfo { - method: http::Method, - version: http::Version, - path: http::Uri, - host: Option, - user_agent: Option, -} - -/// Key extractor for tower-governor that uses ConnectInfo to get the client IP. -#[derive(Clone)] -struct ClientIpKeyExtractor; -impl tower_governor::key_extractor::KeyExtractor for ClientIpKeyExtractor { - type Key = std::net::IpAddr; - - fn name(&self) -> &'static str { - "ClientIpKeyExtractor" - } - - fn extract(&self, req: &Request) -> Result { - req.extensions() - .get::>() - .map(|ci| ci.0.ip()) - .ok_or(tower_governor::GovernorError::UnableToExtractKey) - } -} - -#[tokio::main] -async fn main() { - let mut config_path = None; - for arg in std::env::args().skip(1) { - if arg == "--help" || arg == "-h" { - print!("{HELP}"); - return; - } - if arg == "--version" || arg == "-V" { - println!("zorian {VERSION}"); - return; - } - if let Some(path) = arg.strip_prefix("--config=") { - config_path = Some(PathBuf::from(path)); - } - } - - let config = Arc::new( - config::ConfigService::load(config_path).unwrap_or_else(|e| { - eprintln!("invalid config: {e}"); - std::process::exit(1); - }), - ); - - let mut telemetry = - telemetry::TelemetryService::init(config.telemetry(), config.appname(), VERSION); - - let storage = Arc::new(storage::StorageService::new(config.clone()).await.unwrap()); - let network = Arc::new(proxy::ProxyService::new()); - - let source = format!("zorian:{}", config.appname()); - let backends = config.backends(); - - const REQUEST_ID_HEADER: http::HeaderName = http::HeaderName::from_static("x-request-id"); - - let trace_layer = tower_http::trace::TraceLayer::new_for_http() - .make_span_with(|req: &http::Request| { - let request_id = req - .headers() - .get(&REQUEST_ID_HEADER) - .and_then(|v| v.to_str().ok()) - .unwrap_or(""); - let local_addr = req.extensions().get::().map(|a| a.addr); - let remote_addr = req - .extensions() - .get::>() - .map(|ci| ci.0.ip()); - - tracing::info_span!( - "http_request", - request_id = %request_id, - local_addr = ?local_addr, - remote_addr = ?remote_addr, - ) - }) - .on_request(|req: &Request, span: &tracing::Span| { - let info = RequestInfo { - method: req.method().clone(), - path: req.uri().clone(), - version: req.version(), - host: extract_host(req), - user_agent: req - .headers() - .get(http::header::USER_AGENT) - .and_then(|v| v.to_str().ok()) - .map(String::from), - }; - - span.with_subscriber(|(id, dispatch)| { - if let Some(reg) = dispatch.downcast_ref::() - && let Some(span_ref) = reg.span(id) - { - span_ref.extensions_mut().insert(info); - } - }); - }) - .on_response( - |res: &Response, latency: std::time::Duration, span: &tracing::Span| { - use axum::body::HttpBody as _; - - let status = res.status().as_u16(); - let content_length = res.body().size_hint().exact(); - let content_type = res - .headers() - .get(http::header::CONTENT_TYPE) - .and_then(|v| v.to_str().ok()); - - let req_info = span.with_subscriber(|(id, dispatch)| { - dispatch - .downcast_ref::() - .and_then(|reg| reg.span(id)) - .and_then(|span_ref| span_ref.extensions().get::().cloned()) - }); - - if let Some(Some(req_info)) = req_info { - info!( - method = %req_info.method, - version = ?req_info.version, - path = %req_info.path, - host = req_info.host, - user_agent = req_info.user_agent, - status, - latency = latency.as_nanos() as u64, - content_type, - content_length, - "on_response", - ); - } else { - info!( - status, - latency = latency.as_nanos() as u64, - content_type, - content_length, - "on_response", - ); - } - }, - ) - .on_failure(tower_http::trace::DefaultOnFailure::new().level(tracing::Level::ERROR)); - - let governor_config = tower_governor::governor::GovernorConfigBuilder::default() - .period(config.server().rate_limit_period) - .burst_size(config.server().rate_limit_burst_size) - .key_extractor(ClientIpKeyExtractor) - .finish() - .unwrap(); - - let mut index_tasks = tokio::task::JoinSet::new(); - let index_cancel = tokio_util::sync::CancellationToken::new(); - - let zig_backend = init_backend( - ZigBackend::new( - backends.zig.clone(), - source.clone(), - storage.clone(), - network.clone(), - ), - &mut index_tasks, - index_cancel.clone(), - ) - .await; - - let go_backend = init_backend( - GoBackend::new( - backends.go.clone(), - source.clone(), - storage.clone(), - network.clone(), - ), - &mut index_tasks, - index_cancel.clone(), - ) - .await; - - let web_controller = Arc::new(WebController::new(zig_backend.clone(), go_backend.clone())); - let mut app = axum::Router::new().merge(web_controller.router()); - - if let Some(ref backend) = zig_backend { - let ctrl = Arc::new(BackendController::new( - backend.clone(), - storage.clone(), - network.clone(), - )); - app = app.nest("/zig", ctrl.router()); - } - - if let Some(ref backend) = go_backend { - let ctrl = Arc::new(BackendController::new( - backend.clone(), - storage.clone(), - network.clone(), - )); - app = app.nest("/go", ctrl.router()); - } - - let app = app - // Opt-in layers - .layer(tower_http::compression::CompressionLayer::new()) - // request limits - .layer(HostValidationLayer) - .layer(tower_http::limit::RequestBodyLimitLayer::new( - config.server().max_body_size.as_u64() as usize, - )) - .layer(tower_http::timeout::TimeoutLayer::with_status_code( - http::StatusCode::REQUEST_TIMEOUT, - config.server().request_timeout, - )) - // logging - .layer(trace_layer) - // rate-limits - .layer(tower_governor::GovernorLayer::new(Arc::new( - governor_config, - ))) - .layer(tower::limit::ConcurrencyLimitLayer::new( - config.server().max_concurrent_requests, - )) - // global headers - .layer(tower_http::request_id::PropagateRequestIdLayer::new( - REQUEST_ID_HEADER.clone(), - )) - .layer(tower_http::request_id::SetRequestIdLayer::new( - REQUEST_ID_HEADER.clone(), - tower_http::request_id::MakeRequestUuid, - )) - .layer(tower_http::set_header::SetResponseHeaderLayer::overriding( - http::header::SERVER, - http::HeaderValue::from_static(concat!("zorian/", env!("CARGO_PKG_VERSION"))), - )); - - let mut tasks = tokio::task::JoinSet::new(); - let handle = Handle::new(); - - for listener_config in config.listeners() { - let std_listener = TcpListener::bind(listener_config.addr).unwrap(); - std_listener.set_nonblocking(true).unwrap(); - - let addr = std_listener.local_addr().unwrap(); - - let app = app - .clone() - .layer(axum::Extension(ListenerInfo { - addr, - hosts: listener_config.hostnames.clone(), - })) - .into_make_service_with_connect_info::(); - - let handle = handle.clone(); - - let tls_enabled = - if let (Some(crt), Some(key)) = (&listener_config.tls_crt, &listener_config.tls_key) { - let rustls_config = RustlsConfig::from_pem_file(crt, key) - .await - .expect("failed to load TLS config"); - - tasks.spawn(async move { - let server = axum_server::from_tcp_rustls(std_listener, rustls_config).unwrap(); - server.handle(handle).serve(app).await.unwrap(); - }); - - true - } else { - tasks.spawn(async move { - let server = axum_server::from_tcp(std_listener).unwrap(); - server.handle(handle).serve(app).await.unwrap(); - }); - - false - }; - - info!( - "listening {} on {} (hostnames: {})", - if tls_enabled { "HTTPS" } else { "HTTP" }, - addr, - if listener_config.hostnames.is_empty() { - "*".to_string() - } else { - listener_config.hostnames.join(", ") - }, - ); - } - - let mut watchdog_ticker = tokio::time::interval(std::time::Duration::from_secs(60)); - - #[cfg(target_os = "linux")] - if sd_notify::booted().unwrap_or(false) { - sd_notify::notify(false, &[NotifyState::Ready]).ok(); - - let mut usec = 0u64; - (sd_notify::watchdog_enabled(true, &mut usec) && usec > 0).then(|| { - let interval = std::time::Duration::from_micros(usec) / 2; - info!( - interval_ms = interval.as_millis() as u64, - "watchdog enabled" - ); - watchdog_ticker = tokio::time::interval(interval); - }); - }; - - #[cfg(unix)] - let mut sigint = signal::unix::signal(signal::unix::SignalKind::interrupt()) - .expect("failed to install signal handler"); - #[cfg(windows)] - let mut sigint = signal::windows::signal(signal::windows::SignalKind::interrupt()) - .expect("failed to install signal handler"); - - #[cfg(unix)] - let mut sigterm = signal::unix::signal(signal::unix::SignalKind::terminate()) - .expect("failed to install signal handler"); - - loop { - let watchdog = watchdog_ticker.tick(); - - #[cfg(unix)] - let sigterm = sigterm.recv(); - #[cfg(not(unix))] - let sigterm = std::future::pending::<()>(); - - tokio::select! { - _ = sigint.recv() => { - info!("received SIGINT, shutting down"); - break; - }, - _ = sigterm => { - info!("received SIGTERM, shutting down"); - break; - }, - _ = watchdog => { - trace!("server is alive"); - - #[cfg(target_os = "linux")] - sd_notify::notify(false, &[NotifyState::Watchdog]).ok(); - }, - result = tasks.join_next() => { - match result { - Some(Ok(())) => error!("listener exited unexpectedly, shutting down"), - Some(Err(e)) => error!("listener failed: {e}, shutting down"), - None => { - error!("no listeners running"); - return; - } - } - break; - }, - } - } - - #[cfg(target_os = "linux")] - sd_notify::notify(false, &[NotifyState::Stopping]).ok(); - - index_cancel.cancel(); - handle.graceful_shutdown(None); - - // Wait for all tasks to finish with timeout - let shutdown_result = tokio::time::timeout(config.server().shutdown_timeout, async { - while let Some(result) = tasks.join_next().await { - if let Err(e) = result { - error!("listener task failed: {e}"); - } - } - while let Some(result) = index_tasks.join_next().await { - if let Err(e) = result { - error!("index task failed: {e}"); - } - } - }) - .await; - - if shutdown_result.is_err() { - error!( - "shutdown timeout after {:?}, aborting remaining tasks", - config.server().shutdown_timeout, - ); - tasks.abort_all(); - index_tasks.abort_all(); - } else { - info!("shutdown complete"); - } - - telemetry.shutdown(); -} - -/// Layer that validates the Host header against configured hostnames. -#[derive(Clone)] -struct HostValidationLayer; -impl tower::Layer for HostValidationLayer { - type Service = HostValidationService; - - fn layer(&self, inner: S) -> Self::Service { - HostValidationService { inner } - } -} - -#[derive(Clone)] -struct HostValidationService { - inner: S, -} -impl tower::Service> for HostValidationService -where - S: tower::Service, Response = Response> + Clone + Send + 'static, - S::Future: Send, -{ - type Response = S::Response; - type Error = S::Error; - type Future = Pin> + Send>>; - - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - fn call(&mut self, req: Request) -> Self::Future { - let interface = req.extensions().get::().cloned(); - - if let Some(iface) = interface - && !iface.hosts.is_empty() - { - let is_valid = extract_host(&req) - .map(|h| { - iface - .hosts - .iter() - .any(|allowed| allowed.eq_ignore_ascii_case(&h)) - }) - .unwrap_or(false); - - if !is_valid { - return Box::pin(async move { - Ok(Response::builder() - .status(http::StatusCode::MISDIRECTED_REQUEST) - .body(Body::empty()) - .unwrap()) - }); - } - } - - let clone = self.inner.clone(); - let mut inner = std::mem::replace(&mut self.inner, clone); - Box::pin(async move { inner.call(req).await }) - } -} - -fn extract_host(req: &Request) -> Option { - // HTTP/1.1 uses HOST header, HTTP/2 uses :authority (available via URI) - let raw = if let Some(host) = req.headers().get(http::header::HOST) { - host.to_str().ok().map(|raw| { - if let Some((host, port)) = raw.rsplit_once(':') - && port.parse::().is_ok() - && (host.ends_with(']') || !host.contains('[')) - { - host - } else { - raw - } - }) - } else { - req.uri().host() - }; - - raw.and_then(|raw| url::Host::parse(raw).ok()) - .map(|h| h.to_string().trim_end_matches('.').to_string()) -} diff --git a/crates/zorian/src/proxy.rs b/crates/zorian/src/proxy.rs deleted file mode 100644 index bd6a0f4..0000000 --- a/crates/zorian/src/proxy.rs +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-FileCopyrightText: 2026 Nikolay Govorov -// SPDX-License-Identifier: AGPL-3.0-or-later - -use bytes::Bytes; -use http_body_util::{BodyExt, Empty}; -use hyper::{Request, http}; -use hyper_tls::HttpsConnector; -use hyper_util::client::legacy::{Client, connect::HttpConnector}; -use hyper_util::rt::TokioExecutor; -use tower::ServiceExt; -use tower_http::follow_redirect::FollowRedirect; -use url::Url; - -use repos::{BackendError, BackendNetwork}; - -#[derive(Clone)] -pub struct DownloadRequest { - pub url: Url, -} - -#[derive(Clone)] -pub struct File { - pub bytes: Bytes, -} - -pub struct ProxyService { - client: FollowRedirect, Empty>>, -} - -impl ProxyService { - pub fn new() -> Self { - let https = HttpsConnector::new(); - let client = Client::builder(TokioExecutor::new()).build(https); - Self { - client: FollowRedirect::new(client), - } - } - - pub async fn fetch(&self, request: DownloadRequest) -> Result { - let request = Request::builder() - .method(http::Method::GET) - .uri(request.url.as_str()) - .header(http::header::USER_AGENT, "zorian/0.1") - .body(Empty::::new()) - .unwrap(); - - let response = self - .client - .clone() - .oneshot(request) - .await - .map_err(|_| http::StatusCode::GATEWAY_TIMEOUT)?; - - let (parts, body) = response.into_parts(); - let status = parts.status; - if !status.is_success() { - return Err(status); - } - - let bytes = body - .collect() - .await - .map_err(|_| http::StatusCode::GATEWAY_TIMEOUT)? - .to_bytes(); - - Ok(File { bytes }) - } -} - -#[async_trait::async_trait] -impl BackendNetwork for ProxyService { - async fn http_get(&self, url: &url::Url) -> Result { - self.fetch(DownloadRequest { url: url.clone() }) - .await - .map(|f| f.bytes) - .map_err(|e| BackendError::Network(e.to_string())) - } -} diff --git a/crates/zorian/src/storage.rs b/crates/zorian/src/storage.rs deleted file mode 100644 index 0e7f3ac..0000000 --- a/crates/zorian/src/storage.rs +++ /dev/null @@ -1,1203 +0,0 @@ -// SPDX-FileCopyrightText: 2026 Nikolay Govorov -// SPDX-License-Identifier: AGPL-3.0-or-later - -// This class stores uploaded files and associated metadata. -// Files are immutable but can be deleted. -// -// A unique file is defined by a `scope` and a `filename`. -// The filename can be any valid UTF-8 string up to 1KB -// in size and does not have to be a valid filesystem name. -// -// The list of files and their metadata are stored in a single -// SQLite database table. Small files are stored in a BLOB column -// in SQLite; for larger files, a checksum is stored in the database, -// and the file itself is stored on disk. -// -// On disk new files are written in two steps: -// - the file is written to a temporary file in the same directory; -// - a transaction is opened and a new file entry is created -// - temp file is renamed to the final filename -// - the transaction is committed. -// -// This scheme guarantees that if a record exists in the table, the file is written. -// However if the server crashes after rename but before commit, an orphan file will remain on the disk. -// To combat this, when the server starts, we check that there is an entry -// in the database for each file on the disk, and we also delete all temporary (non-renamed) files. - -use std::path::{Path, PathBuf}; -use std::sync; - -use bytes::Bytes; -use crc32fast::Hasher as Crc32Hasher; -use sqlx::encode::{Encode, IsNull}; -use sqlx::error::BoxDynError; -use sqlx::{FromRow, Pool, Sqlite, query, query_as, query_scalar, sqlite}; -use thiserror::Error; -use tokio::fs; -use tokio::io::AsyncWriteExt; -use tracing::{debug, error, instrument, warn}; -use uuid::Uuid; - -use crate::config::ConfigService; -use repos::{BackendError, BackendStorage, RawRelease, RawReleaseFile, Release}; - -const SQLITE_POOL_SIZE: u32 = 16; -const INLINE_THRESHOLD: usize = 256 * 1024; // 256 KB - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Id(pub Uuid); - -impl std::ops::Deref for Id { - type Target = Uuid; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl sqlx::Type for Id { - fn type_info() -> sqlite::SqliteTypeInfo { - as sqlx::Type>::type_info() - } - - fn compatible(ty: &sqlite::SqliteTypeInfo) -> bool { - as sqlx::Type>::compatible(ty) - } -} - -impl<'r> sqlx::decode::Decode<'r, Sqlite> for Id { - fn decode( - value: sqlite::SqliteValueRef<'r>, - ) -> Result> { - let value: Vec = as sqlx::decode::Decode>::decode(value)?; - let uuid = Uuid::from_slice(&value)?; - Ok(Id(uuid)) - } -} - -impl<'q> Encode<'q, Sqlite> for Id { - fn encode_by_ref( - &self, - buf: &mut ::ArgumentBuffer<'q>, - ) -> Result { - let value = self.0.as_bytes().to_vec(); - as Encode>::encode(value, buf) - } -} - -#[derive(Debug, Clone)] -pub struct Blob(pub Bytes); - -impl std::ops::Deref for Blob { - type Target = Bytes; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl sqlx::Type for Blob { - fn type_info() -> sqlite::SqliteTypeInfo { - as sqlx::Type>::type_info() // BLOB - } - - fn compatible(ty: &sqlite::SqliteTypeInfo) -> bool { - as sqlx::Type>::compatible(ty) - } -} - -impl<'r> sqlx::decode::Decode<'r, Sqlite> for Blob { - fn decode( - value: sqlite::SqliteValueRef<'r>, - ) -> Result> { - let slice: &'r [u8] = <&'r [u8] as sqlx::decode::Decode>::decode(value)?; - Ok(Blob(Bytes::copy_from_slice(slice))) - } -} - -#[derive(Debug, Error)] -pub enum StorageError { - #[error("file already exists: {0}/{1}")] - AlreadyExists(String, String), - - #[error("blob integrity check failed")] - IntegrityError, - - #[error("blob file missing on disk: {0}")] - BlobNotFound(PathBuf), - - #[error("failed to connect index db: {0}")] - DbError(#[from] sqlx::Error), - - #[error("io error: {0}")] - IoError(#[from] std::io::Error), -} - -/// Cached file entry (datafiles table) -#[allow(unused)] -#[derive(Debug, Clone, FromRow)] -pub struct Object { - pub id: Id, - pub scope: String, - pub created_at: chrono::DateTime, - - pub file_name: String, - pub file_size: i64, - pub file_bytes: Blob, - pub inlined: bool, -} - -impl Object { - // You cannot change this ID, this will desynchronize the records in the database and the files on the disk. - const UUID_ROOT_NAMESPACE: Uuid = Uuid::from_bytes([ - 0x8b, 0x06, 0x3c, 0x4c, 0x6b, 0x5c, 0x4a, 0x8b, 0x92, 0x8f, 0x75, 0x8b, 0x0e, 0x63, 0xc3, - 0x5d, - ]); - - fn uuid(scope: &str, file: &str) -> Id { - let scope_ns = Uuid::new_v5(&Object::UUID_ROOT_NAMESPACE, scope.as_bytes()); - Id(Uuid::new_v5(&scope_ns, file.as_bytes())) - } - - fn hash(scope: &str, file: &str, blob: &[u8]) -> Vec { - let mut hasher = Crc32Hasher::new(); - - hasher.update(b"/"); - hasher.update(scope.as_bytes()); - - hasher.update(b"/"); - hasher.update(file.as_bytes()); - - hasher.update(b"/"); - hasher.update(blob); - hasher.update(b"\0"); - - hasher.finalize().to_be_bytes().to_vec() - } -} - -/// Builder for file query SQL -pub struct FileQuery<'a> { - backend: &'a str, - version: Option<&'a str>, - filename: Option<&'a str>, - meta_null: Option<&'a str>, -} - -impl<'a> FileQuery<'a> { - pub fn new(backend: &'a str) -> Self { - Self { - backend, - version: None, - filename: None, - meta_null: None, - } - } - - pub fn version(mut self, version: &'a str) -> Self { - self.version = Some(version); - self - } - - pub fn filename(mut self, filename: &'a str) -> Self { - self.filename = Some(filename); - self - } - - pub fn where_meta_null(mut self, field: &'a str) -> Self { - self.meta_null = Some(field); - self - } - - pub fn build_sql(&self) -> String { - let mut sql = String::from( - "SELECT backend, version, filename, checksum, size, os, arch, meta FROM files WHERE backend = ?1", - ); - let mut param_idx = 1; - - if self.version.is_some() { - param_idx += 1; - sql.push_str(&format!(" AND version = ?{}", param_idx)); - } - if self.filename.is_some() { - param_idx += 1; - sql.push_str(&format!(" AND filename = ?{}", param_idx)); - } - if let Some(field) = self.meta_null { - sql.push_str(&format!( - " AND (meta IS NULL OR json_extract(meta, '$.{}') IS NULL)", - field - )); - } - - sql - } -} - -struct FileSystem { - objects: PathBuf, - database: PathBuf, -} - -impl FileSystem { - fn new(root: &Path) -> Self { - Self { - objects: root.join("objects"), - database: root.join("index.sqlite"), - } - } - - fn database(&self) -> &Path { - &self.database - } - - fn objects_root(&self) -> &Path { - &self.objects - } - - fn object(&self, scope: &str, file: &str) -> PathBuf { - let id = Object::uuid(scope, file); - let hash_hex = hex::encode(id.0.as_bytes()); - self.objects_root() - .join(&hash_hex[0..2]) - .join(&hash_hex[2..4]) - .join(&hash_hex) - } - - async fn objects_walk(&self, mut f: F) -> Result<(), StorageError> - where - F: FnMut(PathBuf) -> Fut, - Fut: std::future::Future>, - { - if !self.objects.exists() { - return Ok(()); - } - - let mut stack = vec![self.objects.to_path_buf()]; - while let Some(dir) = stack.pop() { - let mut entries = fs::read_dir(&dir).await?; - while let Some(entry) = entries.next_entry().await? { - let path = entry.path(); - let file_type = entry.file_type().await?; - - if file_type.is_dir() { - stack.push(path); - } else if file_type.is_file() { - f(path).await?; - } - } - } - - Ok(()) - } -} - -pub struct StorageService { - blobfs: FileSystem, - sqlite: Pool, -} - -impl StorageService { - pub async fn new(config: sync::Arc) -> Result { - let blobfs = FileSystem::new(config.dirname()); - - let connection = format!("sqlite:{}?mode=rwc", blobfs.database().to_str().unwrap()); - let sqlite: Pool = sqlite::SqlitePoolOptions::new() - .max_connections(SQLITE_POOL_SIZE) - .after_connect(|conn, _meta| { - Box::pin(async move { - // Connection-specific PRAGMAs (must be set on each connection) - sqlx::query("PRAGMA foreign_keys = ON;") - .execute(&mut *conn) - .await?; - sqlx::query("PRAGMA busy_timeout = 5000;") - .execute(&mut *conn) - .await?; - Ok(()) - }) - }) - .connect(&connection) - .await?; - - // WAL mode is database-wide and persists, only needs to be set once - query("PRAGMA journal_mode = WAL;").execute(&sqlite).await?; - - let storage = Self { sqlite, blobfs }; - storage.migrations().await?; - storage.doctor().await?; - - Ok(storage) - } - - /// Synchronously traverses the tree and removes temporary files. - /// Must run before the application starts. - async fn doctor(&self) -> Result<(), StorageError> { - let result = self.blobfs.objects_walk(|path| async move { - let name = match path.file_name().and_then(|name| name.to_str()) { - Some(name) => name.to_string(), - None => { - warn!(path = %path.display(), "cleanup: invalid blob name"); - let _ = fs::remove_file(path).await; - return Ok(()); - } - }; - - if name.ends_with(".part") { - warn!(path = %path.display(), "cleanup: removing temp file"); - let _ = fs::remove_file(path).await; - return Ok(()); - } - - if name.len() != 32 { - warn!(path = %path.display(), "cleanup: invalid blob name length"); - let _ = fs::remove_file(path).await; - return Ok(()); - } - - let id_bytes = match hex::decode(&name) { - Ok(bytes) => bytes, - Err(_) => { - warn!(path = %path.display(), "cleanup: invalid blob name hex"); - let _ = fs::remove_file(path).await; - return Ok(()); - } - }; - - let id = match Uuid::from_slice(&id_bytes) { - Ok(uuid) => Id(uuid), - Err(_) => { - warn!(path = %path.display(), "cleanup: invalid blob uuid"); - let _ = fs::remove_file(path).await; - return Ok(()); - } - }; - - let exists: Option = query_scalar("SELECT 1 FROM datafiles WHERE id = ?1") - .bind(id) - .fetch_optional(&self.sqlite) - .await?; - - if exists.is_none() { - warn!(path = %path.display(), "cleanup: removing orphan blob"); - let _ = fs::remove_file(path).await; - } - - Ok(()) - }); - result.await?; - - Ok(()) - } - - async fn migrations(&self) -> Result<(), StorageError> { - // Object storage table - query( - "CREATE TABLE IF NOT EXISTS datafiles( - id BLOB PRIMARY KEY CHECK (length(id) = 16), - scope TEXT NOT NULL, - created_at TEXT DEFAULT (datetime('now')), - file_name TEXT NOT NULL, - file_size INTEGER NOT NULL, - file_bytes BLOB, - inlined INTEGER NOT NULL, - UNIQUE (scope, file_name) - ) STRICT", - ) - .execute(&self.sqlite) - .await?; - - // Drop old backend-specific tables (data will be re-fetched from upstream) - query("DROP TABLE IF EXISTS go_files") - .execute(&self.sqlite) - .await?; - query("DROP TABLE IF EXISTS go_versions") - .execute(&self.sqlite) - .await?; - query("DROP TABLE IF EXISTS zig_files") - .execute(&self.sqlite) - .await?; - query("DROP TABLE IF EXISTS zig_versions") - .execute(&self.sqlite) - .await?; - - // Unified versions table - query( - "CREATE TABLE IF NOT EXISTS versions ( - backend TEXT NOT NULL, - version TEXT NOT NULL, - sort_key INTEGER NOT NULL, - meta BLOB CHECK (meta IS NULL OR (json_valid(meta) AND json_type(meta) = 'object')), - PRIMARY KEY (backend, version) - ) STRICT", - ) - .execute(&self.sqlite) - .await?; - - // Unified files table - query( - "CREATE TABLE IF NOT EXISTS files ( - backend TEXT NOT NULL, - version TEXT NOT NULL, - filename TEXT NOT NULL, - checksum TEXT NOT NULL, - size INTEGER NOT NULL, - os TEXT, - arch TEXT, - meta BLOB CHECK (meta IS NULL OR (json_valid(meta) AND json_type(meta) = 'object')), - PRIMARY KEY (backend, version, filename), - FOREIGN KEY (backend, version) REFERENCES versions(backend, version) - ) STRICT", - ) - .execute(&self.sqlite) - .await?; - - // Index for fast filename lookups - query("CREATE INDEX IF NOT EXISTS idx_files_backend_filename ON files(backend, filename)") - .execute(&self.sqlite) - .await?; - - Ok(()) - } - - #[instrument(skip(self))] - pub async fn get(&self, scope: &str, filename: &str) -> Result, StorageError> { - let file: Option = - query_as("SELECT * FROM datafiles WHERE scope = ?1 AND file_name = ?2") - .bind(scope) - .bind(filename) - .fetch_optional(&self.sqlite) - .await?; - - match file { - None => { - debug!("get: file not found"); - Ok(None) - } - Some(mut file) if !file.inlined => { - let obj = self.blobfs.object(scope, filename); - let bytes = match fs::read(&obj).await { - Ok(b) => Bytes::from(b), - Err(e) if e.kind() == std::io::ErrorKind::NotFound => { - return Err(StorageError::BlobNotFound(obj)); - } - Err(e) => return Err(e.into()), - }; - - let hash = Object::hash(scope, filename, &bytes); - if hash != file.file_bytes.to_vec() { - return Err(StorageError::IntegrityError); - } - - file.file_bytes = Blob(bytes); - debug!(size = file.file_size, "get: loaded from disk"); - Ok(Some(file)) - } - Some(file) => { - debug!(size = file.file_size, "get: loaded inline"); - Ok(Some(file)) - } - } - } - - #[instrument(skip(self, bytes), fields(size = bytes.len()))] - pub async fn put( - &self, - scope: &str, - filename: &str, - bytes: &Bytes, - ) -> Result<(), StorageError> { - let inlined = bytes.len() <= INLINE_THRESHOLD; - - let obj = self.blobfs.object(scope, filename); - let tmp = obj.with_extension(format!("{}.part", Uuid::new_v4())); - - // write temp file - if !inlined { - if let Some(parent) = obj.parent() { - fs::create_dir_all(parent).await?; - } - - let mut file = fs::OpenOptions::new() - .write(true) - .create_new(true) - .open(&tmp) - .await?; - - file.write_all(bytes).await?; - file.sync_all().await?; - } - - // bytes for small files or hash for large ones - let payload: Vec = if inlined { - bytes.to_vec() - } else { - Object::hash(scope, filename, bytes) - }; - - let result = async { - let mut tx = self.sqlite.begin().await?; - let id = Object::uuid(scope, filename); - - let result = query( - " - INSERT INTO datafiles ( - id, scope, file_name, file_size, file_bytes, inlined - ) VALUES ( - ?1, ?2, ?3, ?4, ?5, ?6 - ); - ", - ) - .bind(id) - .bind(scope) - .bind(filename) - .bind(bytes.len() as i64) - .bind(&payload) - .bind(inlined) - .execute(tx.as_mut()) - .await; - - match result { - Ok(_) => { - if !inlined { - fs::rename(&tmp, &obj).await?; - if let Some(parent) = obj.parent() { - let dir = fs::File::open(parent).await?; - dir.sync_all().await?; - } - } - - tx.commit().await?; - debug!("put: a new file has been commited"); - Ok(()) - } - Err(sqlx::Error::Database(ref db_err)) if db_err.is_unique_violation() => { - let existing: Option = - query_as("SELECT * FROM datafiles WHERE scope = ?1 AND file_name = ?2") - .bind(scope) - .bind(filename) - .fetch_optional(tx.as_mut()) - .await?; - - match existing { - Some(file) if file.file_bytes.to_vec() == payload => { - if !inlined { - let _ = fs::remove_file(&tmp).await; - tx.rollback().await?; - } - - debug!("put: identical file already exists"); - return Ok(()); - } - Some(_) => { - warn!("put: file already exists with different content"); - } - None => { - // unique_violation but row doesn't exist - shouldn't happen - warn!("corrupted! 'is_unique_violation' received, but data cannot be selected"); - } - } - - Err(StorageError::AlreadyExists( - scope.to_string(), - filename.to_string(), - )) - } - Err(e) => Err(e.into()), - } - }.await; - - if result.is_err() && !inlined { - let _ = fs::remove_file(&tmp).await; - } - - result - } - - /// Insert or update releases with their files in a single transaction. - pub async fn insert_releases( - &self, - releases: &[(RawRelease, Vec)], - ) -> Result<(), StorageError> { - for (release, files) in releases { - let mut tx = match self.sqlite.begin().await { - Ok(tx) => tx, - Err(e) => { - error!( - backend = release.backend, - version = release.version, - "failed to start transaction: {e}" - ); - return Err(e.into()); - } - }; - - let meta_json = release - .meta - .as_ref() - .map(|m| serde_json::to_vec(m).unwrap()); - - let result = async { - // Insert/update version - query( - "INSERT INTO versions (backend, version, sort_key, meta) - VALUES (?1, ?2, ?3, ?4) - ON CONFLICT(backend, version) DO UPDATE SET - sort_key = excluded.sort_key, - meta = excluded.meta - WHERE sort_key IS NOT excluded.sort_key OR meta IS NOT excluded.meta", - ) - .bind(&release.backend) - .bind(&release.version) - .bind(release.sort_key) - .bind(meta_json.as_deref()) - .execute(&mut *tx) - .await?; - - // Insert/update files - for file in files { - let changed = - Self::insert_file(&mut tx, &release.backend, &release.version, file) - .await?; - if changed { - warn!( - backend = release.backend, - version = release.version, - filename = file.filename, - "index file changed" - ); - } - } - - Ok::<(), StorageError>(()) - } - .await; - - match result { - Ok(()) => { - if let Err(e) = tx.commit().await { - error!( - backend = release.backend, - version = release.version, - "failed to commit release: {e}" - ); - } - } - Err(e) => { - error!( - backend = release.backend, - version = release.version, - "failed to store release, skipping: {e}" - ); - let _ = tx.rollback().await; - } - } - } - - Ok(()) - } - - /// Insert or update a single file within a transaction. - /// Returns `true` if an existing file was modified. - async fn insert_file( - tx: &mut sqlx::Transaction<'_, Sqlite>, - backend: &str, - version: &str, - file: &RawReleaseFile, - ) -> Result { - let meta_json = file.meta.as_ref().map(|m| serde_json::to_vec(m).unwrap()); - let os_str = file.os.as_ref().map(AsRef::as_ref); - let arch_str = file.arch.as_ref().map(AsRef::as_ref); - - let existed: Option<(i32,)> = - query_as("SELECT 1 FROM files WHERE backend = ?1 AND version = ?2 AND filename = ?3") - .bind(backend) - .bind(version) - .bind(&file.filename) - .fetch_optional(&mut **tx) - .await?; - - let changed: Option<(i32,)> = query_as( - "INSERT INTO files (backend, version, filename, checksum, size, os, arch, meta) - VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8) - ON CONFLICT(backend, version, filename) DO UPDATE SET - checksum = excluded.checksum, - size = excluded.size, - os = excluded.os, - arch = excluded.arch - WHERE checksum IS NOT excluded.checksum - OR size IS NOT excluded.size - OR os IS NOT excluded.os - OR arch IS NOT excluded.arch - RETURNING 1", - ) - .bind(backend) - .bind(version) - .bind(&file.filename) - .bind(&file.checksum) - .bind(file.size) - .bind(os_str) - .bind(arch_str) - .bind(meta_json.as_deref()) - .fetch_optional(&mut **tx) - .await?; - - Ok(existed.is_some() && changed.is_some()) - } - - /// Execute a file query. - pub async fn query_files_filtered( - &self, - q: FileQuery<'_>, - ) -> Result, StorageError> { - let sql = q.build_sql(); - - let mut query = sqlx::query_as::< - _, - ( - String, - String, - String, - String, - i64, - Option, - Option, - Option>, - ), - >(&sql) - .bind(q.backend); - - if let Some(v) = q.version { - query = query.bind(v); - } - if let Some(f) = q.filename { - query = query.bind(f); - } - - let rows = query.fetch_all(&self.sqlite).await?; - - rows.into_iter() - .map( - |(backend, version, filename, checksum, size, os_str, arch_str, meta_bytes)| { - let meta = meta_bytes - .map(|b| serde_json::from_slice(&b)) - .transpose() - .map_err(|e| StorageError::DbError(sqlx::Error::Decode(Box::new(e))))?; - - Ok(RawReleaseFile { - backend, - version, - filename, - checksum, - size, - os: os_str.and_then(|s| s.parse().ok()), - arch: arch_str.and_then(|s| s.parse().ok()), - meta, - }) - }, - ) - .collect() - } - - /// Query all versions for a backend, ordered by sort_key. - pub async fn query_releases(&self, backend: &str) -> Result, StorageError> { - let rows = query_as::<_, (String, String, i64, Option>)>( - "SELECT backend, version, sort_key, meta FROM versions WHERE backend = ?1 ORDER BY sort_key", - ) - .bind(backend) - .fetch_all(&self.sqlite) - .await?; - - rows.into_iter() - .map(|(backend, version, sort_key, meta_bytes)| { - let meta = meta_bytes - .map(|b| serde_json::from_slice(&b)) - .transpose() - .map_err(|e| StorageError::DbError(sqlx::Error::Decode(Box::new(e))))?; - - Ok(Release { - backend, - version, - sort_key, - meta, - }) - }) - .collect() - } - - /// Update file metadata (e.g. after fetching a signature). - pub async fn update_file_meta(&self, file: &RawReleaseFile) -> Result { - let meta_json = file.meta.as_ref().map(|m| serde_json::to_vec(m).unwrap()); - - let result = query( - "UPDATE files SET meta = ?1 - WHERE backend = ?2 AND version = ?3 AND filename = ?4", - ) - .bind(meta_json.as_deref()) - .bind(&file.backend) - .bind(&file.version) - .bind(&file.filename) - .execute(&self.sqlite) - .await?; - - Ok(result.rows_affected() > 0) - } -} - -#[async_trait::async_trait] -impl BackendStorage for StorageService { - async fn insert_releases( - &self, - releases: &[(RawRelease, Vec)], - ) -> Result<(), BackendError> { - StorageService::insert_releases(self, releases) - .await - .map_err(|e| BackendError::Storage(e.to_string())) - } - - async fn query_releases(&self, backend: &str) -> Result, BackendError> { - StorageService::query_releases(self, backend) - .await - .map_err(|e| BackendError::Storage(e.to_string())) - } - - async fn query_files( - &self, - backend: &str, - version: Option<&str>, - filename: Option<&str>, - meta_null_field: Option<&str>, - ) -> Result, BackendError> { - let mut q = FileQuery::new(backend); - if let Some(v) = version { - q = q.version(v); - } - if let Some(f) = filename { - q = q.filename(f); - } - if let Some(field) = meta_null_field { - q = q.where_meta_null(field); - } - self.query_files_filtered(q) - .await - .map_err(|e| BackendError::Storage(e.to_string())) - } - - async fn update_file_meta(&self, file: &RawReleaseFile) -> Result { - StorageService::update_file_meta(self, file) - .await - .map_err(|e| BackendError::Storage(e.to_string())) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use tempfile::TempDir; - - const BIG_FILE_SIZE: usize = INLINE_THRESHOLD * 64; - - async fn create_storage_at(path: &Path) -> StorageService { - let config = sync::Arc::new(ConfigService::for_test(path.to_path_buf())); - StorageService::new(config).await.unwrap() - } - - async fn create_test_storage() -> (StorageService, TempDir) { - let tmp = TempDir::new().unwrap(); - let storage = create_storage_at(tmp.path()).await; - (storage, tmp) - } - - /// Count files in a directory recursively - fn count_files(dir: &Path, ext: Option<&str>) -> usize { - let mut count = 0; - if let Ok(entries) = std::fs::read_dir(dir) { - for entry in entries.flatten() { - let path = entry.path(); - if path.is_dir() { - count += count_files(&path, ext); - } else if let Some(extension) = ext { - if path.extension().is_some_and(|ext| ext == extension) { - count += 1; - } - } else { - count += 1; - } - } - } - count - } - - /// Recursively delete or corrupt all files in a directory - fn damage_blobs(dir: &Path, corrupt: bool) { - if let Ok(entries) = std::fs::read_dir(dir) { - for entry in entries.flatten() { - let path = entry.path(); - if path.is_dir() { - damage_blobs(&path, corrupt); - } else if corrupt { - if let Ok(meta) = path.metadata() { - let _ = std::fs::write(&path, vec![0x00; meta.len() as usize]); - } - } else { - let _ = std::fs::remove_file(&path); - } - } - } - } - - #[tokio::test] - async fn test_write_read_small_file() { - let (storage, _tmp) = create_test_storage().await; - - // 1 KB file - should be stored inline - let data = Bytes::from(vec![0xAB; 1024]); - storage.put("test-scope", "small.bin", &data).await.unwrap(); - - let file = storage.get("test-scope", "small.bin").await.unwrap(); - assert!(file.is_some()); - - let file = file.unwrap(); - assert!(file.inlined); - assert_eq!(file.file_bytes.0, data); - assert_eq!(file.file_size, 1024); - } - - #[tokio::test] - async fn test_write_read_large_file() { - let (storage, tmp) = create_test_storage().await; - - // Large file - should be stored on disk - let data = Bytes::from(vec![0xCD; BIG_FILE_SIZE]); - storage.put("test-scope", "large.bin", &data).await.unwrap(); - - let file = storage.get("test-scope", "large.bin").await.unwrap(); - assert!(file.is_some()); - - let file = file.unwrap(); - assert!(!file.inlined); - assert_eq!(file.file_bytes.0, data); - assert_eq!(file.file_size, (BIG_FILE_SIZE) as i64); - - // Verify file is stored on disk, not inline in SQLite - let db_size = std::fs::metadata(tmp.path().join("index.sqlite")) - .unwrap() - .len(); - assert!( - db_size < data.len() as u64, - "database ({db_size} bytes) should be smaller than file ({} bytes)", - data.len() - ); - } - - #[tokio::test] - async fn test_write_read_boundary_file() { - let (storage, _tmp) = create_test_storage().await; - - // Exactly 256 KB - should be stored inline (threshold is <=) - let data = Bytes::from(vec![0xEF; INLINE_THRESHOLD]); - storage - .put("test-scope", "boundary.bin", &data) - .await - .unwrap(); - - let file = storage.get("test-scope", "boundary.bin").await.unwrap(); - assert!(file.is_some()); - - let file = file.unwrap(); - assert!(file.inlined); - assert_eq!(file.file_bytes.0, data); - assert_eq!(file.file_size, INLINE_THRESHOLD as i64); - } - - #[tokio::test] - async fn test_read_nonexistent_file() { - let (storage, _tmp) = create_test_storage().await; - - let file = storage.get("test-scope", "nonexistent.bin").await.unwrap(); - assert!(file.is_none()); - } - - #[tokio::test] - async fn test_persistence_after_restart() { - let tmp = TempDir::new().unwrap(); - - let small_data = Bytes::from(vec![0x11; 1024]); - let large_data = Bytes::from(vec![0x22; BIG_FILE_SIZE]); - - // First "session": write files - { - let storage = create_storage_at(tmp.path()).await; - storage - .put("persist", "small.bin", &small_data) - .await - .unwrap(); - storage - .put("persist", "large.bin", &large_data) - .await - .unwrap(); - // storage is dropped here, simulating shutdown - } - - // Second "session": verify files persist - { - let storage = create_storage_at(tmp.path()).await; - - let small = storage.get("persist", "small.bin").await.unwrap(); - assert!(small.is_some()); - assert_eq!(small.unwrap().file_bytes.0, small_data); - - let large = storage.get("persist", "large.bin").await.unwrap(); - assert!(large.is_some()); - assert_eq!(large.unwrap().file_bytes.0, large_data); - } - } - - #[tokio::test] - async fn test_error_blob_not_found() { - let (storage, tmp) = create_test_storage().await; - - // Write a large file (stored on disk) - let data = Bytes::from(vec![0xAA; BIG_FILE_SIZE]); - storage - .put("test-scope", "to-delete.bin", &data) - .await - .unwrap(); - - // Delete all blob files from disk - damage_blobs(&tmp.path().join("objects"), false); - - // Reading should fail with BlobNotFound - let result = storage.get("test-scope", "to-delete.bin").await; - assert!(matches!(result, Err(StorageError::BlobNotFound(_)))); - } - - #[tokio::test] - async fn test_error_blob_corrupted() { - let (storage, tmp) = create_test_storage().await; - - // Write a large file (stored on disk) - let data = Bytes::from(vec![0xBB; BIG_FILE_SIZE]); - storage - .put("test-scope", "to-corrupt.bin", &data) - .await - .unwrap(); - - // Corrupt all blob files on disk - damage_blobs(&tmp.path().join("objects"), true); - - // Reading should fail with IntegrityError - let result = storage.get("test-scope", "to-corrupt.bin").await; - assert!(matches!(result, Err(StorageError::IntegrityError))); - } - - #[tokio::test] - async fn test_duplicate_put_same_content() { - let (storage, tmp) = create_test_storage().await; - - // Write a large file - let data = Bytes::from(vec![0xCC; BIG_FILE_SIZE]); - storage.put("test-scope", "dup.bin", &data).await.unwrap(); - - // Write the same file again with identical content - should succeed - let result = storage.put("test-scope", "dup.bin", &data).await; - assert!(result.is_ok()); - - // Verify no temp files left behind - assert_eq!(count_files(&tmp.path().join("objects"), Some("part")), 0); - - // Verify file is still readable with correct content - let file = storage.get("test-scope", "dup.bin").await.unwrap(); - assert!(file.is_some()); - assert_eq!(file.unwrap().file_bytes.0, data); - } - - #[tokio::test] - async fn test_duplicate_put_different_content() { - let (storage, tmp) = create_test_storage().await; - - // Write a large file - let data1 = Bytes::from(vec![0xDD; BIG_FILE_SIZE]); - storage.put("test-scope", "dup.bin", &data1).await.unwrap(); - - // Write the same filename with different content - should fail - let data2 = Bytes::from(vec![0xEE; BIG_FILE_SIZE]); - let result = storage.put("test-scope", "dup.bin", &data2).await; - assert!(matches!(result, Err(StorageError::AlreadyExists(_, _)))); - - // Verify no temp files left behind - assert_eq!(count_files(&tmp.path().join("objects"), Some("part")), 0); - - // Verify original file is still intact - let file = storage.get("test-scope", "dup.bin").await.unwrap(); - assert!(file.is_some()); - assert_eq!(file.unwrap().file_bytes.0, data1); - } - - #[tokio::test] - async fn test_doctor_removes_temp_files() { - let tmp = TempDir::new().unwrap(); - - // First session: write a large file - let data = Bytes::from(vec![0xAA; BIG_FILE_SIZE]); - { - let storage = create_storage_at(tmp.path()).await; - storage.put("test-scope", "valid.bin", &data).await.unwrap(); - } - - // Manually create temp files in the objects directory - let objects_dir = tmp.path().join("objects"); - std::fs::create_dir_all(objects_dir.join("ab/cd")).unwrap(); - std::fs::write(objects_dir.join("ab/cd/test.part"), b"temp1").unwrap(); - std::fs::write(objects_dir.join("ab/cd/another.12345.part"), b"temp2").unwrap(); - - assert_eq!(count_files(&objects_dir, Some("part")), 2); - - // Second session: doctor should clean up temp files - { - let storage = create_storage_at(tmp.path()).await; - - // Temp files should be gone - assert_eq!(count_files(&objects_dir, Some("part")), 0); - - // Valid file should still be readable - let file = storage.get("test-scope", "valid.bin").await.unwrap(); - assert!(file.is_some()); - assert_eq!(file.unwrap().file_bytes.0, data); - } - } - - #[tokio::test] - async fn test_doctor_removes_orphan_blobs() { - let tmp = TempDir::new().unwrap(); - - // First session: write a large file - let data = Bytes::from(vec![0xBB; BIG_FILE_SIZE]); - { - let storage = create_storage_at(tmp.path()).await; - storage.put("test-scope", "valid.bin", &data).await.unwrap(); - } - - // Count files before adding orphan - let objects_dir = tmp.path().join("objects"); - let files_before = count_files(&objects_dir, None); - assert_eq!(files_before, 1); // Only the valid blob - - // Manually create an orphan blob (valid hex name but no DB record) - std::fs::create_dir_all(objects_dir.join("de/ad")).unwrap(); - let orphan_name = "deadbeefdeadbeefdeadbeefdeadbeef"; // 32 hex chars - std::fs::write(objects_dir.join("de/ad").join(orphan_name), b"orphan").unwrap(); - - assert_eq!(count_files(&objects_dir, None), 2); - - // Second session: doctor should clean up orphan blob - { - let storage = create_storage_at(tmp.path()).await; - - // Only the valid file should remain - assert_eq!(count_files(&objects_dir, None), 1); - - // Valid file should still be readable - let file = storage.get("test-scope", "valid.bin").await.unwrap(); - assert!(file.is_some()); - assert_eq!(file.unwrap().file_bytes.0, data); - } - } -} diff --git a/crates/zorian/src/telemetry.rs b/crates/zorian/src/telemetry.rs deleted file mode 100644 index 116a7d0..0000000 --- a/crates/zorian/src/telemetry.rs +++ /dev/null @@ -1,247 +0,0 @@ -// SPDX-FileCopyrightText: 2026 Nikolay Govorov -// SPDX-License-Identifier: AGPL-3.0-or-later - -use std::fmt::Debug; -use std::time::SystemTime; - -use opentelemetry::InstrumentationScope; -use opentelemetry::KeyValue; -use opentelemetry::logs::LogRecord as _; -use opentelemetry::trace::TracerProvider as _; -use opentelemetry_otlp::{ - LogExporter, Protocol, SpanExporter, WithExportConfig, WithHttpConfig, WithTonicConfig, -}; -use opentelemetry_sdk::Resource; -use opentelemetry_sdk::error::OTelSdkResult; -use opentelemetry_sdk::logs::{BatchLogProcessor, LogProcessor, SdkLogRecord, SdkLoggerProvider}; -use opentelemetry_sdk::trace::SdkTracerProvider; -use tonic::metadata::{MetadataKey, MetadataMap, MetadataValue}; -use tonic::transport::{Certificate, ClientTlsConfig, Identity}; -use tracing_subscriber::Layer; -use tracing_subscriber::layer::SubscriberExt; -use tracing_subscriber::util::SubscriberInitExt; - -use crate::config::{LogLevel, OtelcolConfig, StdoutFormat, TelemetryConfig}; - -/// LogProcessor wrapper that sets timestamp from observed_timestamp. -/// -/// opentelemetry-appender-tracing intentionally doesn't set timestamp because -/// tracing doesn't provide it. This causes some backends to show epoch (1970-01-01). -/// See: https://github.com/open-telemetry/opentelemetry-rust/issues/1479 -#[derive(Debug)] -struct TimestampLogProcessor

(P); -impl LogProcessor for TimestampLogProcessor

{ - fn emit(&self, record: &mut SdkLogRecord, scope: &InstrumentationScope) { - if record.timestamp().is_none() { - let ts = record.observed_timestamp().unwrap_or_else(SystemTime::now); - record.set_timestamp(ts); - } - self.0.emit(record, scope); - } - - fn force_flush(&self) -> OTelSdkResult { - self.0.force_flush() - } - - fn shutdown(&self) -> OTelSdkResult { - self.0.shutdown() - } -} - -macro_rules! build_exporter { - ($Exporter:ident, $cfg:expr, $url:expr, $tls:expr, $path:expr) => { - if $cfg.endpoint.starts_with("http://") { - // with_endpoint() requires full path for HTTP protocol - $Exporter::builder() - .with_http() - .with_protocol(Protocol::HttpBinary) - .with_endpoint(format!("{}{}", $url, $path)) - .with_timeout($cfg.timeout) - .with_headers($cfg.headers.clone()) - .build() - .expect(concat!("failed to build ", stringify!($Exporter))) - } else if $cfg.endpoint.starts_with("grpc://") { - $Exporter::builder() - .with_tonic() - .with_endpoint($url) - .with_timeout($cfg.timeout) - .with_tls_config($tls) - .with_metadata(build_metadata($cfg)) - .build() - .expect(concat!("failed to build ", stringify!($Exporter))) - } else { - panic!( - "invalid OTLP endpoint: {}. Expected http:// or grpc://", - $cfg.endpoint - ) - } - }; -} - -fn build_metadata(cfg: &OtelcolConfig) -> MetadataMap { - let mut metadata = MetadataMap::new(); - for (key, value) in &cfg.headers { - if let (Ok(k), Ok(v)) = ( - key.parse::>(), - value.parse::>(), - ) { - metadata.insert(k, v); - } - } - metadata -} - -pub struct TelemetryService { - logger_provider: Option, - tracer_provider: Option, -} -impl Drop for TelemetryService { - fn drop(&mut self) { - self.shutdown(); - } -} -impl TelemetryService { - pub fn init(config: &TelemetryConfig, service_name: &str, service_version: &str) -> Self { - let env_filter = match std::env::var_os("ZORIAN_LOG") { - Some(val) => tracing_subscriber::EnvFilter::try_new(val.to_string_lossy()) - .expect("Invalid ZORIAN_LOG"), - None => tracing_subscriber::EnvFilter::new(Self::log_level_to_filter( - config.stdout.log_level, - )), - }; - - let mut tracer_provider = None; - let mut logger_provider = None; - - let stdout = config - .stdout - .enabled - .then(|| match config.stdout.log_format { - StdoutFormat::Json => tracing_subscriber::fmt::layer().json().boxed(), - StdoutFormat::Pretty => tracing_subscriber::fmt::layer().pretty().boxed(), - }); - - let (otel_logs, otel_traces) = match &config.otelcol { - Some(cfg) if cfg.enabled => { - let tls = Self::build_tls(cfg); - let url = Self::parse_endpoint(&cfg.endpoint); - let resource = Resource::builder() - .with_service_name(service_name.to_string()) - .with_attribute(KeyValue::new( - opentelemetry_semantic_conventions::attribute::SERVICE_VERSION, - service_version.to_string(), - )) - .build(); - - let logs = cfg.logs.then(|| { - let exporter = - build_exporter!(LogExporter, cfg, url.clone(), tls.clone(), "/v1/logs"); - let provider = SdkLoggerProvider::builder() - .with_resource(resource.clone()) - .with_log_processor(TimestampLogProcessor( - BatchLogProcessor::builder(exporter).build(), - )) - .build(); - let layer = - opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge::new( - &provider, - ) - .with_filter(Self::to_level_filter(cfg.log_level)); - logger_provider = Some(provider); - layer - }); - - let traces = cfg.traces.then(|| { - let provider = SdkTracerProvider::builder() - .with_resource(resource.clone()) - .with_batch_exporter(build_exporter!( - SpanExporter, - cfg, - url.clone(), - tls.clone(), - "/v1/traces" - )) - .build(); - let layer = tracing_opentelemetry::layer() - .with_tracer(provider.tracer(service_name.to_string())); - tracer_provider = Some(provider); - layer - }); - - (logs, traces) - } - _ => (None, None), - }; - - tracing_subscriber::registry() - .with(stdout) - .with(otel_logs) - .with(otel_traces) - .with(env_filter) - .init(); - - Self { - tracer_provider, - logger_provider, - } - } - - fn parse_endpoint(endpoint: &str) -> String { - if endpoint.starts_with("http://") { - endpoint.to_string() - } else if let Some(rest) = endpoint.strip_prefix("grpc://") { - format!("https://{rest}") - } else { - panic!("invalid OTLP endpoint: {endpoint}. Expected http:// or grpc://") - } - } - - fn build_tls(cfg: &OtelcolConfig) -> ClientTlsConfig { - let mut tls = ClientTlsConfig::new().with_native_roots(); - if let Some(path) = &cfg.tls_ca { - tls = tls.ca_certificate(Certificate::from_pem( - std::fs::read_to_string(path).expect("failed to read CA"), - )); - } - if let (Some(crt), Some(key)) = (&cfg.tls_crt, &cfg.tls_key) { - tls = tls.identity(Identity::from_pem( - std::fs::read_to_string(crt).expect("failed to read cert"), - std::fs::read_to_string(key).expect("failed to read key"), - )); - } - tls - } - - fn to_level_filter(level: LogLevel) -> tracing_subscriber::filter::LevelFilter { - match level { - LogLevel::Trace => tracing_subscriber::filter::LevelFilter::TRACE, - LogLevel::Debug => tracing_subscriber::filter::LevelFilter::DEBUG, - LogLevel::Info => tracing_subscriber::filter::LevelFilter::INFO, - LogLevel::Warning => tracing_subscriber::filter::LevelFilter::WARN, - LogLevel::Error => tracing_subscriber::filter::LevelFilter::ERROR, - } - } - - fn log_level_to_filter(level: LogLevel) -> &'static str { - match level { - LogLevel::Trace => "trace", - LogLevel::Debug => "debug", - LogLevel::Info => "info", - LogLevel::Warning => "warn", - LogLevel::Error => "error", - } - } - - pub fn shutdown(&mut self) { - if let Some(p) = self.tracer_provider.take() - && let Err(e) = p.shutdown() - { - tracing::error!("failed to shutdown tracer provider: {e}"); - } - if let Some(p) = self.logger_provider.take() - && let Err(e) = p.shutdown() - { - tracing::error!("failed to shutdown logger provider: {e}"); - } - } -} diff --git a/deny.toml b/deny.toml index f9d0ba0..797da56 100644 --- a/deny.toml +++ b/deny.toml @@ -25,8 +25,8 @@ exceptions = [ { crate = "xtask", allow = ["AGPL-3.0-or-later"] }, { crate = "base", allow = ["AGPL-3.0-or-later"] }, { crate = "repos", allow = ["AGPL-3.0-or-later"] }, - { crate = "zorian", allow = ["AGPL-3.0-or-later"] }, { crate = "smoke", allow = ["AGPL-3.0-or-later"] }, + { crate = "recluse", allow = ["AGPL-3.0-or-later"] }, ] unused-allowed-license = "allow" diff --git a/nfpm.yaml b/nfpm.yaml index 262bde9..390cd89 100644 --- a/nfpm.yaml +++ b/nfpm.yaml @@ -4,7 +4,7 @@ # yaml-language-server: $schema=https://nfpm.goreleaser.com/schema.json # vim: set ts=2 sw=2 tw=0 fo=cnqoj -name: zorian +name: recluse arch: ${ARCH} version: ${VERSION} license: AGPL-3.0-or-later @@ -14,34 +14,34 @@ description: Tiny packages caching proxy contents: - src: ./LICENSE - dst: /usr/share/doc/zorian/LICENSE + dst: /usr/share/doc/recluse/LICENSE - src: ./README.md - dst: /usr/share/doc/zorian/README.md + dst: /usr/share/doc/recluse/README.md - - src: target/release/zorian - dst: /usr/local/bin/zorian + - src: target/release/recluse + dst: /usr/local/bin/recluse file_info: mode: 0755 - - src: pkg/zorian.toml - dst: /etc/zorian.toml + - src: pkg/recluse.toml + dst: /etc/recluse.toml type: config|noreplace file_info: mode: 0640 owner: root - group: zorian + group: recluse - - src: pkg/zorian.service - dst: /usr/lib/systemd/system/zorian.service + - src: pkg/recluse.service + dst: /usr/lib/systemd/system/recluse.service file_info: mode: 0644 - - dst: /var/lib/zorian + - dst: /var/lib/recluse type: dir file_info: mode: 0755 owner: root - group: zorian + group: recluse scripts: diff --git a/pkg/recluse.service b/pkg/recluse.service new file mode 100644 index 0000000..caf75db --- /dev/null +++ b/pkg/recluse.service @@ -0,0 +1,51 @@ +# SPDX-FileCopyrightText: 2026 Nikolay Govorov +# SPDX-License-Identifier: AGPL-3.0-or-later + +[Unit] +Description=recluse server (tiny packages caching proxy) +Requires=network-online.target +After=time-sync.target network-online.target remote-fs.target nss-lookup.target +Wants=time-sync.target + +[Service] +Type=notify +User=recluse +Group=recluse +Restart=always +RestartSec=30 +WatchdogSec=30 +NotifyAccess=main +ExecPaths=/usr/local/bin/recluse /usr/lib +ExecStart=/usr/local/bin/recluse --config=/etc/recluse.toml +LimitCORE=infinity +LimitNOFILE=500000 +AmbientCapabilities=CAP_NET_BIND_SERVICE + +# %p is resolved to the systemd unit name +LogsDirectory=%p +StateDirectory=%p +CacheDirectory=%p +RuntimeDirectory=%p + +UMask=0077 +LockPersonality=yes +NoNewPrivileges=yes +PrivateDevices=yes +PrivateTmp=true +ProcSubset=pid +ProtectClock=yes +ProtectControlGroups=yes +ProtectHome=yes +ProtectHostname=yes +ProtectKernelLogs=yes +ProtectKernelModules=yes +ProtectKernelTunables=yes +ProtectProc=invisible +ProtectSystem=strict +RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX +RestrictNamespaces=yes +RestrictSUIDSGID=yes + +[Install] +# service should not start from the rescue shell (rescue.target). +WantedBy=multi-user.target diff --git a/pkg/recluse.toml b/pkg/recluse.toml new file mode 100644 index 0000000..ecda215 --- /dev/null +++ b/pkg/recluse.toml @@ -0,0 +1,59 @@ +# SPDX-FileCopyrightText: 2026 Nikolay Govorov +# SPDX-License-Identifier: AGPL-3.0-or-later + +# recluse will dutifully indicate its user agent and protocols (for example, source for zig). +# Specify your name if you want your instance to be identified. +appname="recluse" + +# Path to the directory for storing state (indexes, caches, statistics). +# Must be a writable directory. +dirname="/var/lib/recluse" + +# Common server settings +[server] +shutdown_timeout = 60 # seconds +request_timeout = 30 # seconds +max_body_size = "64 MiB" +max_concurrent_requests = 512 +rate_limit_period = 10 +rate_limit_burst_size = 50 + +# Listeners configuration. Each listener has an address and optional hostnames. +# Empty hostnames means accept all requests (catch-all). +[[listen]] +addr = "0.0.0.0:2025" +hostnames = ["localhost", "127.0.0.1", "::1"] + +# For HTTPS, set tls_cert and tls_key to PEM file paths. +# tls_crt = "/etc/recluse/cert.pem" +# tls_key = "/etc/recluse/key.pem" + +# Telemetry configuration +# Logs to stdout (pretty or json format) +[telemetry.stdout] +enabled = true +log_level = "info" # trace, debug, info, warning, error +log_format = "pretty" # pretty, json + +# OpenTelemetry Collector (OTLP) +# Uncomment to enable sending logs and traces to an OTLP collector +# [telemetry.otelcol] +# enabled = true +# logs = true +# traces = true +# endpoint = "http://localhost:4318" # HTTP protocol (no TLS) +# # endpoint = "grpc://localhost:4317" # gRPC protocol (requires TLS) +# timeout = 10 # seconds +# log_level = "info" +# +# # For gRPC with TLS, specify certificates: +# # tls_ca = "/etc/recluse/otel-ca.crt" +# # tls_crt = "/etc/recluse/otel-client.crt" # for mTLS +# # tls_key = "/etc/recluse/otel-client.key" # for mTLS +# +# # HTTP headers for authentication: +# # [telemetry.otelcol.headers] +# # Authorization = "Bearer " + +# Environment variable RECLUSE_LOG overrides log_level settings. +# Example: RECLUSE_LOG=debug,sqlx=warn diff --git a/pkg/scripts/postinstall.sh b/pkg/scripts/postinstall.sh index 8a1e7cf..fe717a3 100644 --- a/pkg/scripts/postinstall.sh +++ b/pkg/scripts/postinstall.sh @@ -4,7 +4,7 @@ set -e -if [ -x "/bin/systemctl" ] && [ -d /run/systemd/system ] && [ -f /usr/lib/systemd/system/zorian.service ]; then +if [ -x "/bin/systemctl" ] && [ -d /run/systemd/system ] && [ -f /usr/lib/systemd/system/recluse.service ]; then /bin/systemctl daemon-reload - /bin/systemctl enable zorian + /bin/systemctl enable recluse fi diff --git a/pkg/scripts/preinstall.sh b/pkg/scripts/preinstall.sh index 2828c95..7f0e0de 100644 --- a/pkg/scripts/preinstall.sh +++ b/pkg/scripts/preinstall.sh @@ -4,14 +4,14 @@ set -e -PROGRAM=zorian -ZORIAN_USER=${ZORIAN_USER:-zorian} -ZORIAN_GROUP=${ZORIAN_GROUP:-${ZORIAN_USER}} +PROGRAM=recluse +RECLUSE_USER=${RECLUSE_USER:-recluse} +RECLUSE_GROUP=${RECLUSE_GROUP:-${RECLUSE_USER}} -if ! getent group $ZORIAN_GROUP >/dev/null; then - groupadd --system $ZORIAN_GROUP +if ! getent group $RECLUSE_GROUP >/dev/null; then + groupadd --system $RECLUSE_GROUP fi -if ! getent passwd $ZORIAN_USER >/dev/null; then - useradd --system --gid $ZORIAN_GROUP --no-create-home --shell /usr/sbin/nologin $ZORIAN_USER +if ! getent passwd $RECLUSE_USER >/dev/null; then + useradd --system --gid $RECLUSE_GROUP --no-create-home --shell /usr/sbin/nologin $RECLUSE_USER fi diff --git a/pkg/scripts/preremove.sh b/pkg/scripts/preremove.sh index 87c062a..3e69d06 100644 --- a/pkg/scripts/preremove.sh +++ b/pkg/scripts/preremove.sh @@ -4,7 +4,7 @@ set -e -if [ -x "/bin/systemctl" ] && [ -d /run/systemd/system ] && [ -f /usr/lib/systemd/system/zorian.service ]; then - /bin/systemctl stop zorian.service || true - /bin/systemctl disable zorian.service || true +if [ -x "/bin/systemctl" ] && [ -d /run/systemd/system ] && [ -f /usr/lib/systemd/system/recluse.service ]; then + /bin/systemctl stop recluse.service || true + /bin/systemctl disable recluse.service || true fi diff --git a/pkg/zorian.service b/pkg/zorian.service deleted file mode 100644 index 64f34b5..0000000 --- a/pkg/zorian.service +++ /dev/null @@ -1,51 +0,0 @@ -# SPDX-FileCopyrightText: 2026 Nikolay Govorov -# SPDX-License-Identifier: AGPL-3.0-or-later - -[Unit] -Description=Zorian server (tiny packages caching proxy) -Requires=network-online.target -After=time-sync.target network-online.target remote-fs.target nss-lookup.target -Wants=time-sync.target - -[Service] -Type=notify -User=zorian -Group=zorian -Restart=always -RestartSec=30 -WatchdogSec=30 -NotifyAccess=main -ExecPaths=/usr/local/bin/zorian /usr/lib -ExecStart=/usr/local/bin/zorian --config=/etc/zorian.toml -LimitCORE=infinity -LimitNOFILE=500000 -AmbientCapabilities=CAP_NET_BIND_SERVICE - -# %p is resolved to the systemd unit name -LogsDirectory=%p -StateDirectory=%p -CacheDirectory=%p -RuntimeDirectory=%p - -UMask=0077 -LockPersonality=yes -NoNewPrivileges=yes -PrivateDevices=yes -PrivateTmp=true -ProcSubset=pid -ProtectClock=yes -ProtectControlGroups=yes -ProtectHome=yes -ProtectHostname=yes -ProtectKernelLogs=yes -ProtectKernelModules=yes -ProtectKernelTunables=yes -ProtectProc=invisible -ProtectSystem=strict -RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX -RestrictNamespaces=yes -RestrictSUIDSGID=yes - -[Install] -# service should not start from the rescue shell (rescue.target). -WantedBy=multi-user.target diff --git a/pkg/zorian.toml b/pkg/zorian.toml deleted file mode 100644 index 0fde186..0000000 --- a/pkg/zorian.toml +++ /dev/null @@ -1,59 +0,0 @@ -# SPDX-FileCopyrightText: 2026 Nikolay Govorov -# SPDX-License-Identifier: AGPL-3.0-or-later - -# Zorian will dutifully indicate its user agent and protocols (for example, source for zig). -# Specify your name if you want your instance to be identified. -appname="zorian" - -# Path to the directory for storing state (indexes, caches, statistics). -# Must be a writable directory. -dirname="/var/lib/zorian" - -# Common server settings -[server] -shutdown_timeout = 60 # seconds -request_timeout = 30 # seconds -max_body_size = "64 MiB" -max_concurrent_requests = 512 -rate_limit_period = 10 -rate_limit_burst_size = 50 - -# Listeners configuration. Each listener has an address and optional hostnames. -# Empty hostnames means accept all requests (catch-all). -[[listen]] -addr = "0.0.0.0:2025" -hostnames = ["localhost", "127.0.0.1", "::1"] - -# For HTTPS, set tls_cert and tls_key to PEM file paths. -# tls_crt = "/etc/zorian/cert.pem" -# tls_key = "/etc/zorian/key.pem" - -# Telemetry configuration -# Logs to stdout (pretty or json format) -[telemetry.stdout] -enabled = true -log_level = "info" # trace, debug, info, warning, error -log_format = "pretty" # pretty, json - -# OpenTelemetry Collector (OTLP) -# Uncomment to enable sending logs and traces to an OTLP collector -# [telemetry.otelcol] -# enabled = true -# logs = true -# traces = true -# endpoint = "http://localhost:4318" # HTTP protocol (no TLS) -# # endpoint = "grpc://localhost:4317" # gRPC protocol (requires TLS) -# timeout = 10 # seconds -# log_level = "info" -# -# # For gRPC with TLS, specify certificates: -# # tls_ca = "/etc/zorian/otel-ca.crt" -# # tls_crt = "/etc/zorian/otel-client.crt" # for mTLS -# # tls_key = "/etc/zorian/otel-client.key" # for mTLS -# -# # HTTP headers for authentication: -# # [telemetry.otelcol.headers] -# # Authorization = "Bearer " - -# Environment variable ZORIAN_LOG overrides log_level settings. -# Example: ZORIAN_LOG=debug,sqlx=warn diff --git a/tests/smoke/run-local.sh b/tests/smoke/run-local.sh index 4117271..32193dd 100755 --- a/tests/smoke/run-local.sh +++ b/tests/smoke/run-local.sh @@ -2,27 +2,27 @@ # SPDX-FileCopyrightText: 2026 Nikolay Govorov # SPDX-License-Identifier: AGPL-3.0-or-later -# Builds zorian, starts it in a temporary directory, runs smoke tests, cleans up. +# Builds recluse, starts it in a temporary directory, runs smoke tests, cleans up. # # Usage: # ./tests/smoke/run-local.sh # default port 2025 -# ZORIAN_PORT=9999 ./tests/smoke/run-local.sh +# RECLUSE_PORT=9999 ./tests/smoke/run-local.sh set -euo pipefail -PORT="${ZORIAN_PORT:-2025}" +PORT="${RECLUSE_PORT:-2025}" BASE_URL="http://127.0.0.1:${PORT}" TMPDIR="$(mktemp -d)" -LOGFILE="$TMPDIR/zorian.log" +LOGFILE="$TMPDIR/recluse.log" trap 'kill "$PID" 2>/dev/null; wait "$PID" 2>/dev/null; rm -rf "$TMPDIR"' EXIT # Build -echo "Building zorian..." -cargo build --release -p zorian +echo "Building recluse..." +cargo build --release -p recluse # Write minimal config -cat > "$TMPDIR/zorian.toml" < "$TMPDIR/recluse.toml" <"$LOGFILE" 2>&1 & +cargo run --release -p recluse -- --config="$TMPDIR/recluse.toml" >"$LOGFILE" 2>&1 & PID=$! # Wait for index to load (log shows "index refreshed" for each backend) @@ -60,7 +60,7 @@ for i in $(seq 1 120); do break fi if ! kill -0 "$PID" 2>/dev/null; then - echo "zorian exited unexpectedly. Server log:" + echo "recluse exited unexpectedly. Server log:" cat "$LOGFILE" exit 1 fi @@ -74,4 +74,4 @@ if ! grep -q "index refreshed" "$LOGFILE" 2>/dev/null; then fi # Run smoke tests -ZORIAN_URL="${BASE_URL}" cargo run -p smoke +RECLUSE_URL="${BASE_URL}" cargo run -p smoke diff --git a/tests/smoke/src/main.rs b/tests/smoke/src/main.rs index 93a914b..f94af25 100644 --- a/tests/smoke/src/main.rs +++ b/tests/smoke/src/main.rs @@ -1,13 +1,13 @@ // SPDX-FileCopyrightText: 2026 Nikolay Govorov // SPDX-License-Identifier: AGPL-3.0-or-later -// Black-box smoke tests for Zorian. +// Black-box smoke tests for Recluse. // -// Downloads archives from Zorian and upstream, compares sha256 hashes, +// Downloads archives from Recluse and upstream, compares sha256 hashes, // verifies that minisig signatures (Zig) and sha256 checksums (Go) match upstream. // // Usage: -// ZORIAN_URL=https://pkg.earth cargo run -p smoke +// RECLUSE_URL=https://pkg.earth cargo run -p smoke use sha2::{Digest, Sha256}; @@ -198,8 +198,8 @@ fn test_web(r: &mut Runner, base_url: &str) { r.fail(name, &format!("status {status}, expected 200")); } else if !ct.contains("text/html") { r.fail(name, &format!("content-type: {ct}")); - } else if !body.contains("Zorian") { - r.fail(name, "body missing \"Zorian\""); + } else if !body.contains("Recluse") { + r.fail(name, "body missing \"Recluse\""); } else { r.ok(name); } @@ -274,11 +274,11 @@ fn test_go(r: &mut Runner, base_url: &str) { r.fetch_bytes(&format!("{base_url}/go/{file}")), r.fetch_bytes(&format!("https://go.dev/dl/{file}")), ) { - (Ok(zorian), Ok(upstream)) => { - let zh = sha256hex(&zorian); + (Ok(recluse), Ok(upstream)) => { + let zh = sha256hex(&recluse); let uh = sha256hex(&upstream); if zh != uh { - r.fail(&name, &format!("zorian={zh} upstream={uh}")); + r.fail(&name, &format!("recluse={zh} upstream={uh}")); } else { r.ok(&name); } @@ -332,11 +332,11 @@ fn test_zig(r: &mut Runner, base_url: &str) { r.fetch_bytes(&format!("{base_url}/zig/{}", entry.file)), r.fetch_bytes(&zig_upstream_url(entry.file, entry.version)), ) { - (Ok(zorian), Ok(upstream)) => { - let zh = sha256hex(&zorian); + (Ok(recluse), Ok(upstream)) => { + let zh = sha256hex(&recluse); let uh = sha256hex(&upstream); if zh != uh { - r.fail(&name, &format!("zorian={zh} upstream={uh}")); + r.fail(&name, &format!("recluse={zh} upstream={uh}")); } else { r.ok(&name); } @@ -348,11 +348,11 @@ fn test_zig(r: &mut Runner, base_url: &str) { // Signature: compare .minisig with upstream { let name = format!("zig: {}.minisig matches upstream", entry.file); - let zorian_url = format!("{base_url}/zig/{}.minisig", entry.file); + let recluse_url = format!("{base_url}/zig/{}.minisig", entry.file); let upstream_url = format!("{}.minisig", zig_upstream_url(entry.file, entry.version)); - match (r.fetch_bytes(&zorian_url), r.fetch_bytes(&upstream_url)) { - (Ok(zorian), Ok(upstream)) => { - if zorian != upstream { + match (r.fetch_bytes(&recluse_url), r.fetch_bytes(&upstream_url)) { + (Ok(recluse), Ok(upstream)) => { + if recluse != upstream { r.fail(&name, "minisig content differs from upstream"); } else { r.ok(&name); @@ -374,11 +374,11 @@ fn test_zig(r: &mut Runner, base_url: &str) { } fn main() { - let base_url = match std::env::var("ZORIAN_URL") { + let base_url = match std::env::var("RECLUSE_URL") { Ok(url) => url, Err(_) => { - eprintln!("Error: ZORIAN_URL environment variable is not set."); - eprintln!("Usage: ZORIAN_URL=https://pkg.earth cargo run -p smoke"); + eprintln!("Error: RECLUSE_URL environment variable is not set."); + eprintln!("Usage: RECLUSE_URL=https://pkg.earth cargo run -p smoke"); std::process::exit(1); } }; diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 786eafc..333e3a4 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -6,7 +6,7 @@ fn main() -> Result<(), Box> { match args.first().map(|s| s.as_str()) { Some("licenses") => { - let json = xtask::licenses::generate_json("crates/zorian/Cargo.toml")?; + let json = xtask::licenses::generate_json("crates/recluse/Cargo.toml")?; println!("{json}"); Ok(()) } -- Gilti