From fda15b194bfa46b3e1bdea84dca17d9f6601a591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gruszczy=C5=84ski?= Date: Tue, 6 Oct 2026 23:20:37 +0200 Subject: [PATCH] small www --- Dockerfile | 54 +++++++++---------- README.md | 109 +++++++++++++++++++++++++++++--------- docker-compose.yml | 17 ++++++ http/nginx.conf | 67 +++++++++++++++++++++++ scripts/generate-index.sh | 45 +++++++++++++--- start.sh | 101 ++++++++++++++++++++++++++++++----- tests/static.sh | 15 +++++- 7 files changed, 336 insertions(+), 72 deletions(-) create mode 100644 http/nginx.conf diff --git a/Dockerfile b/Dockerfile index ecb626f..558cf6f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,41 +7,41 @@ ARG APTLY_VERSION=1.6.3 ARG APTLY_ZIP_SHA256=535ed24eb706bc25a316b59d709a7e74e10165f2ffab8552097ba7e4816a3e7e RUN dnf -y install --allowerasing \ - bash binutils ca-certificates cmake coreutils createrepo_c curl findutils \ - gcc gcc-c++ git gnupg2 gzip make openssl pkgconf-pkg-config python3 python3.11 \ - rpm rsync shadow-utils sqlite-devel tar unzip xz \ - && dnf clean all \ - && rm -rf /var/cache/dnf + bash binutils ca-certificates cmake coreutils createrepo_c curl findutils \ + gcc gcc-c++ git gnupg2 gzip make openssl pkgconf-pkg-config python3 python3.11 \ + rpm rsync shadow-utils sqlite-devel tar unzip xz \ + && dnf clean all \ + && rm -rf /var/cache/dnf RUN set -eux; \ - curl -fsSL -o /tmp/nfpm.rpm \ - "https://github.com/goreleaser/nfpm/releases/download/v${NFPM_VERSION}/nfpm-${NFPM_VERSION}-1.x86_64.rpm"; \ - echo "${NFPM_RPM_SHA256} /tmp/nfpm.rpm" | sha256sum -c -; \ - rpm -Uvh /tmp/nfpm.rpm; \ - rm -f /tmp/nfpm.rpm; \ - nfpm --version + curl -fsSL -o /tmp/nfpm.rpm \ + "https://github.com/goreleaser/nfpm/releases/download/v${NFPM_VERSION}/nfpm-${NFPM_VERSION}-1.x86_64.rpm"; \ + echo "${NFPM_RPM_SHA256} /tmp/nfpm.rpm" | sha256sum -c -; \ + rpm -Uvh /tmp/nfpm.rpm; \ + rm -f /tmp/nfpm.rpm; \ + nfpm --version RUN set -eux; \ - curl -fsSL -o /tmp/aptly.zip \ - "https://github.com/aptly-dev/aptly/releases/download/v${APTLY_VERSION}/aptly_${APTLY_VERSION}_linux_amd64.zip"; \ - echo "${APTLY_ZIP_SHA256} /tmp/aptly.zip" | sha256sum -c -; \ - mkdir -p /tmp/aptly; \ - unzip -q /tmp/aptly.zip -d /tmp/aptly; \ - install -m 0755 "$(find /tmp/aptly -type f -name aptly | head -n1)" /usr/local/bin/aptly; \ - rm -rf /tmp/aptly /tmp/aptly.zip; \ - aptly version + curl -fsSL -o /tmp/aptly.zip \ + "https://github.com/aptly-dev/aptly/releases/download/v${APTLY_VERSION}/aptly_${APTLY_VERSION}_linux_amd64.zip"; \ + echo "${APTLY_ZIP_SHA256} /tmp/aptly.zip" | sha256sum -c -; \ + mkdir -p /tmp/aptly; \ + unzip -q /tmp/aptly.zip -d /tmp/aptly; \ + install -m 0755 "$(find /tmp/aptly -type f -name aptly | head -n1)" /usr/local/bin/aptly; \ + rm -rf /tmp/aptly /tmp/aptly.zip; \ + aptly version ENV RUSTUP_HOME=/opt/rustup \ - CARGO_HOME=/opt/cargo \ - RUST_PROXY_PYTHON=/usr/bin/python3.11 \ - PATH=/opt/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + CARGO_HOME=/opt/cargo \ + RUST_PROXY_PYTHON=/usr/bin/python3.11 \ + PATH=/opt/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin RUN set -eux; \ - curl --proto '=https' --tlsv1.2 -fsSL https://sh.rustup.rs -o /tmp/rustup-init.sh; \ - sh /tmp/rustup-init.sh -y --no-modify-path --profile minimal --default-toolchain "${RUST_TOOLCHAIN}" --component rustfmt --component clippy; \ - rm -f /tmp/rustup-init.sh; \ - rustc --version; \ - cargo --version + curl --proto '=https' --tlsv1.2 -fsSL https://sh.rustup.rs -o /tmp/rustup-init.sh; \ + sh /tmp/rustup-init.sh -y --no-modify-path --profile minimal --default-toolchain "${RUST_TOOLCHAIN}" --component rustfmt --component clippy; \ + rm -f /tmp/rustup-init.sh; \ + rustc --version; \ + cargo --version # Registry/git/target cache is persistent, while rustup/toolchains stay in the image. ENV CARGO_HOME=/var/lib/package-builder/cargo diff --git a/README.md b/README.md index 00c684d..9da1841 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Rust Package Builder -Minimalny kontener, który cyklicznie sprawdza branch Git, buduje projekt Rust i publikuje podpisane repozytoria APT oraz RPM/DNF. +Minimalny automat Docker, który cyklicznie sprawdza branch Git, buduje projekt Rust i publikuje podpisane repozytoria APT oraz RPM/DNF. Projekt zawiera również mały, utwardzony serwer HTTP udostępniający gotowe repozytorium i stronę z instrukcją instalacji. ## Obsługiwane cele @@ -26,14 +26,40 @@ Nie utrzymuje drugiej kopii konfiguracji systemd RustProxy. Wersja i nazwa binar ## Uruchomienie -Najprostszy wariant wymaga ustawienia tylko dwóch wartości: +Ustawiasz ręcznie tylko dwie wartości: ```bash cp .env.example .env -# edytuj .env i ustaw SOURCE_REPO oraz REPOSITORY_URL +nano .env +``` + +Przykład dla serwera `192.168.1.100`: + +```env +SOURCE_REPO=https://git.linuxiarz.pl/gru/RustProxy.git +REPOSITORY_URL=http://192.168.1.100 +``` + +Następnie: + +```bash ./start.sh ``` +Jeżeli w `REPOSITORY_URL` nie podasz portu, `start.sh` automatycznie ustawi `18765` i zapisze efektywny adres, np.: + +```text +http://192.168.1.100:18765 +``` + +Jeżeli chcesz inny port, wystarczy wpisać go bezpośrednio w adresie: + +```env +REPOSITORY_URL=http://192.168.1.100:23456 +``` + +Nie trzeba ustawiać osobnego `HTTP_PORT` ręcznie — skrypt pobierze go z adresu. `HTTP_PORT` jest zapisywany pomocniczo do `.env`, aby Compose zachował tę samą konfigurację. + `start.sh` automatycznie: - sprawdza Docker i Docker Compose, @@ -41,35 +67,57 @@ cp .env.example .env - buduje obraz buildera, - przy pierwszym uruchomieniu generuje trwały klucz GPG RSA 3072 bez hasła, - zapisuje klucz prywatny jako `gpg/private-key.asc`, publiczny jako `gpg/public-key.asc` oraz fingerprint jako `gpg/fingerprint`, -- przy kolejnych uruchomieniach ponownie używa tego samego klucza, -- uruchamia usługę przez `docker compose up -d`, -- builder natychmiast sprawdza repozytorium Git i po udanym buildzie publikuje APT oraz RPM/DNF. +- przy kolejnych uruchomieniach używa tego samego klucza, +- uruchamia builder i mikroserwer HTTP, +- builder natychmiast sprawdza repozytorium Git i po udanym buildzie publikuje APT oraz RPM/DNF, +- strona główna HTTP automatycznie pokazuje instrukcję instalacji i linki do klucza/metadanych. Można też uruchomić bez wcześniejszego tworzenia `.env`: ```bash SOURCE_REPO=https://git.linuxiarz.pl/gru/RustProxy.git \ -REPOSITORY_URL=https://packages.linuxiarz.pl \ +REPOSITORY_URL=http://192.168.1.100 \ ./start.sh ``` -W takim przypadku `start.sh` zapisze te dwie wartości do `.env`. +## Mikro HTTP -Publiczny katalog repozytorium: +Repozytorium jest wystawiane przez osobny kontener `repository-http` oparty o `nginxinc/nginx-unprivileged:stable-alpine-slim`. + +Domyślnie: ```text -./data/repository/ +http://ADRES_SERWERA:18765/ ``` -Wystaw ten katalog przez nginx/RustProxy/Apache pod adresem z `REPOSITORY_URL`. Builder celowo nie uruchamia własnego HTTP ani TLS. +Serwer HTTP jest celowo bardzo prosty: -RustProxy 0.26.6 wymaga podczas builda Python 3.10+; obraz zawiera Python 3.11 i ustawia `RUST_PROXY_PYTHON=/usr/bin/python3.11`. +- działa jako użytkownik nieuprzywilejowany, +- kontener ma `cap_drop: ALL`, +- ma `no-new-privileges`, +- root filesystem jest read-only, +- repozytorium jest montowane read-only, +- obsługuje wyłącznie `GET` i `HEAD`, +- nie pozwala na upload, +- nie pokazuje listingów katalogów, +- blokuje pliki ukryte, +- dodaje podstawowe nagłówki bezpieczeństwa, +- posiada `/healthz`, +- logi idą do `docker compose logs`. -### Klucz GPG +Przed pierwszym udanym buildem `/` wyświetla prostą informację, że repozytorium jest inicjalizowane. Po publikacji builder atomowo podmienia stronę na właściwą instrukcję instalacji. + +### HTTPS + +Wbudowany mikroserwer świadomie obsługuje tylko HTTP. Jeżeli `REPOSITORY_URL` zaczyna się od `https://`, zakładane jest, że przed nim stoi zewnętrzny reverse proxy/TLS (np. RustProxy/nginx/Caddy). Sam builder nadal wystawia lokalny HTTP na porcie `18765` lub `HTTP_PORT`. + +Dla kompletnego uruchomienia bez reverse proxy użyj `http://IP_LUB_HOST`. + +## Klucz GPG Klucz jest generowany tylko wtedy, gdy `gpg/private-key.asc` nie istnieje. Nie usuwaj katalogu `gpg/` po publikacji repozytorium: zmiana klucza spowoduje, że klienci z wcześniej zainstalowanym kluczem przestaną ufać nowym podpisom. -Do backupu wystarczy zachować co najmniej: +Do backupu zachowaj co najmniej: ```text gpg/private-key.asc @@ -87,11 +135,12 @@ SOURCE_REPO REPOSITORY_URL ``` -Domyślne: +Domyślne / automatyczne: ```text SOURCE_BRANCH=master POLL_INTERVAL=300 +HTTP_PORT=18765 REPO_DISTRIBUTION=stable REPO_COMPONENT=main PACKAGE_RELEASE=auto @@ -100,17 +149,17 @@ GPG_PRIVATE_KEY_FILE=/run/secrets/gpg/private-key.asc GPG_PASSPHRASE_FILE=/run/secrets/gpg/passphrase ``` -`GPG_PASSPHRASE_FILE` nie musi istnieć dla klucza bez hasła. `GPG_KEY_ID` może być podany przez ENV; jeśli go brak, builder wybiera pierwszy zaimportowany klucz prywatny. +`GPG_PASSPHRASE_FILE` nie musi istnieć dla automatycznie generowanego klucza bez hasła. `GPG_KEY_ID` może być podany przez ENV; jeśli go brak, builder wybiera pierwszy zaimportowany klucz prywatny. ## Dane trwałe ```text /var/lib/package-builder/ -├── aptly/ # baza/pool aptly -├── cargo/ # registry + target cache +├── aptly/ +├── cargo/ ├── packages/ -│ ├── deb/ # historia zbudowanych DEB -│ └── rpm/x86_64/ # historia zbudowanych RPM +│ ├── deb/ +│ └── rpm/x86_64/ ├── repository/ │ ├── current -> releases/ │ ├── apt -> current/apt @@ -137,14 +186,22 @@ clone -> cargo build --release -> nFPM DEB/RPM -> podpisy -> aptly -> createrepo Publiczny symlink `repository/current` jest podmieniany dopiero na końcu. Błąd kompilacji, pakowania, podpisu lub generowania metadata nie przełącza publicznego repozytorium. `last_commit` jest zapisywany dopiero po udanej publikacji, więc nieudany commit zostanie ponowiony w następnym cyklu. -Kolejne snapshoty w `repository/releases/` używają hardlinków do niezmienionych plików poprzedniego snapshotu, więc zachowanie historii nie oznacza pełnej kopii wszystkich paczek przy każdym buildzie. +Kolejne snapshoty w `repository/releases/` używają hardlinków do niezmienionych plików poprzedniego snapshotu. ## Podpisy - DEB: podpis GPG nFPM (`_gpgorigin`) oraz podpisane `Release.gpg`/`InRelease` przez aptly. - RPM: podpis GPG pakietu nFPM. - RPM metadata: `repodata/repomd.xml.asc`; instrukcja używa `repo_gpgcheck=1` i `gpgcheck=1`. -- publiczny klucz: `https://.../repo-key.gpg` jako ASCII-armored OpenPGP, zgodny z `gpg --dearmor` i `rpm --import`. +- publiczny klucz: `http(s)://.../repo-key.gpg` jako ASCII-armored OpenPGP, zgodny z `gpg --dearmor` i `rpm --import`. + +## Logi i kontrola + +```bash +docker compose logs -f rust-package-builder +docker compose logs -f repository-http +curl -f http://127.0.0.1:18765/healthz +``` ## Test plików dostarczonego RustProxy @@ -153,10 +210,6 @@ Kolejne snapshoty w `repository/releases/` używają hardlinków do niezmieniony ./tests/check-rustproxy-source.sh /sciezka/do/RustProxy ``` -## HTTP - -Builder nie uruchamia serwera HTTP i nie obsługuje TLS. Generuje katalog `repository/` oraz prosty `index.html` z instrukcją instalacji dopasowaną do `REPOSITORY_URL` i nazwy pakietu. - ## Własny klucz GPG (opcjonalnie) Jeżeli zamiast automatycznie generowanego klucza chcesz użyć własnego, umieść go przed pierwszym `./start.sh` jako: @@ -173,3 +226,7 @@ chmod 600 gpg/private-key.asc ``` `start.sh` wykryje istniejący klucz i nie wygeneruje nowego. Klucz prywatny nie jest kopiowany do obrazu. Kontener otrzymuje katalog `gpg/` wyłącznie jako read-only mount `/run/secrets/gpg`. + +## Rocky Linux 9 / pakiety bazowe + +Dockerfile używa `dnf --allowerasing`, ponieważ obrazy Rocky Linux 9 mogą zawierać `coreutils-single` i `curl-minimal`. Podczas budowy są one zastępowane pełnymi pakietami `coreutils` i `curl`, wymaganymi przez builder. diff --git a/docker-compose.yml b/docker-compose.yml index ca64598..a1b54f3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,3 +12,20 @@ services: - ./data:/var/lib/package-builder - ./gpg:/run/secrets/gpg:ro restart: unless-stopped + + repository-http: + image: nginxinc/nginx-unprivileged:stable-alpine-slim + ports: + - "0.0.0.0:${HTTP_PORT:-18765}:8080" + volumes: + - ./data/repository:/srv/repository:ro + - ./http/nginx.conf:/etc/nginx/nginx.conf:ro + entrypoint: ["nginx", "-g", "daemon off;"] + read_only: true + tmpfs: + - /tmp:rw,noexec,nosuid,size=16m + cap_drop: + - ALL + security_opt: + - no-new-privileges:true + restart: unless-stopped diff --git a/http/nginx.conf b/http/nginx.conf new file mode 100644 index 0000000..be38afb --- /dev/null +++ b/http/nginx.conf @@ -0,0 +1,67 @@ +worker_processes 1; +pid /tmp/nginx.pid; +error_log /dev/stderr warn; + +events { + worker_connections 256; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + access_log /dev/stdout; + server_tokens off; + sendfile on; + tcp_nopush on; + keepalive_timeout 15s; + client_max_body_size 1k; + + client_body_temp_path /tmp/client_temp; + proxy_temp_path /tmp/proxy_temp; + fastcgi_temp_path /tmp/fastcgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + scgi_temp_path /tmp/scgi_temp; + + server { + listen 8080 default_server; + listen [::]:8080 default_server; + server_name _; + + root /srv/repository; + index index.html; + autoindex off; + + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "DENY" always; + add_header Referrer-Policy "no-referrer" always; + add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; + add_header Content-Security-Policy "default-src 'none'; style-src 'unsafe-inline'; img-src 'self'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'" always; + + if ($request_method !~ ^(GET|HEAD)$) { + return 405; + } + + location = /healthz { + default_type text/plain; + return 200 "ok\n"; + } + + location = / { + try_files /index.html @initializing; + } + + location @initializing { + default_type text/html; + return 200 'Rust Package Repository

