From da460519e8bfae52644d05f061d596ec58322f9f Mon Sep 17 00:00:00 2001 From: emirhanmamak-blueforce Date: Wed, 16 Sep 2026 16:53:24 +0300 Subject: [PATCH] feat(install): internet-free install flow, auto-discovered local packages The operator no longer answers an "offline?" question and no longer needs network access: the installer finds the package set that ships with the checkout, so the only input left is the dealer number. Installer - Auto-discover the local APT repository (BF_OFFLINE_REPO, then provisioning/offline-repo/built, then /opt/blueforce/offline-repo) and enter offline mode on its own; --offline stays for compatibility. - Fail closed with an explicit Turkish message when nothing is found: the searched locations, what to do, and a named exit reason -- no state touched. - Distinguish "repository absent" (operator error, actionable) from "repository present but invalid" (OFFLINE BLOCKED, verification gate). - Network is informational only in precheck/network modules; no probe runs in offline mode and archive.ubuntu.com is no longer mandatory. ISO builder - Look for built/ first, which is what build-index.sh produces, and accept build/ as a warned legacy path. The two disagreed, so a medium could be built without the package set and fail only at install time. Docs - docs/27, scripts/install/README, provisioning/offline-repo/README and provisioning/firstboot/README describe the discovered flow, the two failure modes, and that the installer downloads nothing. Tests - check-admin-static exercised the "console missing from the clone" branch by deleting a tracked file; git clone restored it from history, so the branch never ran and the warning was effectively untested. Build the stripped source as a real commit instead; verified by mutation. --- docs/27-OFFLINE-PROVISIONING.md | 106 +++++++--- provisioning/firstboot/README.md | 34 ++- provisioning/iso/build-blueforce-iso.sh | 13 +- provisioning/offline-repo/README.md | 134 +++++++++--- scripts/install/README.md | 193 +++++++++++++++--- scripts/install/blueforce-install.sh | 7 +- .../install/installer/modules/01-precheck.sh | 39 +++- .../install/installer/modules/05-network.sh | 47 ++++- tests/check-admin-static.sh | 35 +++- 9 files changed, 509 insertions(+), 99 deletions(-) diff --git a/docs/27-OFFLINE-PROVISIONING.md b/docs/27-OFFLINE-PROVISIONING.md index fe90c6c..e110334 100644 --- a/docs/27-OFFLINE-PROVISIONING.md +++ b/docs/27-OFFLINE-PROVISIONING.md @@ -4,7 +4,7 @@ > > - Dosya: `docs/27-OFFLINE-PROVISIONING.md` > -> **Uygulama sözleşmesi:** `--offline`, varsayılan `/opt/blueforce/offline-repo` içindeki yalnız yerel `file:` APT kaynağını kullanır; uzak APT source, curl, wget, key download veya `apt download` çağrısı yapmaz. `Packages`, `Packages.gz`, `SHA256SUMS`, `packages.lock.tsv` ve her manifest için somut `package=version` pinleri eksikse paket modüllerinden önce `OFFLINE BLOCKED` ile durur. Bu repoda gerçek paket/pin bulunmadığından üretilen ISO LAB-only'dir ve provision edilmiş olarak temsil edilmez. +> **Uygulama sözleşmesi:** Kurucu, paket setini **kendi kendine bulur** ve varsayılan olarak yerel depodan kurar; `--offline` bayrağı artık **gerekmez** (geriye uyumluluk için kabul edilir, yalnız yerel depoyu zorlar). Arama sırası: (1) `BF_OFFLINE_REPO` ortam değişkeni, (2) `/provisioning/offline-repo/built`, (3) `/opt/blueforce/offline-repo`; ilk eksiksiz aday kazanır. Yerel `file:` APT kaynağı dışında hiçbir kaynak kullanılmaz: uzak APT source, curl, wget, anahtar indirme veya `apt download` çağrılmaz. **İnternet kurulum için gerekmez.** İki farklı başarısızlık vardır: depo hiç yoksa kurulum Türkçe bir hata ve `ÇIKIŞ NEDENİ: yerel paket deposu bulunamadı.` ile durur; depo bulunup da doğrulanamazsa (eksik `Packages`, `Packages.gz`, `packages.lock.tsv`, `SHA256SUMS`; checksum uyuşmazlığı; boş/bozuk kilit; eksik pin) `OFFLINE BLOCKED: ` ile durur. Her iki durumda da paket modüllerinden önce durulur, kurulum başlamaz ve sistemde hiçbir değişiklik yapılmaz. Paketler bu git deposunda taşınır ve **repo sorumlusu** tarafından `add-packages.sh` + `build-index.sh` ile bu depoya konur; kuran kişi hiçbir şey indirmez. Yalnız geliştirme/test için `--online` vardır ve **üretim cihazlarında kullanılmaz**. > - İlgili kararlar: `24-DECISION-LOG.md#K-16`, `#K-09`, `#K-11`, `#K-12` > - Durum: [ ] Taslak @@ -16,23 +16,23 @@ Saha interneti kesik veya güvenilmezken tekrarlanabilir, denetlenebilir ve secr ## 2. Kapsam -- Kapsam içi: seed USB, offline APT repository/snapshot, kurucu, durum damgası ve sonradan enrollment. +- Kapsam içi: seed USB veya git checkout, offline APT repository/snapshot, kurucunun yerel depoyu otomatik bulması, durum damgası ve sonradan enrollment. - Kapsam dışı: merkezi peer atama ve token doğrulama (29), release imzalama (30). ## 3. Kararlar ```text -KARAR: Offline kurulum, imzalı/sürümlü medya ve ayrı offline APT kaynağıyla yapılır; sonuç durumu yalnızca PROVISIONED_OFFLINE'dır. -GEREKÇE: Paket indirme veya merkezi API'ye erişim yokken cihaz standarda getirilebilir; fakat merkezde doğrulanmamış kimlik ve kanallar READY iddiası yapamaz. -ALTERNATİF: İnternet gelene kadar kurulum yapmama — saha ziyareti ve bekleme maliyeti nedeniyle elendi. -RİSK: Eski veya karışık paket snapshot'ı; manifest, checksum ve release kimliği ile azaltılır. +KARAR: Offline kurulum, imzalı/sürümlü medya ya da git checkout ve ayrı offline APT kaynağıyla yapılır; paket seti kurucu tarafından otomatik bulunur ve sonuç durumu yalnızca PROVISIONED_OFFLINE'dır. +GEREKÇE: Paket indirme veya merkezi API'ye erişim yokken cihaz standarda getirilebilir; fakat merkezde doğrulanmamış kimlik ve kanallar READY iddiası yapamaz. Operatörün hatırlaması gereken bayrak sayısı azaldıkça saha hatası azalır: yerel depo varsayılan kaynaktır. +ALTERNATİF: İnternet gelene kadar kurulum yapmama — saha ziyareti ve bekleme maliyeti nedeniyle elendi. Kurulumu `--offline` bayrağına bağlamak — operatör bayrağı unuttuğunda kurulum durur; otomatik keşif seçildi, bayrak geriye uyumluluk için korundu. +RİSK: Eski veya karışık paket snapshot'ı; manifest, checksum ve release kimliği ile azaltılır. Yanlış/eski depo bulunması; arama sırası ve her adayda eksiksizlik denetimi ile azaltılır. MALİYET: Ücretsiz. LİSANS: APT — https://manpages.ubuntu.com/manpages/noble/en/man8/apt.8.html ; dpkg — https://manpages.ubuntu.com/manpages/noble/en/man1/dpkg.1.html ; Ubuntu offline kurulum ayrıntısı 26.04 için LAB doğrulamalıdır. ``` ## 4. Neden Bu Karar? -Offline medya, işletim sistemi ve zorunlu paketleri taşır; merkezi sırları taşımamalıdır. Durum makinesi, "kuruldu" ile "merkezce güvenildi" arasındaki farkı görünür yapar. +Offline medya ve git deposu, işletim sistemi ve zorunlu paketleri taşır; merkezi sırları taşımamalıdır. Durum makinesi, "kuruldu" ile "merkezce güvenildi" arasındaki farkı görünür yapar. Paket setini **repo sorumlusu** hazırlayıp sürümlediği için sahada "hangi paket nereden geldi?" sorusu `packages.lock.tsv` ve `repo-manifest.yaml` ile yanıtlanır; kuran kişi paket aramaz ve indirmez. ## 5. Alternatifler @@ -41,11 +41,13 @@ Offline medya, işletim sistemi ve zorunlu paketleri taşır; merkezi sırları | Sürümlü offline APT repo | Tekrarlanabilir | Medya yönetimi | **Seçildi** | | Rastgele `.deb` dosyaları | İlk anda kolay | Bağımlılık/sürüm belirsiz | Elendi | | İnternet bekleme | Basit | Saha blokajı | Elendi | +| Yerel depoyu operatörün `--offline` bayrağıyla göstermesi | Basit | Bayrak unutulunca kurulum durur, saha hatası üretir | Elendi (bayrak geriye uyumluluk için korundu) | ## 6. Avantajlar - Bağlantısız sahada standarda yakın kurulum. - Paket manifesti ile hangi sürümün yüklendiği kanıtlanır. +- Kurulum yapan kişi **hiçbir indirme yapmaz** ve bayrak ezberlemez: paketler zaten deponun içindedir, kurucu depoyu kendisi bulur. ## 7. Dezavantajlar @@ -59,28 +61,70 @@ Offline medya, işletim sistemi ve zorunlu paketleri taşır; merkezi sırları | Eski güvenlik paketi | Orta | Orta | Süre sonu olan release medyası, hızlı enrollment kuyruğu | | Secret USB'ye yazılır | Düşük | Yüksek | Secret taraması; token yalnız bir kez ve cihazda girilir | | Yarım paket işlemi | Orta | Orta | `dpkg --configure -a`, idempotent kurucu | +| Kurucu yanlış/eski depoyu bulur | Düşük | Orta | Arama sırası sabittir; aday eksiksiz değilse kullanılmaz, en son `BF_OFFLINE_REPO` ile açıkça yönlendirilebilir | ## 9. Uygulama Planı -1. Medya manifesti: Field OS release, ISO checksum, seed checksum, APT snapshot kimliği, kurucu commit'i. -2. Kurulumda yalnız genel paketler ve `blueforce-install.sh --offline` kullanılır. -3. Kurucu yerel durum dosyasına `PROVISIONED_OFFLINE` yazar; `READY` yazması yasaktır. -4. İnternet geldiğinde 29'daki tek-kullanımlık token ile enrollment başlatılır; sonra merkezi kanallar test edilir. +1. Medya manifesti: Field OS release, ISO checksum, seed checksum, offline APT snapshot kimliği, kurucu commit'i. +2. Paket setini **repo sorumlusu** hazırlar: `.deb` dosyalarını `add-packages.sh` ile depoya koyar, `build-index.sh` ile `provisioning/offline-repo/built` indeksini üretir, `packages.lock.tsv` / `SHA256SUMS` / `repo-manifest.yaml` ile birlikte commit eder. Kuran kişi yalnız git tarafını çeker. +3. Kurulumda yalnız genel paketler kullanılır; kurucu yerel depoyu **otomatik bulur** ve `--offline` gerekmez. +4. Kurucu yerel durum dosyasına `PROVISIONED_OFFLINE` yazar; `READY` yazması yasaktır. +5. İnternet geldiğinde 29'daki tek-kullanımlık token ile enrollment başlatılır; sonra merkezi kanallar test edilir. + +Kuran kişinin komutu (bayrak yok, tek zorunlu bilgi bayi numarası): ```bash -sudo mount /dev/sdX1 /mnt/blueforce-repo -sudo apt -o Dir::Etc::sourcelist=/mnt/blueforce-repo/sources.list update -sudo dpkg --configure -a -sudo ./blueforce-install.sh --offline --dealer-id 12010193 -bf-status # PROVISIONED_OFFLINE beklenir +# Konsoldan (önerilen): Python operatör konsolu; bash yedek yolu sudo bf-menu +sudo bf + +# Doğrudan kurucu ile +sudo ./scripts/install/blueforce-install.sh --dealer-id 12010193 + +# Bilinçli olarak başka bir depo dizinini göstermek (nadir, repo sorumlusu isterse) +BF_OFFLINE_REPO=/mnt/blueforce-repo/built \ + sudo ./scripts/install/blueforce-install.sh --dealer-id 12010193 ``` +Depo bulunduğunda ekranda şu duyuru çıkar: + +```text +Yerel paket deposu bulundu: paket, + Depo : + Kaynak : + Kip : yerel kurulum. İnternet, paket indirme ve ek anahtar gerekmez. +``` + +Depo hiçbir yerde yoksa kurulum başlamadan durur: + +```text +HATA: Yerel paket deposu yok. Repo sorumlusuna başvurun: provisioning/offline-repo/README.md +... +ÇIKIŞ NEDENİ: yerel paket deposu bulunamadı. +``` + +Depo bulundu ama doğrulanamadıysa (bozuk/eksik içerik) kurulum yine başlamaz: + +```text +OFFLINE BLOCKED: + Depo : + Ne yapmalı : paket setini yeniden üretip git ile getirin (provisioning/offline-repo/README.md) + ÇIKIŞ NEDENİ: yerel paket deposu doğrulanamadı; kurulum başlamadı ve + sistemde hiçbir değişiklik yapılmadı. +``` + +`--online` yalnız geliştirme/test makinesi içindir; paketleri internetten çeker ve üretim cihazlarında kullanılmaz. + ## 10. Test Planı | Test | Beklenen sonuç | Ortam | |---|---|---| -| İnternetsiz kurulum | Paketler manifestten kurulur | LAB(2) air-gapped | -| DNS/WAN kesik | Kurucu dış indirme istemez | LAB(2) | +| İnternetsiz kurulum | Paketler manifestten kurulur, dış indirme yok | LAB(2) air-gapped | +| Depo yolu verilmeden kurulum | Kurucu depoyu otomatik bulur (`repo/built`), duyuru satırını yazar | LAB(2) | +| `BF_OFFLINE_REPO` ile başka dizin | Verilen dizin kullanılır; geçersizse durur | LAB(2) | +| Depo hiç yok | Türkçe hata + `ÇIKIŞ NEDENİ: yerel paket deposu bulunamadı.`, exit 1, sistem değişmez | LAB(2) | +| Depo var ama bozuk (checksum/pin) | `OFFLINE BLOCKED: ` + Türkçe çıkış nedeni, exit 1, sistem değişmez | LAB(2) | +| DNS/WAN kesik | Kurucu dış indirme istemez; `01-precheck` ağı yalnız bilgi olarak yazar, `05-network` DNS zorunlu tutmaz | LAB(2) | +| `--online` üretimde denenmez | Yalnız geliştirme/test; kurucu uyarı yazar | LAB(2) | | `bf-status` | `PROVISIONED_OFFLINE`; READY değil | LAB(2) | | Bağlantı sonrası enrollment | ENROLLED → READY kapıları çalışır | LAB(2) | @@ -88,12 +132,17 @@ bf-status # PROVISIONED_OFFLINE beklenir 1. Paket işlemi bozuksa aynı onaylı snapshot ile `dpkg --configure -a` ve kurucu yeniden çalıştırılır. 2. Yanlış medya sürümü geri çekilir; önceki onaylı medya manifestiyle yeniden kurulur. -3. Kimlik/token hatasında cihaz resetlenmez; 29'daki token iptal/yenileme prosedürü uygulanır. +3. Yerel depo bozuksa sahada onarılmaz: repo sorumlusu depoyu yeniden üretip commit eder (`add-packages.sh` + `build-index.sh`), kurulum yapan kişi güncel git tarafını çekip komutu tekrarlar. +4. Kimlik/token hatasında cihaz resetlenmez; 29'daki token iptal/yenileme prosedürü uygulanır. ## 12. Kontrol Listesi -- [ ] Offline medya manifesti ve checksum'ları var. -- [ ] Medyada cihaz kimliği, private key veya kalıcı token yok. +- [ ] Offline medya/git manifesti ve checksum'ları var. +- [ ] Paket seti repoda: `provisioning/offline-repo/built` (`Packages`, `Packages.gz`, `packages.lock.tsv`, `SHA256SUMS`, `pool/`). +- [ ] `repo-manifest.yaml` güncel; pin listesi ile paket havuzu uyuşuyor. +- [ ] Medyada/depoda cihaz kimliği, private key veya kalıcı token yok. +- [ ] Kuran kişinin komutu `--offline` bayrağı istemiyor; depo otomatik bulunuyor. +- [ ] İnternet kapalıyken kurulum tamamlanıyor; dış indirme çağrısı yok. - [ ] `PROVISIONED_OFFLINE` görünür ve READY kapısı kapalı. - [ ] Sonradan enrollment sahibi/kuyruğu kayıtlı. @@ -101,16 +150,21 @@ bf-status # PROVISIONED_OFFLINE beklenir - [ ] Offline APT snapshot yenileme sıklığı — sahibi: release yöneticisi. - [ ] Medyanın fiziksel zimmet ve imha süreci — sahibi: saha operasyonu. +- [ ] Git checkout ile ISO/medya yolundan hangisinin birincil olduğu ve `--online` geliştirme yolunun hangi ortamlarda serbest olduğu — sahibi: yönetim + 26/33 yazarları. --- -## Ek: Durum akışı +## Ek: Keşif ve durum akışı ```mermaid flowchart LR - M["ISO + seed + offline APT"] --> P["PROVISIONED_OFFLINE"] + M["ISO/seed veya git checkout
+ repodaki offline APT"] --> D{"Kurucu yerel depoyu arar
BF_OFFLINE_REPO → repo/built → /opt/blueforce/offline-repo"} + D -->|"hiçbiri yok / eksik"| X["HATA: Yerel paket deposu yok
ÇIKIŞ NEDENİ: bulunamadı · exit 1
sistem değişmez"] + D -->|"eksiksiz aday bulundu"| V{"Doğrulama katmanı:
dosya listesi, SHA256SUMS, kilit, pin ↔ pool"} + V -->|"başarısız"| B["OFFLINE BLOCKED: sebep
ÇIKIŞ NEDENİ: doğrulanamadı · exit 1"] + V -->|"geçti"| P["PROVISIONED_OFFLINE"] P --> T["Tek kullanımlık token"] T --> E["ENROLLED"] - E --> V["WG + erişim + izleme doğrulama"] - V --> R["READY"] -``` \ No newline at end of file + E --> C["WG + erişim + izleme doğrulama"] + C --> R["READY"] +``` diff --git a/provisioning/firstboot/README.md b/provisioning/firstboot/README.md index b9a88ea..4000fc2 100644 --- a/provisioning/firstboot/README.md +++ b/provisioning/firstboot/README.md @@ -2,7 +2,7 @@ Bu dizin, cihazın ilk açılışında sahada çalışan giriş noktasını barındırır: -- `bf-firstboot` — bayi numarasını toplayan/doğrulayan ve yerel offline kurucuyu bir kez çalıştıran script. +- `bf-firstboot` — bayi numarasını toplayan/doğrulayan ve yerel offline kurucuyu bir kez çalıştıran script. Kurucu paket deposunu kendisi bulur; internet gerekmez, teknisyen hiçbir şey indirmez. - `blueforce-firstboot.service` — boot'ta script'i bir kez çalıştıran systemd unit'i. - Bu doküman — gerçek davranış, otomasyon yolu, kimlik değişimi prosedürü ve secret kuralları. @@ -89,9 +89,27 @@ Ortam değişkenleri: `BF_FIRSTBOOT_MARKER` (marker yolu), `STATE_DIR` (varsayı - Marker yalnız kurucu başarıyla bittikten sonra yazılır (`set -euo pipefail` sayesinde hata hâlinde yazılmaz). - Önceki koşu yarıda kaldıysa (`$STATE_DIR/install-state` dolu) kurucu `--resume` ile çağrılır: kurucu `--offline --dealer-id --yes` (+ gerekirse `--resume`) argümanlarıyla koşar. -- Script her zaman kurucuyu `--offline` ile çağırır; kurucu `PROVISIONED_OFFLINE` durumuna tamamlar. +- Script kurucuyu `--offline` ile çağırır. **Bu bayrak artık zorunlu değildir**: kurucu yerel + paket deposunu kendisi bulur (`BF_OFFLINE_REPO` → `/provisioning/offline-repo/built` → + `/opt/blueforce/offline-repo`). firstboot bayrağı geriye uyumluluk için verir; sonuç aynıdır: + yerel depodan, internet olmadan kurulum ve `PROVISIONED_OFFLINE` durumu. - `--check` hiçbir dosya/dizin/log üretmez ve kurucuyu çağırmaz. +### Depo bulunamazsa / doğrulanamazsa + +firstboot kurucuyu çağırır; paket deposuna ilişkin karar ve mesaj **kurucunun** sorumluluğundadır. +İki farklı durum vardır ve ikisinde de firstboot marker **yazmaz** (cihaz provision edilmiş sayılmaz): + +| Durum | Kim söyler | Ekranda ne görünür (kısaltılmış) | Sonuç | +|---|---|---|---| +| Yerel depo hiç yok (üç arama yerinde de yok) | Kurucu | `HATA: Yerel paket deposu yok. Repo sorumlusuna başvurun: provisioning/offline-repo/README.md` … `ÇIKIŞ NEDENİ: yerel paket deposu bulunamadı.` | `exit 1`; hiçbir şey değişmez | +| Depo bulundu ama doğrulanamadı (checksum, kilit, eksik pin) | Kurucu | `OFFLINE BLOCKED: ` … `ÇIKIŞ NEDENİ: yerel paket deposu doğrulanamadı…` | `exit 1`; hiçbir şey değişmez | +| Admin public key eksik/geçersiz | firstboot'un kendi kapısı | `OFFLINE BLOCKED: seed-provided BF_ADMIN_PUBLIC_KEY_FILE is required.` (veya anahtar kuralı satırı) | `exit 1`; kurucu hiç çağrılmaz | + +Çözüm sahadaki teknisyenin işi değildir: mesajı repo sorumlusuna iletmek ve depo düzeltildikten +sonra kurulumu tekrar çalıştırmak yeterlidir. Kurulumu yapan kişi hiçbir şey indirmez; paketler +git deposunda taşınır. + ## 4. Kimlik değişimi prosedürü (admin / recovery — varsayılan KAPALI) Bayi numarası değişimi **sıradan kullanıcı yolu değildir**. Wizard ve normal koşu bu yolu içermez. @@ -120,9 +138,15 @@ Değişimden sonra `docs/02-DEVICE-NAMING-AND-INVENTORY.md` §9'daki yeniden-num - Script secret **loglamaz**: mesajlarda yalnız dosya yolları ve cihaz kimlikleri geçer; anahtar içeriği, token, parola hiçbir satıra yazılmaz (`--force-reidentity` audit kaydı da yalnız kimlikleri yazar). - Wizard girdisi ekrana yankılanır (teknisyen yazar); bu ekran token/parola istemez, yalnız bayi numarası alır. -- ISO'da geçerli yerel APT indeksleri, checksum/lock ve tüm somut pinli paketler yoksa işlem - `OFFLINE BLOCKED` ile durur ve cihaz provision edilmiş sayılmaz. Yalnız offline bundle + public-key - önkoşulları geçerse `PROVISIONED_OFFLINE` yazılır. +- Kurucu, yerel paket deposunu kendisi bulur (`BF_OFFLINE_REPO` → `/provisioning/offline-repo/built` + → `/opt/blueforce/offline-repo`); `--offline` bayrağı gerekmez. Internet kurulum için gerekmez. + Public-key önkoşulu geçtikten sonra: + * depo hiç yoksa kurucu Türkçe `HATA: Yerel paket deposu yok…` + `ÇIKIŞ NEDENİ: yerel paket deposu bulunamadı.` ile durur; + * depo bulunup da doğrulanamazsa (geçerli yerel APT indeksleri, checksum/lock ya da tüm somut + pinli paketler eksik/bozuk) kurucu `OFFLINE BLOCKED: ` ile durur. + Her iki durumda cihaz provision edilmiş sayılmaz ve firstboot marker yazmaz. Yalnız yerel depo + + public-key önkoşulları geçerse `PROVISIONED_OFFLINE` yazılır. Ayrıntı: §3 ve + `provisioning/offline-repo/README.md` §3. ## 6. systemd unit ve boot'u kilitlememe diff --git a/provisioning/iso/build-blueforce-iso.sh b/provisioning/iso/build-blueforce-iso.sh index 2e9b491..834a1a3 100755 --- a/provisioning/iso/build-blueforce-iso.sh +++ b/provisioning/iso/build-blueforce-iso.sh @@ -32,7 +32,11 @@ AUTOINSTALL_DIR="$PROVISIONING_DIR/autoinstall" FIRSTBOOT_DIR="$PROVISIONING_DIR/firstboot" RELEASE_DIR="$PROVISIONING_DIR/release" OFFLINE_REPO_DIR="$PROVISIONING_DIR/offline-repo" -OFFLINE_AUTODETECT="$OFFLINE_REPO_DIR/build" +OFFLINE_AUTODETECT="$OFFLINE_REPO_DIR/built" +# `build-index.sh` writes to built/. Older tooling in this repository used +# build/, so accept that as a second candidate rather than silently building a +# medium without the package set. +OFFLINE_AUTODETECT_LEGACY="$OFFLINE_REPO_DIR/build" DEFAULT_DIST="$REPO_ROOT/dist" MEDIA_PREFIX="/blueforce-provisioning" FIRSTBOOT_PATH="$MEDIA_PREFIX/firstboot" @@ -60,7 +64,7 @@ Options: --version VERSION Field OS version (default: provisioning/iso/field-os-version) --offline-repo DIR Built offline APT repository to embed (Packages, Packages.gz, SHA256SUMS, packages.lock.tsv). Default: auto-detect - provisioning/offline-repo/build, else build without it. + provisioning/offline-repo/built, else build without it. --require-offline-repo Fail closed when no built offline repository is available --volid LABEL ISO volume label (default: the upstream label, preserved so the live-media discovery path stays untouched; recorded in the manifest) @@ -225,13 +229,16 @@ resolve_offline_repo() { [[ -d "$OFFLINE_REPO" ]] || die "Offline repository directory not found: $OFFLINE_REPO" elif [[ -z "$OFFLINE_REPO" && -d "$OFFLINE_AUTODETECT" ]]; then OFFLINE_REPO="$OFFLINE_AUTODETECT" + elif [[ -z "$OFFLINE_REPO" && -d "$OFFLINE_AUTODETECT_LEGACY" ]]; then + OFFLINE_REPO="$OFFLINE_AUTODETECT_LEGACY" + warn "Using the legacy offline repository path ${OFFLINE_AUTODETECT_LEGACY#"$REPO_ROOT"/}; build-index.sh writes to built/ instead." else OFFLINE_REPO="" fi if [[ -z "$OFFLINE_REPO" ]]; then if [[ "$REQUIRE_OFFLINE" -eq 1 ]]; then - die "No built offline APT repository found (looked at ${OFFLINE_AUTODETECT#"$REPO_ROOT"/} and --offline-repo). Build one with provisioning/offline-repo/build-offline-repo.sh, then retry." + die "No built offline APT repository found (looked at ${OFFLINE_AUTODETECT#"$REPO_ROOT"/} and --offline-repo). Build one with provisioning/offline-repo/build-index.sh, then retry." fi OFFLINE_MODE="not-included" warn "No built offline APT repository is embedded: the medium ships the offline tooling and manifests only." diff --git a/provisioning/offline-repo/README.md b/provisioning/offline-repo/README.md index ed4a059..aa357dc 100644 --- a/provisioning/offline-repo/README.md +++ b/provisioning/offline-repo/README.md @@ -15,7 +15,7 @@ paketlerini ve bunların APT indeksini **bu git deposunun içinde** taşır. | Rol | Kimdir | Ne yapar | |---|---|---| | Repo sorumlusu | bu depoyu yöneten kişi | Ubuntu 26.04 makinesinde paketleri toplar, doğrular, indeksi üretir, commit eder | -| Kuran kişi | sahada cihazı kuran teknisyen | ISO/seed ile kurar, `blueforce-install.sh --offline` çalıştırır; paket aramaz, indirmez | +| Kuran kişi | sahada cihazı kuran teknisyen | ISO/seed ile kurar, `blueforce-install.sh --dealer-id ` çalıştırır (kurucu yerel depoyu kendisi bulur); paket aramaz, depoyu göstermek veya indirmek zorunda değildir | ## Dosya haritası @@ -231,47 +231,131 @@ cd built && sha256sum -c SHA256SUMS # OK görmelisiniz * Saha cihazında internet yok (ya da güvenilmez). Bu yüzden kurulumun ihtiyaç duyduğu her şey **medyanın ve git deposunun içinde** taşınır. -* Kurucu `--offline` ile çalıştığında tek kaynak şudur: - `/opt/blueforce/offline-repo` dizinine konan yerel depo - (`deb [trusted=yes] file:/opt/blueforce/offline-repo ./`). Uzak APT kaynağı, - anahtar indirme, `curl`, `wget`, `apt download` kullanılmaz. -* Bu dizin (git deposundaki `built/`) ISO ile hedefe taşınır ve kurucu şu - dosyaları arar ve doğrular: `Packages`, `Packages.gz`, `packages.lock.tsv`, - `SHA256SUMS` ve `pool/` içinde manifestlerdeki pinlere karşılık gelen `.deb` - dosyaları. +* Kurucu paket setini **kendi kendine bulur**; `--offline` bayrağı artık + gerekmez (geriye uyumluluk için duruyor ve yalnızca yerel depoyu zorlar). + Arama sırası — ilk eksiksiz aday kazanır: + + | Sıra | Yer | Ne zaman kullanılır | + |---|---|---| + | 1 | `BF_OFFLINE_REPO` ortam değişkeni | Repo sorumlusu bilinçli olarak başka bir dizin verdiyse | + | 2 | `/provisioning/offline-repo/built` | Normal durum: git checkout'un içindeki hazır set | + | 3 | `/opt/blueforce/offline-repo` | Paket seti cihaza ISO/medya ile kopyalanmışsa | + +* Kurucu yerel depo dışında hiçbir kaynak kullanmaz: uzak APT kaynağı, anahtar + indirme, `curl`, `wget`, `apt download` çağrılmaz. Cihazdaki tek APT kaynağı + `deb [trusted=yes] file: ./` satırıdır. İnternet kurulum için gerekmez. +* Kurucu şu dosyaları arar ve doğrular: `Packages`, `Packages.gz`, + `packages.lock.tsv`, `SHA256SUMS` ve `pool/` içinde manifestlerdeki pinlere + karşılık gelen `.deb` dosyaları. * Kurucu kurulum sonunda cihazı `PROVISIONED_OFFLINE` durumuna getirir. Cihaz, bir kerelik enrollment ve merkezi kanal doğrulaması yapılmadan `READY` olmaz. * Sonuç: kuran kişinin yaptığı tek şey `git`/ISO'dan gelen dosyaları yerine - koymak ve kurucuyu çalıştırmaktır. Hangi sürümün kurulduğu - `packages.lock.tsv` ve `repo-manifest.yaml` ile kanıtlanır. + koymak ve kurucuyu çalıştırmaktır. **Hiçbir şey indirmez, depoyu elle + göstermek zorunda değildir.** Hangi sürümün kurulduğu `packages.lock.tsv` ve + `repo-manifest.yaml` ile kanıtlanır. -Kuran kişinin komutu: +Kuran kişinin komutu (bayrak gerekmez): ```bash -sudo ./scripts/install/blueforce-install.sh --offline --dealer-id <8 haneli numara> +sudo ./scripts/install/blueforce-install.sh --dealer-id <8 haneli numara> +``` + +Konsoldan kullanmak için: `sudo bf` (Python operatör konsolu; bash yedek yolu +`sudo bf-menu`). + +Depo bulunduğunda kurucu şu duyuruyu yazar: + +```text +Yerel paket deposu bulundu: paket, + Depo : + Kaynak : + Kip : yerel kurulum. İnternet, paket indirme ve ek anahtar gerekmez. ``` --- -# 3. Eksik paket olursa ne olur? (`OFFLINE BLOCKED`) +# 3. Eksik paket ya da eksik depo olursa ne olur? -Cihazdaki kurucu, paket modüllerinden **önce** yerel depoyu doğrular. Bir şey -eksik ya da bozuksa kurulum durur ve ekrana `OFFLINE BLOCKED` ile başlayan bir -satır yazar. `OFFLINE BLOCKED` demek: "cihazda kurulum yapılmadı, depo -tamamlanmadı, sorumluya haber verin". +Cihazdaki kurucu, paket modüllerinden **önce** yerel depoyu arar ve doğrular. +Burada **birbirinden farklı iki durum** vardır; ikisi de kurulumu başlatmadan +durdurur ve sistemde hiçbir değişiklik bırakmaz, ama mesajları ve anlamları +farklıdır. + +## 3.1 Depo hiç yok (kurucu bulamadı) + +Aranan üç yer de yoksa — ya da var ama dizin `Packages`, `Packages.gz`, +`packages.lock.tsv`, `SHA256SUMS` dosyalarının hepsini taşımıyorsa — kurucu +Türkçe yazar ve `exit 1` verir: + +```text +HATA: Yerel paket deposu yok. Repo sorumlusuna başvurun: provisioning/offline-repo/README.md + +Kurulum paketleri yalnız yerel depodan kurar; bu makinede internetten paket +alınmaz. Depo olmadığı için paket adımları çalışamaz. + +Aranan yerler: + - depodaki hazır paket seti — yok: /provisioning/offline-repo/built + - cihazdaki kurulu paket deposu — yok: /opt/blueforce/offline-repo +... +ÇIKIŞ NEDENİ: yerel paket deposu bulunamadı. +``` + +Var olan ama eksiksiz olmayan bir dizin, "Aranan yerler" listesinde şu satırla +görünür (yine de kurulum başlamaz): + +```text + - depodaki hazır paket seti — eksik/bozuk: (Packages, Packages.gz, packages.lock.tsv ve SHA256SUMS dosyalarının hepsi gerekli) +``` + +Anlamı: **kurucu paket setini bulamadı.** Sistem değişmedi; yapılacak şey depoyu +tam olarak getirmektir (git'ten veya repo sorumlusunun verdiği kopyayı +`/opt/blueforce/offline-repo` altına koyarak) ve komutu tekrar çalıştırmaktır. + +## 3.2 Depo bulundu ama doğrulanamadı (`OFFLINE BLOCKED`) + +Depo bulunduysa (dört indeks/kilit dosyası da var) kurucu onu baştan sona +doğrular. Doğrulama katmanı geçmezse kurulum durur ve ekrana **`OFFLINE BLOCKED`** +ile başlayan bir satır yazar. `OFFLINE BLOCKED` demek: "depo bulundu ama +güvenilir değil; cihazda kurulum yapılmadı, sorumluya haber verin". + +```text +OFFLINE BLOCKED: + Depo : + Ne yapmalı : paket setini yeniden üretip git ile getirin (provisioning/offline-repo/README.md) + ÇIKIŞ NEDENİ: yerel paket deposu doğrulanamadı; kurulum başlamadı ve + sistemde hiçbir değişiklik yapılmadı. +``` + +Doğrulama katmanının **gerçek** sebepleri (mesajdaki ``): | Ekranda ne yazar (kısaltılmış) | Ne anlama gelir | Sorumlu tarafında çözüm | |---|---|---| -| `BF_OFFLINE_REPO must be an existing absolute local directory` | Depo dizini hiç yok: medya ya da kopyalama eksik | `built/` içeriğini `/opt/blueforce/offline-repo` altına koyun | -| `local APT index, lock, or checksums are missing; ISO bundle is incomplete` | `Packages`, `Packages.gz`, `packages.lock.tsv` veya `SHA256SUMS` yok. Genelde indeks üretilmeden commit edilmiştir | `./build-index.sh` çalıştırıp `built/` dizinini commit edin | -| `local APT repository checksum validation failed` | Dosyalar elle değişmiş ya da kopyalama bozulmuş (`sha256sum -c SHA256SUMS` hatası) | Depoyu git'ten yeniden alın; indeksi yeniden üretin | -| `package lock is empty or invalid` | `packages.lock.tsv` başlığı/kolonları bozuk ya da dosya boş | `./build-index.sh` ile yeniden üretin, elle düzenlemeyin | -| `pinned package absent from bundle: ` | Manifestteki sürüm depoda yok: pin ile paket eşleşmiyor | `add-packages.sh` ile doğru sürümü ekleyip pini güncelleyin | +| `BF_OFFLINE_REPO mutlak bir yerel dizin olmalıdır.` | `BF_OFFLINE_REPO` ile verilen yol mutlak bir dizin değil | Doğru yolu verin ya da değişkeni kaldırın; varsayılan keşif kullanılsın | +| `Yerel APT indeksi, kilit dosyası ya da checksum kaydı eksik; paket seti tamamlanmamış.` | `Packages`, `Packages.gz`, `packages.lock.tsv` veya `SHA256SUMS` boş/eksik | `./build-index.sh` çalıştırıp `built/` dizinini commit edin | +| `Yerel APT deposunun checksum doğrulaması başarısız.` | Dosyalar elle değişmiş ya da kopyalama bozulmuş (`sha256sum -c SHA256SUMS` hatası) | Depoyu git'ten yeniden alın; indeksi yeniden üretin | +| `Paket kilidi boş ya da biçimi bozuk.` | `packages.lock.tsv` başlığı/kolonları bozuk ya da dosya boş | `./build-index.sh` ile yeniden üretin, elle düzenlemeyin | +| `Kilitte yazılı paket depoda yok: ().` | Kilit dosyasındaki bir satırın `.deb` dosyası `pool/` içinde yok | `add-packages.sh` ile paketi ekleyip indeksi yeniden üretin | +| `Gerekli pin manifestosu boş: .` | `manifests/*.txt` dosyalarından biri boş | Pini doldurun; `requirements.tsv` ile birlikte güncelleyin | +| `Gerekli pin manifestosunda paket pini yok: .` | Manifestte yalnız yorum satırı var, paket pini yok | Manifeste `paket=sürüm` satırlarını yazın | +| `Geçersiz paket pini: içinde ''.` | Pin biçimi bozuk ya da `placeholder`/`REPLACE` içeriyor | Satırı `paket=sürüm` biçimine getirin | +| `Pinlenen paket depoda yok: =.` | Manifestteki sürüm depoda yok: pin ile paket eşleşmiyor | `add-packages.sh` ile doğru sürümü ekleyip pini güncelleyin | Yani "eksik paket" sahada değil, **commit öncesinde** çözülür: `./build-index.sh` eksikleri listeler ve yazmadan durur. Sahada `OFFLINE BLOCKED` -görürseniz ISO, bilgi eksik bir depoyla üretilmiş demektir; çözüm depoyu düzeltip -yeni ISO üretmektir. +görürseniz depo, bilgi eksik ya da bozuk bir hâlde yayınlanmış demektir; çözüm +depoyu düzeltip yeni bir sürüm yayınlamaktır. + +## 3.3 Kuran kişi ne yapar? + +Hiçbir şey indirmez: ne `.deb`, ne anahtar, ne APT listesi. Paketler zaten +git deposunun içinde taşınır ve kurucu yerel depoyu kendisi bulur. Depo yoksa +veya `OFFLINE BLOCKED` görürse yapılacak tek şey **ekrandaki mesajı repo +sorumlusuna iletmektir**; düzeltme sorumlunun işidir. Kurulum yapan kişi yalnız +komutu tekrar çalıştırır: + +```bash +sudo ./scripts/install/blueforce-install.sh --dealer-id <8 haneli numara> +``` --- diff --git a/scripts/install/README.md b/scripts/install/README.md index aea6deb..c6bf5e5 100644 --- a/scripts/install/README.md +++ b/scripts/install/README.md @@ -1,27 +1,174 @@ -# Blueforce installer (`scripts/install/`) +# Blueforce kurulumu (`scripts/install/`) -Single entry point: `sudo ./blueforce-install.sh --dealer-id <8 digits>`. +Bu klasör cihazı kuran betiği içerir. Kurulumu yapan kişinin bilmesi gereken +her şey bu sayfada. -- Orchestrator: `blueforce-install.sh` (dealer-id gate `^[0-9]{8}$`, - hostname `bf-` + device `BF-`, ordered module runs, `--resume`, - results to `/var/log/blueforce-install.log` + `/var/lib/blueforce/install-state`). -- Modules: `installer/modules/01-*.sh` … `18-*.sh`. Every module is idempotent - and supports `--check` (read-only audit). Exit `0` = OK, `3` = SKIP. -- Required remote-channel preconditions: set per-device `WG_ADDRESS`, `WG_ENDPOINT`, - and `WG_PEER_PUBKEY`; WireGuard readiness requires a peer handshake no older than - `BF_WG_HANDSHAKE_MAX_AGE` seconds (default `180`) unless `REQUIRE_WIREGUARD=false`. - Set `RUSTDESK_SERVER` to a real self-hosted endpoint and provide the pinned local - `RUSTDESK_DEB`; placeholders are rejected. -- Docker published ports default to deny. Add only reviewed `tcp PORT` or `udp PORT` - entries to `/etc/blueforce/docker-published-port-allowlist.conf`; the enabled - `blueforce-docker-firewall.service` reapplies that policy after Docker starts. -- Exit codes: `0` READY · `1` module failure · `2` argument/format error. +--- -Module map: 01-precheck · 02-system · 03-user · 04-hostname · 05-network · -06-wireguard · 07-ssh · 08-rdp · 09-rustdesk · 10-docker · 11-meg · -12-monitoring · 13-firewall · 14-update-policy · 15-logrotate · 16-gui · -17-healthcheck · 18-final-check. +## 1. Kurulum yapan kişi ne yapar? -NOTE on AnyDesk: there is deliberately no AnyDesk module. Remote access is -covered by SSH-over-WireGuard, xRDP and RustDesk. AnyDesk stays a manual, -per-device exception outside this installer. +**Tek komut:** + +```bash +sudo ./scripts/install/blueforce-install.sh --dealer-id 12345678 +``` + +- `--dealer-id` tek zorunlu bilgidir: 8 haneli bayi numarası. +- Betik numaradan ana makine adını (`bf-12345678`) ve cihaz kimliğini + (`BF-12345678`) kendisi üretir. +- Kurulum sırasında başka hiçbir soru sorulmaz. Onay istemeyen (fabrika/otomatik) + senaryoda sonuna `--yes` ekleyin. +- Kurulum bittiğinde cihaz yerinde kurulmuş olur ve `PROVISIONED_OFFLINE` + durumuna geçer. Cihazın **READY** sayılması için merkeze kayıt (enrollment) + gerekir; bu ayrı bir adımdır, kuruluma dahil değildir. + +Paket aramaz, paket indirmez, apt kaynağı eklemez, anahtar getirmez. Bunların +hepsi zaten hazırdır. + +--- + +## 2. Paketler nereden gelir? + +Paketler **git deposunun içinde** taşınır: + +```text +provisioning/offline-repo/built/ hazır paket seti (pool/, Packages, SHA256SUMS, packages.lock.tsv) +``` + +Bunları **repo sorumlusu** hazırlar ve commit eder; kurulumu yapan kişi sadece +depoyu çeker. Paket setinin nasıl üretildiği, hangi paketlerin neden +gerektiği ve sorun giderme adımları: + +```text +provisioning/offline-repo/README.md +``` + +Kurucu paket setini kendi kendine bulur. Arama sırası: + +| Sıra | Yer | Ne zaman kullanılır | +|---|---|---| +| 1 | `BF_OFFLINE_REPO` ortam değişkeni | Repo sorumlusu farklı bir dizin verdiyse (nadir) | +| 2 | `provisioning/offline-repo/built` | Normal durum: kurucu betiğin bulunduğu repo | +| 3 | `/opt/blueforce/offline-repo` | Paket seti cihaza ISO/medya ile kopyalanmışsa | + +Bulunan depo kurulumdan önce baştan sona doğrulanır: dosya listesi, +checksum (`SHA256SUMS`) ve pinlenen her paketin depoda gerçekten durması. +Doğrulama geçmezse kurulum **hiç başlamaz**. + +--- + +## 3. İnternet gerekmez — neden? + +- Sahada internet yok veya güvenilmez; kurulumun ihtiyaç duyduğu her paket + yanında taşınır ve cihazdaki tek kaynak yerel depodur. +- Kurulum çalışırken Apt kaynakları yalnızca bu yerel depoyu gösterir. Dış + adreslere, DNS çözümlemesine veya indirmeye ihtiyaç duyulmaz. +- Bu yüzden **internet erişimi kontrolü kurulumu durdurmaz**: `01-precheck` + modülü interneti sadece bilgi olarak yazar. `05-network` modülü de bağlantı + yokken geçer (yerel ağ, internet ve merkez bağlantısı ayrı ayrı raporlanır; + hiçbiri kurulum için şart değildir). +- Merkez bağlantısı (WireGuard, izleme, kayıt) kurulumdan sonra, **enrollment + aşamasında** doğrulanır. + +Yalnızca geliştirme/test makinesi için `--online` vardır: paketleri internetten +çeker. **Üretimde kullanmayın** — sahada kurulum yerel depodan yapılır. + +--- + +## 4. Bir şey ters giderse + +### "Yerel paket deposu yok" hatası + +```text +HATA: Yerel paket deposu yok. Repo sorumlusuna başvurun: provisioning/offline-repo/README.md +``` + +Anlamı: cihazda kullanılacak paket seti yok. Kurulum başlamadı, sistemde +hiçbir değişiklik yapılmadı. Yapılacaklar: + +1. Depoyu tam olarak çekin (`git pull`) veya repo sorumlusunun verdiği kopyayı + `/opt/blueforce/offline-repo` altına koyun. +2. Komutu yeniden çalıştırın. Aynı numarayla devam edebilirsiniz. + +Ekranda aranan yerlerin listesi yazar; o listeyi repo sorumlusuna iletmek +yeterlidir. + +### `OFFLINE BLOCKED` mesajları + +Depo bulundu ama eksik ya da bozuk demektir (checksum tutmuyor, pinlenen paket +depoda yok, kilit/indeks dosyası boş...). Kurulum yine başlamaz ve sistem +değişmez. Mesajın altındaki "Ne yapmalı" satırı depoyu nasıl düzelteceğinizi +söyler; ayrıntılı tablo `provisioning/offline-repo/README.md` içindedir. +Sahada çözülmez — depoyu düzeltip yeniden getirmek gerekir. + +### Kurulum kesildi, devam etmek istiyorum + +```bash +sudo ./scripts/install/blueforce-install.sh --dealer-id 12345678 --resume +``` + +`--resume` daha önce tamamlanmış adımları atlar. Bütün adımlar tekrar +çalıştırılabilir (idempotent); bir adımı iki kez çalıştırmak zarar vermez. + +### Kurulum yapıldı mı, kontrol etmek istiyorum + +```bash +sudo ./scripts/install/blueforce-install.sh --dealer-id 12345678 --check +``` + +`--check` hiçbir şeyi değiştirmez (log, durum dosyası, dizin oluşturmaz); +yalnızca rapor verir. Denetim de aynı paket sözleşmesini doğruladığı için +depo yine gerekir. + +### Kayıtlar nerede? + +| Ne | Yer | +|---|---| +| Kurulum günlüğü | `/var/log/blueforce-install.log` | +| Adım adım durum | `/var/lib/blueforce/install-state` | +| Cihaz durumu | `/var/lib/blueforce/state.json` | + +--- + +## 5. Seçenekler (normalde gerekmez) + +| Seçenek | Ne yapar | +|---|---| +| `--dealer-id NUMARA` | Zorunlu. 8 haneli bayi numarası. | +| `--yes`, `-y` | Onay sormadan başla. | +| `--check` | Salt okunur denetim. | +| `--from NN` | `NN` numaralı adımdan başla (örn. `--from 06`). | +| `--only AD` | Yalnız tek adımı çalıştır (örn. `--only 05-network`). | +| `--resume` | Daha önce tamamlanan adımları atla. | +| `--help`, `-h` | Yardım metni. | +| `--offline` | Yerel depoyu kullanmayı zorlar. Artık gerekmez; varsayılan davranış zaten budur (eski komutlar bozulmasın diye duruyor). | +| `--online` | Yalnız geliştirme/test: paketleri internetten çeker. Üretimde kullanılmaz. | + +Kurulum sonucu: `0` başarılı · `1` kurulum durdu (depo ya da adım hatası) · +`2` komut/parametre hatası. + +--- + +## 6. Kurulum adımları (modül haritası) + +Her adım tekrar çalıştırılabilir ve `--check` destekler. + +`01-precheck` · `02-system` · `03-user` · `04-hostname` · `05-network` · +`06-wireguard` · `07-ssh` · `08-rdp` · `09-rustdesk` · `10-docker` · `11-meg` · +`12-monitoring` · `13-firewall` · `14-update-policy` · `15-logrotate` · +`16-gui` · `17-healthcheck` · `18-final-check` + +Uzak erişim için her cihaza özel değerler gerekir: `WG_ADDRESS`, `WG_ENDPOINT`, +`WG_PEER_PUBKEY`, `RUSTDESK_SERVER` ve yerel `RUSTDESK_DEB`. Yer tutucu +değerler kabul edilmez; WireGuard erişimi `BF_WG_HANDSHAKE_MAX_AGE` saniyeden +(öntanımlı `180`) daha yeni bir eş el sıkışması ister (`REQUIRE_WIREGUARD=false` +ile kapatılabilir). + +Docker'ın dışa açtığı portlar öntanımlı olarak kapalıdır. Yalnız incelenmiş +`tcp PORT` / `udp PORT` satırları +`/etc/blueforce/docker-published-port-allowlist.conf` dosyasına eklenir; +`blueforce-docker-firewall.service` bu politikayı Docker her başladığında +yeniden uygular. + +Not: AnyDesk bilinçli olarak yoktur. Uzak erişim SSH-over-WireGuard, xRDP ve +RustDesk ile sağlanır; AnyDesk elle yapılan cihaz başına bir istisnadır. diff --git a/scripts/install/blueforce-install.sh b/scripts/install/blueforce-install.sh index 63c06c4..ae710dc 100755 --- a/scripts/install/blueforce-install.sh +++ b/scripts/install/blueforce-install.sh @@ -265,8 +265,11 @@ fi export DEALER_ID BF_HOSTNAME="bf-${DEALER_ID}" BF_DEVICE="BF-${DEALER_ID}" STATE_DIR BF_OFFLINE BF_OFFLINE_REPO="${REPO_DIR:-}" if [[ "$CHECK_MODE" -eq 0 && "$ASSUME_YES" -eq 0 ]]; then - read -r -p "Kurulum $BF_DEVICE olarak başlatılsın mı? [e/H] " answer - [[ "$answer" =~ ^[Ee]$ ]] || { echo 'Kurulum iptal edildi.'; exit 2; } + if ! read -r -p "Kurulum $BF_DEVICE olarak başlatılsın mı? [e/H] " answer; then + printf '\nKurulum iptal edildi: onay alınamadı (terminal yok). Otomatik kurulum için --yes ekleyin.\n' >&2 + exit 2 + fi + [[ "$answer" =~ ^[Ee]$ ]] || { printf 'Kurulum iptal edildi.\n'; exit 2; } fi RUN=(); for m in "${MODULES[@]}"; do diff --git a/scripts/install/installer/modules/01-precheck.sh b/scripts/install/installer/modules/01-precheck.sh index 39c6155..2b88227 100755 --- a/scripts/install/installer/modules/01-precheck.sh +++ b/scripts/install/installer/modules/01-precheck.sh @@ -1,7 +1,17 @@ #!/usr/bin/env bash -# Pre-flight checks: root, Ubuntu 26.04, RAM/disk, internet. +# Pre-flight checks: root, Ubuntu release, RAM and disk. +# +# Network is informational here and never a gate: an offline install takes its +# packages from the local bundle, so it needs neither the Internet nor the +# central endpoint. Three things are reported separately for the operator: +# 1. local network link — no intent, not used by the install, +# 2. Internet — NOT required for an offline install (no warning), +# 3. central connection — not needed during install; that is the enrollment +# stage's job. +# This module therefore never fails because a network probe failed. +# # Idempotent: safe to re-run. Supports --check for read-only verification. -# Exit codes: 0 = OK, 3 = SKIP (optional step, nothing to do). +# Exit codes: 0 = OK, 3 = SKIP (optional step, nothing to do), 1 = real failure. set -euo pipefail MODULE="01-precheck" @@ -23,6 +33,25 @@ MIN_RAM_MB=2048 MIN_DISK_MB=20480 fail() { log "FAIL: $1"; echo "FAIL: $1" >&2; exit 1; } +info() { log "BİLGİ: $1"; } + +# Read-only network report. Nothing here can fail the install. +report_network() { + if ip -o link show up 2>/dev/null | grep -qv ' lo:'; then + info "yerel ağ: bağlantı var (kurulum için gerekmiyor, kullanılmıyor)" + else + info "yerel ağ: bağlantı görünmüyor (kurulum için gerekmiyor, kullanılmıyor)" + fi + if [[ "${BF_OFFLINE:-0}" == 1 ]]; then + # Offline install: no probe at all, and no warning either. + info "internet: kurulum yerel paket deposundan yapılır; internet GEREKMEZ" + elif getent hosts archive.ubuntu.com >/dev/null 2>&1; then + info "internet: erişilebilir (geliştirme/test kipi)" + else + info "internet: erişilemiyor (bu kurulum için gerekmez)" + fi + info "merkez bağlantısı: kurulum sırasında gerekmez; enrollment aşamasında doğrulanır" +} run_checks() { [[ "$(id -u)" -eq 0 ]] || fail "must run as root" @@ -38,10 +67,8 @@ run_checks() { [[ "$ram_mb" -ge "$MIN_RAM_MB" ]] || fail "RAM too low: ${ram_mb}MB (need >= ${MIN_RAM_MB}MB)" disk_mb=$(df -m / --output=avail | tail -1 | tr -d ' ') [[ "$disk_mb" -ge "$MIN_DISK_MB" ]] || fail "disk too low: ${disk_mb}MB free on / (need >= ${MIN_DISK_MB}MB)" - if [[ "${BF_OFFLINE:-0}" != 1 ]] && ! getent hosts archive.ubuntu.com >/dev/null 2>&1 && ! ping -c1 -W5 1.1.1.1 >/dev/null 2>&1; then - fail "no internet connectivity (DNS and ping both failed)" - fi - log "OK: precheck passed (Ubuntu ${VERSION_ID}, RAM ${ram_mb}MB, disk ${disk_mb}MB free; offline=${BF_OFFLINE:-0})" + report_network + log "OK: ön denetim geçti (Ubuntu ${VERSION_ID}, RAM ${ram_mb}MB, disk ${disk_mb}MB boş; yerel kurulum=$([[ "${BF_OFFLINE:-0}" == 1 ]] && echo evet || echo hayır))" } run_checks diff --git a/scripts/install/installer/modules/05-network.sh b/scripts/install/installer/modules/05-network.sh index 71da663..cd22002 100755 --- a/scripts/install/installer/modules/05-network.sh +++ b/scripts/install/installer/modules/05-network.sh @@ -1,16 +1,47 @@ #!/usr/bin/env bash -# Network gates distinguish local link, Internet, and central enrollment reachability. +# Network report for the field device. It separates three things that used to be +# one gate: +# 1. local network link — informational; the install does not use it, +# 2. Internet — NOT required: packages come from the local bundle, +# so external name resolution is not mandatory and a +# failing lookup must never stop the run, +# 3. central connection — not needed during install; enrollment checks it. +# +# The module therefore always exits 0: no network condition can fail an install. set -euo pipefail LOG_FILE="${LOG_FILE:-/var/log/blueforce-install.log}"; CHECK_MODE=0 [[ "${1:-}" == --check ]] && CHECK_MODE=1 OFFLINE="${BF_OFFLINE:-0}"; ENDPOINT="${BF_ENROLLMENT_ENDPOINT:-}" log() { echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) [05-network] $1" | tee -a "$LOG_FILE"; } local_link() { ip -o link show up 2>/dev/null | grep -qv ' lo:'; } -internet() { getent hosts archive.ubuntu.com >/dev/null 2>&1 && (ping -c1 -W3 1.1.1.1 >/dev/null 2>&1 || curl --connect-timeout 3 -fsSI https://archive.ubuntu.com >/dev/null 2>&1); } +internet() { ping -c1 -W3 1.1.1.1 >/dev/null 2>&1 || getent hosts archive.ubuntu.com >/dev/null 2>&1; } central() { [[ "$ENDPOINT" =~ ^https://[^[:space:]/]+ ]] && curl --connect-timeout 3 -fsSI "$ENDPOINT" >/dev/null 2>&1; } -local_link || { log 'FAIL: no local network link'; exit 1; } -log 'OK: local link present' -if [[ "$OFFLINE" == 1 ]]; then log 'OK: offline mode defers Internet and central endpoint checks'; exit 0; fi -internet || { log 'FAIL: Internet reachability unavailable'; exit 1; } -log 'OK: Internet reachable' -if [[ -n "$ENDPOINT" ]]; then central && log 'OK: central enrollment endpoint reachable' || log 'WARN: central enrollment endpoint unavailable (enrollment remains pending)'; else log 'INFO: central enrollment endpoint not configured'; fi + +if local_link; then + log 'BİLGİ: yerel ağ bağlantısı var (kurulum için gerekmiyor)' +else + log 'BİLGİ: yerel ağ bağlantısı görünmüyor (kurulum için gerekmiyor)' +fi + +if [[ "$OFFLINE" == 1 ]]; then + log 'BİLGİ: internet: kurulum yerel paket deposundan yapılır; internet GEREKMEZ' + log 'BİLGİ: Apt kaynakları yerel depoyu gösterir; dış DNS çözümlenemese de kurulum sürer' +else + if internet; then + log 'BİLGİ: internet erişilebilir (geliştirme/test kipi; üretimde gerekmez)' + else + log 'BİLGİ: internet erişilemiyor (bu kurulum için gerekmez)' + fi +fi + +if [[ -n "$ENDPOINT" ]]; then + if central; then + log 'BİLGİ: merkez kayıt uç noktası şu an erişilebilir (kurulumda yine de gerekmez)' + else + log 'BİLGİ: merkez kayıt uç noktasına şu an erişilemiyor; kurulum DURMAZ, enrollment aşamasında yeniden denenir' + fi +else + log 'BİLGİ: merkez kayıt uç noktası tanımlı değil; bağlantı enrollment aşamasında kurulur' +fi +log 'OK: ağ raporu tamam; kurulum internetsiz tamamlanabilir' +exit 0 diff --git a/tests/check-admin-static.sh b/tests/check-admin-static.sh index 9e690cc..233a971 100755 --- a/tests/check-admin-static.sh +++ b/tests/check-admin-static.sh @@ -386,7 +386,40 @@ expect_present 'bf-bootstrap cloned the repository' "$APPLY_ROOT/checkout/.git" expect_present 'bf-bootstrap linked a diagnostics tool' "$APPLY_ROOT/bin/bf-status" expect_contains 'bf-bootstrap prints the completion contract' "$WORK/apply1.out" 'Kurulum tamam. Başlamak için: sudo bf' expect_contains 'bf-bootstrap reports the repository in its summary' "$WORK/apply1.out" "$APPLY_ROOT/checkout" -expect_contains 'bf-bootstrap warns when the Python console is not in the clone' "$WORK/apply1.out" 'admin/bf is not present' +# The "console missing from the clone" branch is unreachable in a normal clone +# because admin/bf and admin/bf-menu are tracked. Exercise it deliberately, or +# the warning silently rots the day one of them is renamed. +# +# Note: deleting the file from a git working tree is NOT enough. Neither is +# stripping .git entirely -- bootstrap clones with `--branch main` and a plain +# directory has no such ref. The source has to be a real git repo in which the +# console is absent from the committed tree, so build one. +STRIPPED_REPO="$WORK/stripped-repo" +rm -rf "$STRIPPED_REPO" +cp -a "$REPO_ROOT" "$STRIPPED_REPO" +rm -rf "$STRIPPED_REPO/.git" +rm -f "$STRIPPED_REPO/admin/bf" +git -C "$STRIPPED_REPO" init -q -b main +git -C "$STRIPPED_REPO" -c user.name=check -c user.email=check@example.invalid \ + add -A +git -C "$STRIPPED_REPO" -c user.name=check -c user.email=check@example.invalid \ + commit -q -m 'stripped checkout without the Python console' +if git -C "$STRIPPED_REPO" cat-file -e 'HEAD:admin/bf' 2>/dev/null; then + fail 'the stripped source still tracks admin/bf; the scenario is invalid' +fi +set +e +PATH="$APPLY_PATH" \ +BF_SHIM_APT_LOG="$WORK/apt-stripped.log" \ +BF_BIN_DIR="$WORK/stripped-bin" \ +BF_INSTALL_DIR="$WORK/stripped-checkout" \ +BF_REPO_URL="$STRIPPED_REPO" \ +bash "$BOOTSTRAP" --yes < /dev/null > "$WORK/apply-stripped.out" 2>&1 +stripped_rc=$? +set -e +expect_rc 'bf-bootstrap succeeds even when the Python console is absent' 0 "$stripped_rc" +expect_contains 'bf-bootstrap warns when the Python console is not in the clone' "$WORK/apply-stripped.out" 'admin/bf is not present' +expect_contains 'bf-bootstrap still links the bash fallback' "$WORK/apply-stripped.out" 'bf-menu ready' +rm -rf "$STRIPPED_REPO" "$WORK/stripped-bin" "$WORK/stripped-checkout" linked1="$(find "$APPLY_ROOT/bin" -maxdepth 1 -type l 2>/dev/null | wc -l | tr -d ' ')" check if [[ "$linked1" -ge 10 ]]; then