POSA_Copyrighter/docs/operations/offline-install.md
changukyu 2c607e0df6 docs: 2026-07-11 multi-agent review report, remediation checklist, offline extras
- Add the 2026-07-11 multi-agent project-review report and the remediation
  checklist (per-item status, with deferred items and their rationale).
- offline-install: document Ollama model and Playwright Chromium transfer, a
  hash-verified lock, --only-binary, and correct the egress note (image
  comparison fetches arbitrary SSRF-guarded public URLs, not only API hosts).
2026-07-11 16:08:04 +09:00

115 lines
4.1 KiB
Markdown

# Offline (air-gapped / 폐쇄망) install
The deployment target has **no internet**. All Python dependencies must be
carried across the air gap as pre-downloaded wheels. The build/staging machine
(which has internet) does the downloading; the target only installs.
## Prerequisites
- Same OS + CPU architecture + **Python 3.13** on build and target machines
(wheels are platform- and version-specific).
- The repository itself transferred to the target.
## 1. On the build machine (has internet)
```bash
# Runtime only (--only-binary keeps sdists out so nothing has to build on the
# offline target; also carry pip/setuptools/wheel themselves):
pip download --only-binary=:all: -r requirements.txt -d wheelhouse/
pip download --only-binary=:all: pip setuptools wheel -d wheelhouse/
# Or runtime + test tooling:
pip download --only-binary=:all: -r requirements-dev.txt -d wheelhouse/
```
This fills `wheelhouse/` with every wheel (including transitive deps).
### Hash-verified lock (recommended)
Pin the full transitive tree with hashes so a tampered/substituted wheel is
rejected at install time:
```bash
# On the build machine (pip-tools):
pip-compile --generate-hashes -o requirements.lock requirements.txt
```
Then install on the target with `--require-hashes` (step 3).
## 2. Transfer
Copy both the repository and the `wheelhouse/` directory to the target via the
approved air-gap transfer process (e.g. removable media).
## 3. On the target machine (no internet)
```bash
python -m venv .venv
. .venv/bin/activate # Windows: .venv\Scripts\activate
pip install --no-index --find-links wheelhouse/ -r requirements.txt
```
`--no-index` guarantees pip never reaches out to the internet; `--find-links`
points it at the local wheelhouse.
## 4. Verify offline
```bash
# Confirm no network access is attempted and imports resolve:
python -c "import numpy, cv2, PIL; print('deps ok')"
python -m pytest -q # if test deps were installed
```
## Optional: Ollama LLM model (evidence narration)
The LLM assistant is optional. If you want it on the air-gapped target, the
model weights must be carried across too — they are **not** part of the Python
wheelhouse:
```bash
# Build machine (has internet):
ollama pull qwen2.5:0.5b-instruct # or your pinned OLLAMA_MODEL
# Copy the model store across the air gap:
# default: ~/.ollama/models (or set OLLAMA_MODELS to a directory you transfer)
# Target machine (no internet):
export OLLAMA_MODELS=/path/to/transferred/models
ollama serve &
# Smoke test:
ollama run qwen2.5:0.5b-instruct "hello"
```
Set `OLLAMA_BASE_URL` / `OLLAMA_MODEL` in `.env`. Leave them unset to run without
the LLM (the `llm` provider then reports disabled).
## Optional: Playwright Chromium (E2E tests)
The operator-GUI E2E suite needs a Chromium binary, which Playwright normally
downloads. For the air gap, fetch it on the build machine and carry it:
```bash
# Build machine:
PLAYWRIGHT_BROWSERS_PATH=./pw-browsers playwright install chromium
# Transfer the pw-browsers/ directory to the target, then:
# Target machine:
export PLAYWRIGHT_BROWSERS_PATH=/path/to/pw-browsers
python -m pytest tests/operator_gui -q
```
## Notes
- The operator GUI (`web/operator-gui/`) is fully self-contained: all
scripts/styles are local and the Pretendard font is bundled
(`assets/fonts/PretendardVariable.woff2`). No CDN fetch at runtime.
- External **search** APIs (Google / Naver / Cloud Vision) are an allowed
runtime exception and require outbound access to those providers. They
are optional; missing credentials disable the provider (see the startup
provider-readiness log).
- **Broader egress:** beyond the API hosts, the image-comparison feature also
fetches arbitrary public result-page / image / stylesheet URLs returned by
those searches (SSRF-guarded: private/loopback/CGNAT/link-local ranges are
blocked). Restricting egress to the API hosts only disables image comparison
of external results; it does not break core review.
- `COPYRIGHTER_AUTH_TOKEN` should be set in `.env` for any multi-operator or
networked deployment so the data routes require a shared token.