Rust Package Repository

Repozytorium HTTP działa. Pierwszy build pakietu jeszcze trwa albo nie został zakończony.

Stan buildera sprawdzisz przez docker compose logs -f rust-package-builder.

'; + } + + location ~ (^|/)\. { + deny all; + } + + location / { + try_files $uri =404; + } + } +} diff --git a/scripts/generate-index.sh b/scripts/generate-index.sh index 5668c99..70e7262 100755 --- a/scripts/generate-index.sh +++ b/scripts/generate-index.sh @@ -17,20 +17,42 @@ component=os.environ['REPO_COMPONENT'] h=html.escape content=f''' -{h(package)} repository + + + + +{h(package)} — repozytorium pakietów + + -

{h(package)}

+

{h(package)} — repozytorium pakietów

+

Podpisane pakiety DEB i RPM dla x86_64/amd64.

+
Repozytorium aktywne{h(url)}APT + RPM/DNF
+ +

Debian / Ubuntu

-
curl -fsSL {h(url)}/repo-key.gpg \\
+
curl -fsSL {h(url)}/repo-key.gpg \\
   | sudo gpg --dearmor -o /usr/share/keyrings/{h(package)}.gpg
 
 echo "deb [signed-by=/usr/share/keyrings/{h(package)}.gpg] {h(url)}/apt {h(dist)} {h(component)}" \\
   | sudo tee /etc/apt/sources.list.d/{h(package)}.list
 
 sudo apt update
