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.
11 KiB
First boot — terminal wizard, kimlik koruması ve yarıda kalan kurulum
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. 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ı.
İlk boot, yalnız Subiquity'nin assisted storage onayıyla tamamlanan kurulumdan ve yeniden başlatmadan sonra çalışır.
Kimlik formatı ^[0-9]{8}$ (docs/02-DEVICE-NAMING-AND-INVENTORY.md) ve merkezi durumlar
(PROVISIONED_OFFLINE → ENROLLED → READY, docs/29-DEVICE-ENROLLMENT.md) bu adımın dışındadır:
firstboot yalnız offline provision'ı yapar, enrollment ve READY ayrı adımlardır.
1. Wizard (teknisyen ekranı)
Konsolda (TTY mevcut ve otomasyon istenmemiş) teknisyen şu ekranı görür:
# BLUEFORCE FIELD OS
8 Haneli Bayi Numarası:
> _
Davranış:
- Girdi
^[0-9]{8}$ile doğrulanır. Hatalı girdi kabul edilmez; hata satırı ve(deneme N/3)ile yeniden sorulur. Yalnız baştaki/sondaki boşluk kırpılır (yapıştırma artığı); değerin içinde boşluk veya rakam dışı karakter varsa geçersiz sayılır. - 3 hatalı denemeden sonra script net bir hatayla
exit 2verir ve hiçbir değişiklik yapmaz (BF_FIRSTBOOT_MAX_ATTEMPTSile deneme sayısı değiştirilebilir). - Doğru girdide onay ekranı gösterilir; onay
e/evet/y/yesile alınır:
Device ID (cihaz kimliği): BF-<dealer-id>
Hostname (makine adı) : bf-<dealer-id>
Kurulum bu kimlikle başlatılsın mı? [e/H]:
- Onay verilmezse kurulum başlamaz; deneme hakkı tükenirse
exit 2. readzaman aşımına uğrarsa (varsayılan 300 sn,BF_FIRSTBOOT_INPUT_TIMEOUT) script "no terminal input arrived" hatasıylaexit 2verir; konsolda kimse olmadığında sonsuza kadar bloklamaz.
TTY seçimi: stdin zaten bir terminal ise (systemd StandardInput=tty-force durumu) fd 0 kullanılır;
değilse /dev/tty açılır; o da açılamıyorsa wizard atlanır ve argüman/dosya yoluna düşülür.
2. Kimlik çözümleme sırası
| # | Kaynak | Mod |
|---|---|---|
| 1 | --dealer-id <8hane> |
non-interactive (otomasyon) |
| 2 | --dealer-id-file <yol> |
non-interactive (otomasyon) |
| 3 | --interactive |
wizard (TTY zorunlu) |
| 4 | BF_FIRSTBOOT_NONINTERACTIVE=1 |
non-interactive; seed dosyası (/etc/blueforce/dealer-id) okunur |
| 5 | Seed dosyası /etc/blueforce/dealer-id geçerliyse |
non-interactive; wizard atlanır (log satırı yazılır) |
| 6 | TTY mevcut | wizard |
| 7 | Hiçbiri | net hata + exit 2 (argüman/dosya önerilir) |
Otomasyon yolu (1, 2, 4) hiçbir soru sormaz: seed/USB ile kurulan cihazda teknisyen girdisi gerekmez.
- ve 2. maddeler açıkça verildiği için onay ekranı çıkmaz; bu bilinçli bir otomasyon kapısıdır.
Komut arayüzü
sudo bf-firstboot # wizard (konsol)
sudo bf-firstboot --dealer-id <8hane> # otomasyon
sudo bf-firstboot --dealer-id-file /path/to/dealer-id
sudo bf-firstboot --check --dealer-id <8hane> # salt-okunur denetim
sudo bf-firstboot --interactive # seed dosyası olsa bile wizard
BF_FIRSTBOOT_NONINTERACTIVE=1 sudo bf-firstboot # boot/otomasyon
Ortam değişkenleri: BF_FIRSTBOOT_MARKER (marker yolu), STATE_DIR (varsayılan /var/lib/blueforce),
BF_INSTALLER_PATH (kurucu yolu), BF_ADMIN_PUBLIC_KEY_FILE, BF_FIRSTBOOT_MAX_ATTEMPTS,
BF_FIRSTBOOT_INPUT_TIMEOUT, BF_FIRSTBOOT_TEST_MODE, BF_FIRSTBOOT_NONINTERACTIVE.
Çıkış kodları
| Kod | Anlam |
|---|---|
| 0 | Kurulum tamam (marker yazıldı) veya zaten tamamlanmış (idempotent) veya --check raporu |
| 1 | Offline önkoşul eksik (admin public key), root yok, kurucu yok, veya kurucu hata verdi |
| 2 | Girdi hatası: geçersiz bayi numarası, terminal yok, onay verilmedi, deneme tükendi |
3. İdempotentlik ve yarıda kalan kurulum
- Marker:
/var/lib/blueforce/firstboot-complete(mode600, içinde bayi numarası). - Marker varsa script hiçbir şey yapmaz: sormaz, yazmaz, kurucuyu çağırmaz,
exit 0. Wizard bu durumda asla açılmaz. - Marker varken farklı bir bayi numarası verilirse identity değişmez; yalnız uyarı yazılır ve admin prosedürüne (§4) işaret edilir. Sıradan kullanıcı yoluyla kimlik değiştirilemez.
- Marker yalnız kurucu başarıyla bittikten sonra yazılır (
set -euo pipefailsayesinde hata hâlinde yazılmaz). - Önceki koşu yarıda kaldıysa (
$STATE_DIR/install-statedolu) kurucu--resumeile çağrılır: kurucu--offline --dealer-id <no> --yes(+ gerekirse--resume) argümanlarıyla koşar. - Script kurucuyu
--offlineile çağırır. Bu bayrak artık zorunlu değildir: kurucu yerel paket deposunu kendisi bulur (BF_OFFLINE_REPO→<depo>/provisioning/offline-repo/built→/opt/blueforce/offline-repo). firstboot bayrağı geriye uyumluluk için verir; sonuç aynıdır: yerel depodan, internet olmadan kurulum vePROVISIONED_OFFLINEdurumu. --checkhiç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: <sebep> … Ç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. Yalnız root + açık operatör kapısı + yazılı onay + audit kaydı ile çalışır:
- Fiziksel konsolda root oturumu açılır ve operatör kapısı açıkça verilir:
BF_ALLOW_REIDENTITY=1. - Komut:
BF_ALLOW_REIDENTITY=1 sudo -E bf-firstboot --force-reidentity --dealer-id <yeni-no>. - Ekranda eski/yeni kimlik ve "dokuz merkezi sistem güncellenmeli" uyarısı gösterilir.
- Onay, yeni bayi numarasının yeniden yazılması ile alınır; eşleşmezse hiçbir değişiklik yapılmaz (
exit 2). - Kurucu yeni kimlikle koşar, eski marker
firstboot-complete.reidentified-<UTC>olarak saklanır, yeni marker yazılır. - Her adım
/var/log/blueforce-reidentity.log(mode600, UTC zaman +uid=) ve journal'a yazılır: kim, ne zaman, eski → yeni. Audit log yazılamıyorsa değişim reddedilir (fail-closed).
Kapılar: root değilse exit 1; BF_ALLOW_REIDENTITY=1 yoksa exit 1; TTY yoksa exit 2.
Değişimden sonra docs/02-DEVICE-NAMING-AND-INVENTORY.md §9'daki yeniden-numaralandırma adımları
(WireGuard peer, RustDesk/MeshCentral etiketi, Ansible inventory, monitoring etiketi) uygulanır.
5. Secret kuralları
BF_ADMIN_PUBLIC_KEY_FILEyalnız public SSH key içerebilir; root sahipliğinde ve grup/dünya tarafından yazılamaz olmalıdır (root:600veyaroot:640). Private key, inline anahtar veya boş/okunamayan dosyaOFFLINE BLOCKEDile reddedilir.- Bu kural değiştirilmedi: dosya
ssh-ed25519/ssh-rsa/ssh-ecdsa/sk-ssh-ed25519public key satırı ile başlamalı vePRIVATE KEYiçermemelidir. - 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-reidentityaudit 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.
- Kurucu, yerel paket deposunu kendisi bulur (
BF_OFFLINE_REPO→<depo>/provisioning/offline-repo/built→/opt/blueforce/offline-repo);--offlinebayrağı 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: <sebep>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_OFFLINEyazılır. Ayrıntı: §3 veprovisioning/offline-repo/README.md§3.
- depo hiç yoksa kurucu Türkçe
6. systemd unit ve boot'u kilitlememe
blueforce-firstboot.service:
ConditionPathExists=/etc/blueforce/admin-authorized-key.pub— zorunlu seed önkoşulu yoksa unit hiç başlamaz.ConditionPathExists=!/var/lib/blueforce/firstboot-complete— provision edilmiş cihazda atlanır (başarısız sayılmaz).StandardInput=tty-force+TTYPath=/dev/tty1— wizard sahada konsolda görünür.- TTY kurulamazsa (konsolsuz/headless sistem) systemd unit'i başarısız sayar, boot devam eder; script de TTY yoksa argüman/dosya yoluna düşer.
TimeoutStartSec=45min— konsolda kimse yoksa job sonsuza kadar açık kalmaz.Type=oneshot,RemainAfterExit=yes,WantedBy=multi-user.target— boot'ta bir kez çalışır.NoNewPrivileges=yes,PrivateTmp=yeskorunur.ProtectSystem=strictveProtectHome=yesbilinçli olarak yoktur: offline kurucu/etc,/usrve/home/blueforcealtına yazar.
Not: unit çıktısı konsol TTY'sine gider; aynı satırlar logger -t bf-firstboot ile journal'a da yazılır,
kurucu kendi logunu /var/log/blueforce-install.log içinde tutar.
7. Test
bash tests/test-firstboot-static.sh
Statik test, gerçek systemd/apt işlemi yapmadan şunları doğrular: bayi numarası regex'i, hatalı girdinin
reddi, wizard ekranı ve onay akışı (pty ile), marker idempotentliği, kimlik değişiminin kapalı olması,
public-key önkoşulu ve secret sızıntısı olmadığı, --check ve BF_FIRSTBOOT_TEST_MODE modlarının
mutasyonsuzluğu. Root gerektiren senaryolar unshare -r ile ayrı bir kullanıcı ad alanında koşar;
bu izin yoksa ilgili testler SKIP olarak raporlanır.