Blueforce-Linux/admin/bf
emirhanmamak-blueforce 1387186b03 feat(bfos): Python operator console, Turkish UI, committable offline packages
Switches the operator path from bash-only to a Python console, keeps the bash
menu as a fallback, and makes the offline package set travel with the repository
so the person installing a device never downloads anything.

bfos/ (stdlib only, no textual/rich: those would need a download, which defeats
the offline goal):
- simple mode offers three choices (Kur / Durum / Çıkış); the detailed mode with
  all 21 fleet operations and the local installer is reachable from the menu or
  with --full, so a first-time operator is not buried in options
- gate parity with the bash console: scope read from the playbook file and
  refused on mismatch, production needs a typed token plus a separate approval,
  release-gated runs need their wave name typed, destructive runs need a second
  approval, "all" walks wave by wave and stops at the first failure
- Turkish throughout; audit log at /var/log/blueforce-console.log (600, falls
  back to the user state dir) with a single redaction choke point
- bfos/ui_gui.py adds an optional tkinter window over the same operations layer;
  headless and missing-tkinter cases explain themselves in Turkish

admin/bf-bootstrap.sh: links the Python console as `bf` (primary) and keeps
`bf-menu` (fallback), reports both, and recommends `sudo bf`.

Offline packages are committable now (this was the blocking contradiction):
- .gitignore ignored `Packages`, `Packages.gz` and `packages.lock.tsv` everywhere,
  so a built bundle could never be committed and the installer would always have
  been told to download. provisioning/offline-repo/built/ is now allowed through
  while scratch output stays untracked
- provisioning/offline-repo/{add-packages.sh,build-index.sh,repo-manifest.yaml}
  plus a Turkish step-by-step README for the repository owner
- the over-broad `*token*` ignore rule is narrowed to `*[-_.]token*` so ordinary
  filenames are not silently excluded while token files still are

Tests: run-all.sh now runs the Python suites too (previously it collected only
*.sh, so 212 Python assertions were silently skipped) and executes from the repo
root. 11/11 pass, exit 0.

Two test expectations were corrected rather than the code: a read-only
wave-scoped report legitimately asks for no gate token (the bash console never
did either), so that assertion now checks the command carries operation_wave and
operation_confirmed, and a new test asserts release-gated runs still require
their token. The bootstrap completion contract moved from `sudo bf-menu` to
`sudo bf`.
2026-09-16 16:15:27 +03:00

64 lines
2.3 KiB
Python
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
''''command -v python3 >/dev/null 2>&1 || { printf '%s\n' "HATA: python3 bulunamadı. bfos operatör konsolu için Python 3.8 veya üzeri gerekir." "" "Yedek yol (bash): sudo admin/bf-menu ya da kuruluysa: sudo bf-menu" >&2; exit 3; }; exec python3 "$0" "$@" # '''
"""bfos operator console — thin entry point (sh/Python polyglot).
The file is valid POSIX shell *and* valid Python:
* run as ``admin/bf`` (or as the ``bf`` symlink that
``admin/bf-bootstrap.sh`` creates), the shell line above checks that
``python3`` exists and, when it does not, prints a Turkish error and points at
the proven bash console (``admin/bf-menu``) — a device without Python is still
operational,
* everything after that line is the Python entry point: it puts the repository
root on ``sys.path`` and calls :func:`bfos.cli.main`. Nothing else lives here;
all logic is in the ``bfos`` package next to it.
Usage: sudo bfos [--full] [--dry-run] [--check] [--repo YOL] [--version] [--lang tr]
"""
import os
import sys
MIN_PYTHON = (3, 8)
if sys.version_info < MIN_PYTHON: # pragma: no cover - depends on the interpreter
sys.stderr.write(
"HATA: Python sürümü çok eski: {0}. bfos için Python {1}.{2}+ gerekir.\n".format(
sys.version.split()[0], MIN_PYTHON[0], MIN_PYTHON[1]
)
)
sys.stderr.write("Yedek yol (bash): sudo admin/bf-menu\n")
raise SystemExit(3)
def _repository_root():
"""First candidate directory that actually contains the bfos package."""
here = os.path.dirname(os.path.realpath(__file__))
candidates = [
os.environ.get("BF_REPO", ""),
os.path.dirname(here), # <repo>/admin/bf -> <repo>
here,
os.getcwd(),
]
for candidate in candidates:
if candidate and os.path.isfile(os.path.join(candidate, "bfos", "__init__.py")):
return candidate
return ""
ROOT = _repository_root()
if not ROOT:
sys.stderr.write(
"HATA: bfos paketi bulunamadı. Konsolu Blueforce deposunun içinden çalıştırın,\n"
"ya da --repo YOL ile depo yolunu belirtin.\n"
"Yedek yol (bash): sudo admin/bf-menu\n"
)
raise SystemExit(3)
if ROOT not in sys.path:
sys.path.insert(0, ROOT)
from bfos.cli import main # noqa: E402 (sys.path is prepared above)
if __name__ == "__main__":
raise SystemExit(main())