-sudo apt install {h(package)}
+sudo apt install {h(package)}
+
+ +

RHEL / Rocky / Alma / Fedora

-
sudo rpm --import {h(url)}/repo-key.gpg
+
sudo rpm --import {h(url)}/repo-key.gpg
 
 sudo tee /etc/yum.repos.d/{h(package)}.repo <<'REPO'
 [{h(package)}]
@@ -42,7 +64,18 @@ repo_gpgcheck=1
 gpgkey={h(url)}/repo-key.gpg
 REPO
 
-sudo dnf install {h(package)}
+sudo dnf install {h(package)}
+
+ +
+

Pliki repozytorium

+ +

Obsługiwane cele: Debian 12/13, Ubuntu 24.04/26.04, RHEL 9/10; architektura amd64/x86_64.

+
''' diff --git a/start.sh b/start.sh index fc065fc..6abb376 100755 --- a/start.sh +++ b/start.sh @@ -8,11 +8,17 @@ ENV_FILE="$ROOT/.env" GPG_DIR="$ROOT/gpg" DATA_DIR="$ROOT/data" SERVICE="rust-package-builder" +HTTP_SERVICE="repository-http" +DEFAULT_HTTP_PORT=18765 log() { printf '[start] %s\n' "$*" } +warn() { + printf '[start] WARN: %s\n' "$*" >&2 +} + die() { printf '[start] ERROR: %s\n' "$*" >&2 exit 1 @@ -33,6 +39,21 @@ ENV chmod 0600 "$ENV_FILE" 2>/dev/null || true } +update_env_var() { + local key=$1 + local value=$2 + local tmp="$ENV_FILE.tmp.$$" + + awk -v key="$key" -v value="$value" ' + BEGIN { found=0 } + index($0, key "=") == 1 { print key "=" value; found=1; next } + { print } + END { if (!found) print key "=" value } + ' "$ENV_FILE" > "$tmp" + mv "$tmp" "$ENV_FILE" + chmod 0600 "$ENV_FILE" 2>/dev/null || true +} + load_env_file() { # .env is intentionally limited to simple KEY=value entries used by Compose. # shellcheck disable=SC1090 @@ -41,7 +62,55 @@ load_env_file() { set +a } +normalize_http_settings() { + local url=${REPOSITORY_URL%/} + local rest hostpart explicit_port="" + + HTTP_PORT=${HTTP_PORT:-} + + case "$url" in + http://*) + rest=${url#http://} + [[ "$rest" != */* ]] || die "REPOSITORY_URL dla wbudowanego HTTP nie moze zawierac sciezki: $REPOSITORY_URL" + hostpart=$rest + + if [[ "$hostpart" =~ ^\[[^]]+\]:([0-9]+)$ ]]; then + explicit_port=${BASH_REMATCH[1]} + elif [[ "$hostpart" =~ ^[^:]+:([0-9]+)$ ]]; then + explicit_port=${BASH_REMATCH[1]} + fi + + if [[ -n "$explicit_port" ]]; then + HTTP_PORT=$explicit_port + else + HTTP_PORT=${HTTP_PORT:-$DEFAULT_HTTP_PORT} + url="${url}:${HTTP_PORT}" + REPOSITORY_URL=$url + export REPOSITORY_URL + update_env_var REPOSITORY_URL "$REPOSITORY_URL" + log "REPOSITORY_URL bez portu - ustawiono $REPOSITORY_URL" + fi + ;; + https://*) + # HTTPS is supported as a public URL only when an external TLS proxy points + # to the local micro HTTP service. The embedded service itself is HTTP only. + HTTP_PORT=${HTTP_PORT:-$DEFAULT_HTTP_PORT} + warn "REPOSITORY_URL uzywa HTTPS. Wbudowany serwer nasluchuje po zwyklym HTTP na porcie $HTTP_PORT; HTTPS wymaga zewnetrznego reverse proxy/TLS." + ;; + *) + die "REPOSITORY_URL musi zaczynac sie od http:// albo https://" + ;; + esac + + [[ "$HTTP_PORT" =~ ^[0-9]+$ ]] || die "HTTP_PORT musi byc liczba" + (( HTTP_PORT >= 1024 && HTTP_PORT <= 65535 )) || die "HTTP_PORT musi byc z zakresu 1024-65535" + + export HTTP_PORT + update_env_var HTTP_PORT "$HTTP_PORT" +} + require_cmd docker +require_cmd awk if ! docker info >/dev/null 2>&1; then die "Docker daemon nie jest dostepny dla aktualnego uzytkownika" fi @@ -66,10 +135,8 @@ case "$SOURCE_REPO" in http://*|https://*|ssh://*|git@*|file://*) ;; *) die "SOURCE_REPO ma nieobslugiwany format: $SOURCE_REPO" ;; esac -case "$REPOSITORY_URL" in - http://*|https://*) ;; - *) die "REPOSITORY_URL musi zaczynac sie od http:// albo https://" ;; -esac + +normalize_http_settings mkdir -p "$DATA_DIR/repository" "$DATA_DIR/state" "$DATA_DIR/cargo" "$DATA_DIR/work" "$GPG_DIR" chmod 0700 "$GPG_DIR" 2>/dev/null || true @@ -80,8 +147,11 @@ log "budowanie obrazu buildera" if [[ ! -s "$GPG_DIR/private-key.asc" ]]; then log "brak klucza GPG - generowanie stalego klucza podpisujacego" - IMAGE_REF=$("${COMPOSE[@]}" --env-file "$ENV_FILE" config | awk '$1 == "image:" {print $2; exit}') - [[ -n "$IMAGE_REF" ]] || die "nie mozna ustalic nazwy zbudowanego obrazu" + IMAGE_REF=$("${COMPOSE[@]}" --env-file "$ENV_FILE" config | awk ''' + $1 == "rust-package-builder:" { in_builder=1; next } + in_builder && $1 == "image:" { print $2; exit } + ''') + [[ -n "$IMAGE_REF" ]] || die "nie mozna ustalic nazwy zbudowanego obrazu buildera" docker image inspect "$IMAGE_REF" >/dev/null 2>&1 || die "zbudowany obraz nie istnieje: $IMAGE_REF" uid=$(id -u) @@ -127,8 +197,8 @@ else log "uzywanie istniejacego klucza GPG" fi -log "uruchamianie buildera przez Docker Compose" -"${COMPOSE[@]}" --env-file "$ENV_FILE" up -d "$SERVICE" +log "uruchamianie buildera i mikro HTTP przez Docker Compose" +"${COMPOSE[@]}" --env-file "$ENV_FILE" up -d "$SERVICE" "$HTTP_SERVICE" fingerprint="" if [[ -r "$GPG_DIR/fingerprint" ]]; then @@ -137,13 +207,20 @@ fi log "gotowe" printf '\n' -printf 'SOURCE_REPO: %s\n' "$SOURCE_REPO" -printf 'REPOSITORY_URL: %s\n' "$REPOSITORY_URL" -[[ -n "$fingerprint" ]] && printf 'GPG fingerprint: %s\n' "$fingerprint" +printf 'SOURCE_REPO: %s\n' "$SOURCE_REPO" +printf 'REPOSITORY_URL: %s\n' "$REPOSITORY_URL" +printf 'HTTP port: %s\n' "$HTTP_PORT" +[[ -n "$fingerprint" ]] && printf 'GPG fingerprint: %s\n' "$fingerprint" printf 'Publiczny katalog: %s\n' "$DATA_DIR/repository" printf '\n' -printf 'Podglad logow:\n ' +printf 'Repo/strona: %s/\n' "${REPOSITORY_URL%/}" +printf 'Healthcheck: http://127.0.0.1:%s/healthz\n' "$HTTP_PORT" +printf '\n' +printf 'Podglad logow buildera:\n ' printf '%q ' "${COMPOSE[@]}" printf 'logs -f %q\n' "$SERVICE" +printf 'Podglad logow HTTP:\n ' +printf '%q ' "${COMPOSE[@]}" +printf 'logs -f %q\n' "$HTTP_SERVICE" printf '\n' printf 'Builder natychmiast sprawdzi branch master (lub SOURCE_BRANCH, jezeli ustawiono go opcjonalnie) i po udanym buildzie opublikuje repozytorium.\n' diff --git a/tests/static.sh b/tests/static.sh index c0291ad..7859599 100755 --- a/tests/static.sh +++ b/tests/static.sh @@ -7,6 +7,7 @@ for f in "$ROOT"/start.sh "$ROOT"/scripts/*.sh "$ROOT"/tests/*.sh; do done grep -q 'FROM rockylinux:9' "$ROOT/Dockerfile" +grep -q 'dnf -y install --allowerasing' "$ROOT/Dockerfile" grep -q 'python3.11' "$ROOT/Dockerfile" grep -q 'RUST_PROXY_PYTHON=/usr/bin/python3.11' "$ROOT/Dockerfile" grep -q 'nfpm package' "$ROOT/scripts/build-release.sh" @@ -18,10 +19,22 @@ grep -q 'repo add -force-replace' "$ROOT/scripts/build-release.sh" grep -q '/run/package-builder/gnupg' "$ROOT/scripts/entrypoint.sh" grep -q 'rustproxy-overview.json' "$ROOT/scripts/prepare-package.sh" grep -q 'debian/${PACKAGE_NAME}.service' "$ROOT/scripts/prepare-package.sh" -grep -q 'gpg/private-key.asc' "$ROOT/start.sh" +grep -q 'private-key.asc' "$ROOT/start.sh" grep -q 'docker compose' "$ROOT/start.sh" grep -q 'Key-Type: RSA' "$ROOT/start.sh" +grep -q 'DEFAULT_HTTP_PORT=18765' "$ROOT/start.sh" +grep -q 'repository-http' "$ROOT/start.sh" grep -Fq '${SOURCE_REPO:?SOURCE_REPO is required}' "$ROOT/docker-compose.yml" grep -Fq '${REPOSITORY_URL:?REPOSITORY_URL is required}' "$ROOT/docker-compose.yml" +grep -q 'nginxinc/nginx-unprivileged:stable-alpine-slim' "$ROOT/docker-compose.yml" +grep -q 'read_only: true' "$ROOT/docker-compose.yml" +grep -q 'no-new-privileges:true' "$ROOT/docker-compose.yml" +grep -q 'cap_drop:' "$ROOT/docker-compose.yml" +grep -Fq '0.0.0.0:${HTTP_PORT:-18765}:8080' "$ROOT/docker-compose.yml" +grep -q 'server_tokens off' "$ROOT/http/nginx.conf" +grep -q 'GET|HEAD' "$ROOT/http/nginx.conf" +grep -q 'autoindex off' "$ROOT/http/nginx.conf" +grep -q 'X-Content-Type-Options' "$ROOT/http/nginx.conf" +grep -q 'healthz' "$ROOT/http/nginx.conf" echo 'static checks: OK'