refactor(deploy): standardize enterprise environment file

This commit is contained in:
2026-08-25 15:30:10 +03:00
parent a2ede492b7
commit 4b9619e229
14 changed files with 57 additions and 152 deletions

View File

@@ -1,107 +0,0 @@
# #region env.enterprise-clean [C:2] [TYPE Module] [SEMANTICS env,docker,enterprise]
# @BRIEF Переменные окружения для docker-compose.enterprise-clean.yml.
# Сервисы собираются из исходников или загружаются из pre-built .tar.xz.
# PostgreSQL запускается в контейнере (сервис db).
# @LAYER Infrastructure
# @RELATION DEPENDS_ON -> [docker-compose.enterprise-clean.yml]
# #endregion env.enterprise-clean
# ======================================================================
# PostgreSQL (контейнер) — настройки встроенной БД
# ======================================================================
# Для использования внешнего PostgreSQL — переопределите POSTGRES_HOST
# и удалите/закомментируйте сервис db в docker-compose.enterprise-clean.yml.
POSTGRES_HOST=db
POSTGRES_PORT=5432
POSTGRES_DB=ss_tools
POSTGRES_USER=postgres
POSTGRES_PASSWORD=change-me
POSTGRES_HOST_PORT=5432
# Однократный универсальный reset старой Alembic-схемы перед baseline.
# Можно оставить true: после применения 0001_baseline последующие старты безопасно пропускают reset.
# Непустая БД без таблицы alembic_version никогда не удаляется автоматически.
RESET_DATABASE_SCHEMA=true
# ======================================================================
# Порты хоста
# ======================================================================
BACKEND_HOST_PORT=8001
FRONTEND_HOST_PORT=8000
FRONTEND_SSL_PORT=443
AGENT_HOST_PORT=7860
# ======================================================================
# Безопасность (ОБЯЗАТЕЛЬНО)
# ======================================================================
# JWT-ключ подписи токенов — единый для backend и agent.
# Сгенерировать: python3 -c "import secrets; print(secrets.token_urlsafe(32))"
AUTH_SECRET_KEY=change-me-to-a-random-secret-32-chars-min
# Fernet-ключ шифрования паролей подключений и API-ключей.
# Сгенерировать: python3 -c "import base64,os; print(base64.urlsafe_b64encode(os.urandom(32)).decode())"
ENCRYPTION_KEY=change-me-generate-a-fernet-key
# Сервисный токен для agent→backend вызовов.
# Сгенерировать: python3 -c "import secrets; print('svc-' + secrets.token_urlsafe(24))"
SERVICE_JWT=replace-with-random-service-secret
# ======================================================================
# Сертификаты (корпоративные)
# ======================================================================
CERTS_PATH=./certs
SSL_KEY_PASSPHRASE=
# ======================================================================
# LLM / AI провайдеры
# ======================================================================
OPENAI_API_KEY=
ANTHROPIC_API_KEY=
# Агент: LLM настройки (если не подтягиваются из FastAPI /api/agent/llm-config)
LLM_API_KEY=
LLM_BASE_URL=https://api.openai.com/v1
LLM_MODEL=gpt-4o
# ======================================================================
# Логирование
# ======================================================================
ENABLE_BELIEF_STATE_LOGGING=true
TASK_LOG_LEVEL=INFO
# ======================================================================
# Admin bootstrap (первый запуск)
# ======================================================================
INITIAL_ADMIN_CREATE=false
INITIAL_ADMIN_USERNAME=admin
INITIAL_ADMIN_PASSWORD=change-me
INITIAL_ADMIN_EMAIL=
# ======================================================================
# CORS / Безопасность деплоя
# ======================================================================
ALLOWED_ORIGINS=http://localhost:8000
FORCE_HTTPS=false
APP_TIMEZONE=Europe/Moscow
# ======================================================================
# Features
# ======================================================================
FEATURES__DATASET_REVIEW=true
FEATURES__HEALTH_MONITOR=true
# ======================================================================
# Агент (опциональные тонкие настройки)
# ======================================================================
# GRADIO_ALLOW_PORT_FALLBACK=true
# AGENT_ENABLE_LLM_TITLES=true
# AGENT_TITLE_GENERATION_TIMEOUT_S=0.25
# AGENT_PREFETCH_DASHBOARD_LIMIT=25
# AGENT_CONFIRM_TOOLS=false
# AGENT_INTERRUPT_BEFORE=
# ======================================================================
# ADFS SSO (опционально)
# ======================================================================
# ADFS_CLIENT_ID=
# ADFS_CLIENT_SECRET=
# ADFS_METADATA_URL=

View File

@@ -9,11 +9,17 @@ COMPOSE_PROJECT_NAME=ss-tools-current
# ── PostgreSQL (встроенный, docker compose db service) ────────────────── # ── PostgreSQL (встроенный, docker compose db service) ──────────────────
POSTGRES_IMAGE=postgres:16-alpine POSTGRES_IMAGE=postgres:16-alpine
POSTGRES_HOST=db
POSTGRES_PORT=5432
POSTGRES_HOST_PORT=5433 POSTGRES_HOST_PORT=5433
POSTGRES_DB=ss_tools POSTGRES_DB=ss_tools
POSTGRES_USER=postgres POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres POSTGRES_PASSWORD=postgres
# Universal one-shot migration reset. Legacy Alembic revisions are replaced
# by 0001_baseline; repeated starts preserve the baseline schema.
RESET_DATABASE_SCHEMA=false
# ── Application storage ───────────────────────────────────────────────── # ── Application storage ─────────────────────────────────────────────────
STORAGE_ROOT_PATH=/app/storage STORAGE_ROOT_PATH=/app/storage
@@ -63,6 +69,7 @@ GRADIO_SERVER_PORT=7860
# ── Сертификаты / фронтенд ───────────────────────────────────────────── # ── Сертификаты / фронтенд ─────────────────────────────────────────────
CERTS_PATH=./certs CERTS_PATH=./certs
SSL_KEY_PASSPHRASE= SSL_KEY_PASSPHRASE=
LLM_CA_CERT_URLS=
# ── Логирование ──────────────────────────────────────────────────────── # ── Логирование ────────────────────────────────────────────────────────
ENABLE_BELIEF_STATE_LOGGING=true ENABLE_BELIEF_STATE_LOGGING=true

View File

@@ -105,7 +105,7 @@ superset-tools/
|---|---|---| |---|---|---|
| **current** | `.env.current` | `docker compose --profile current up --build` | | **current** | `.env.current` | `docker compose --profile current up --build` |
| **master** | `.env.master` | `docker compose --profile master up --build` | | **master** | `.env.master` | `docker compose --profile master up --build` |
| **enterprise-clean** | `.env.enterprise-clean` | `docker compose --profile enterprise-clean up --build` | | **enterprise-clean** | `.env` | `docker compose -f docker-compose.enterprise-clean.yml up --build` |
| **e2e** | `.env.e2e` | `docker compose -f docker-compose.e2e.yml up --build` | | **e2e** | `.env.e2e` | `docker compose -f docker-compose.e2e.yml up --build` |
```bash ```bash
@@ -353,7 +353,7 @@ scripts/diag_container.py --target your-llm-provider.com:443 # Контейне
Разворот в корпоративной сети с очищенным дистрибутивом (без тестовых данных, запрет внешних источников, compliance-проверка): Разворот в корпоративной сети с очищенным дистрибутивом (без тестовых данных, запрет внешних источников, compliance-проверка):
```bash ```bash
cp .env.enterprise-clean.example .env cp .env.example .env
docker compose --profile enterprise-clean up --build docker compose --profile enterprise-clean up --build
``` ```

View File

@@ -15,6 +15,8 @@ def test_generated_enterprise_backend_requires_service_jwt() -> None:
assert "SERVICE_JWT: \\${SERVICE_JWT:?Set SERVICE_JWT in .env}" in backend_block assert "SERVICE_JWT: \\${SERVICE_JWT:?Set SERVICE_JWT in .env}" in backend_block
assert "RESET_DATABASE_SCHEMA: \\${RESET_DATABASE_SCHEMA:-true}" in backend_block assert "RESET_DATABASE_SCHEMA: \\${RESET_DATABASE_SCHEMA:-true}" in backend_block
assert '"env_template": ".env.example"' in text
assert '${DIST_ROOT}/.env.example' in text
def test_generated_light_compose_requires_all_runtime_secrets() -> None: def test_generated_light_compose_requires_all_runtime_secrets() -> None:

View File

@@ -75,7 +75,7 @@ setup_compose_profile() {
COMPOSE_FILE="docker-compose.yml" COMPOSE_FILE="docker-compose.yml"
;; ;;
enterprise-clean) enterprise-clean)
PROFILE_ENV_FILE="$SCRIPT_DIR/.env.enterprise-clean" PROFILE_ENV_FILE="$SCRIPT_DIR/.env"
PROJECT_NAME="superset-tools-enterprise" PROJECT_NAME="superset-tools-enterprise"
COMPOSE_FILE="docker-compose.enterprise-clean.yml" COMPOSE_FILE="docker-compose.enterprise-clean.yml"
;; ;;
@@ -567,7 +567,7 @@ postgres_image_id=${postgres_id}
postgres_repo_digest=$(get_repo_digest "${postgres_tag}") postgres_repo_digest=$(get_repo_digest "${postgres_tag}")
postgres_archive=superset-tools-postgres.${tag}${suffix}.tar.xz postgres_archive=superset-tools-postgres.${tag}${suffix}.tar.xz
compose_file=docker-compose.enterprise-clean.yml compose_file=docker-compose.enterprise-clean.yml
env_template=.env.enterprise-clean.example env_template=.env.example
env_bootstrap_fields=INITIAL_ADMIN_CREATE,INITIAL_ADMIN_USERNAME,INITIAL_ADMIN_PASSWORD,INITIAL_ADMIN_EMAIL env_bootstrap_fields=INITIAL_ADMIN_CREATE,INITIAL_ADMIN_USERNAME,INITIAL_ADMIN_PASSWORD,INITIAL_ADMIN_EMAIL
checksums_file=sha256sums.${tag}${suffix}.txt checksums_file=sha256sums.${tag}${suffix}.txt
generated_at_utc=$(date -u +"%Y-%m-%dT%H:%M:%SZ") generated_at_utc=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
@@ -608,7 +608,7 @@ EOF
} }
], ],
"compose_file": "docker-compose.enterprise-clean.yml", "compose_file": "docker-compose.enterprise-clean.yml",
"env_template": ".env.enterprise-clean.example", "env_template": ".env.example",
"env_bootstrap_fields": [ "env_bootstrap_fields": [
"INITIAL_ADMIN_CREATE", "INITIAL_ADMIN_CREATE",
"INITIAL_ADMIN_USERNAME", "INITIAL_ADMIN_USERNAME",
@@ -626,7 +626,7 @@ EOF
generate_bundle_env() { generate_bundle_env() {
local tag="$1" local tag="$1"
cat > "${DIST_ROOT}/.env.enterprise-clean.example" << 'ENV' cat > "${DIST_ROOT}/.env.example" << 'ENV'
# #region env.enterprise-clean.bundle [C:2] [TYPE Module] [SEMANTICS env,docker,bundle] # #region env.enterprise-clean.bundle [C:2] [TYPE Module] [SEMANTICS env,docker,bundle]
# @BRIEF Переменные окружения для docker-compose.enterprise-clean.yml (bundled postgres). # @BRIEF Переменные окружения для docker-compose.enterprise-clean.yml (bundled postgres).
# Все образы предварительно загружены через xz -dc ... | docker load. # Все образы предварительно загружены через xz -dc ... | docker load.
@@ -711,7 +711,7 @@ APP_TIMEZONE=Europe/Moscow
FEATURES__DATASET_REVIEW=true FEATURES__DATASET_REVIEW=true
FEATURES__HEALTH_MONITOR=true FEATURES__HEALTH_MONITOR=true
ENV ENV
echo "[bundle] ✅ Generated bundle env template: ${DIST_ROOT}/.env.enterprise-clean.example" echo "[bundle] ✅ Generated bundle env template: ${DIST_ROOT}/.env.example"
} }
bundle_release() { bundle_release() {
@@ -770,8 +770,9 @@ bundle_release() {
echo " xz -dc ${DIST_ROOT}/superset-tools-frontend.${tag}.tar.xz | docker load" echo " xz -dc ${DIST_ROOT}/superset-tools-frontend.${tag}.tar.xz | docker load"
echo " xz -dc ${DIST_ROOT}/superset-tools-agent.${tag}.tar.xz | docker load" echo " xz -dc ${DIST_ROOT}/superset-tools-agent.${tag}.tar.xz | docker load"
echo " xz -dc ${DIST_ROOT}/superset-tools-postgres.${tag}.tar.xz | docker load" echo " xz -dc ${DIST_ROOT}/superset-tools-postgres.${tag}.tar.xz | docker load"
echo " # Edit .env.enterprise-clean.example -> .env.enterprise-clean, then:" echo " # In the bundle directory, create and edit the standard Compose .env:"
echo " docker compose --env-file ${DIST_ROOT}/.env.enterprise-clean -f ${DIST_ROOT}/docker-compose.enterprise-clean.yml up -d" echo " cd ${DIST_ROOT} && cp .env.example .env"
echo " docker compose -f docker-compose.enterprise-clean.yml up -d"
echo "" echo ""
echo " NOTE: Bundle includes postgres container (db) — no external PostgreSQL needed." echo " NOTE: Bundle includes postgres container (db) — no external PostgreSQL needed."
echo " Corporate certs: mount .crt files via CERTS_PATH=./certs (optional)." echo " Corporate certs: mount .crt files via CERTS_PATH=./certs (optional)."
@@ -887,7 +888,7 @@ volumes:
postgres_data: postgres_data:
COMPOSE COMPOSE
cp "${SCRIPT_DIR}/.env.enterprise-clean.example" "${DIST_ROOT}/.env.light.example" cp "${SCRIPT_DIR}/.env.example" "${DIST_ROOT}/.env.light.example"
echo "[bundle:light] ✅ Lightweight bundle created in ${DIST_ROOT}" echo "[bundle:light] ✅ Lightweight bundle created in ${DIST_ROOT}"
echo " # Load image:" echo " # Load image:"
@@ -964,7 +965,8 @@ EOF
echo " xz -dc ${DIST_ROOT}/superset-tools-frontend.${tag}${suffix}.tar.xz | docker load" echo " xz -dc ${DIST_ROOT}/superset-tools-frontend.${tag}${suffix}.tar.xz | docker load"
echo " xz -dc ${DIST_ROOT}/superset-tools-agent.${tag}${suffix}.tar.xz | docker load" echo " xz -dc ${DIST_ROOT}/superset-tools-agent.${tag}${suffix}.tar.xz | docker load"
echo " xz -dc ${DIST_ROOT}/superset-tools-postgres.${tag}${suffix}.tar.xz | docker load" echo " xz -dc ${DIST_ROOT}/superset-tools-postgres.${tag}${suffix}.tar.xz | docker load"
echo " # Edit .env.enterprise-clean.example -> .env.enterprise-clean, then:" echo " # In the bundle directory: cp .env.example .env, edit .env, then:"
echo " docker compose -f docker-compose.enterprise-clean.yml up -d"
echo " docker compose -f ${DIST_ROOT}/docker-compose.enterprise-clean.yml up -d" echo " docker compose -f ${DIST_ROOT}/docker-compose.enterprise-clean.yml up -d"
echo "" echo ""
echo " NOTE: Agent image includes sentence-transformers+torch (~500 MB+)." echo " NOTE: Agent image includes sentence-transformers+torch (~500 MB+)."

View File

@@ -1,7 +1,7 @@
# #region docker.compose.enterprise-clean [C:4] [TYPE Module] [SEMANTICS docker,compose,enterprise] # #region docker.compose.enterprise-clean [C:4] [TYPE Module] [SEMANTICS docker,compose,enterprise]
# @BRIEF Enterprise docker compose — сборка backend + frontend + agent из исходников, # @BRIEF Enterprise docker compose — сборка backend + frontend + agent из исходников,
# встроенный Postgres (контейнер), корп. сертификаты. # встроенный Postgres (контейнер), корп. сертификаты.
# @PRE Docker и docker compose установлены. Файлы .env.enterprise-clean настроены. # @PRE Docker и docker compose установлены. Стандартный файл .env настроен.
# Postgres: запускается в контейнере (сервис db). Для внешнего PG — переопределить POSTGRES_HOST. # Postgres: запускается в контейнере (сервис db). Для внешнего PG — переопределить POSTGRES_HOST.
# Сертификаты: опциональные .crt файлы в CERTS_PATH монтируются в /opt/certs. # Сертификаты: опциональные .crt файлы в CERTS_PATH монтируются в /opt/certs.
# @POST Сервисы db, backend, frontend и agent запущены. SSL терминация в nginx опциональна. # @POST Сервисы db, backend, frontend и agent запущены. SSL терминация в nginx опциональна.
@@ -16,7 +16,7 @@
# @RELATION DEPENDS_ON -> [docker/nginx.ssl.conf] # @RELATION DEPENDS_ON -> [docker/nginx.ssl.conf]
# @RELATION DEPENDS_ON -> [docker/frontend.entrypoint.sh] # @RELATION DEPENDS_ON -> [docker/frontend.entrypoint.sh]
# @RELATION DEPENDS_ON -> [docker/backend.entrypoint.sh] # @RELATION DEPENDS_ON -> [docker/backend.entrypoint.sh]
# @DATA_CONTRACT Input: .env.enterprise-clean + ./certs/*.crt -> Output: запущенные контейнеры # @DATA_CONTRACT Input: .env + ./certs/*.crt -> Output: запущенные контейнеры
# @INVARIANT При использовании встроенного postgres (сервис db) healthcheck гарантирует # @INVARIANT При использовании встроенного postgres (сервис db) healthcheck гарантирует
# готовность БД через depends_on condition: service_healthy. # готовность БД через depends_on condition: service_healthy.
# Для внешнего PG — переопределить POSTGRES_HOST и удалить сервис db. # Для внешнего PG — переопределить POSTGRES_HOST и удалить сервис db.
@@ -41,7 +41,7 @@ services:
environment: environment:
POSTGRES_DB: ${POSTGRES_DB:-ss_tools} POSTGRES_DB: ${POSTGRES_DB:-ss_tools}
POSTGRES_USER: ${POSTGRES_USER:-postgres} POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env.enterprise-clean} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}
ports: ports:
- "${POSTGRES_HOST_PORT:-5432}:5432" - "${POSTGRES_HOST_PORT:-5432}:5432"
volumes: volumes:
@@ -61,14 +61,14 @@ services:
db: db:
condition: service_healthy condition: service_healthy
environment: environment:
DATABASE_URL: postgresql+psycopg2://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env.enterprise-clean}@${POSTGRES_HOST:-db}:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-ss_tools} DATABASE_URL: postgresql+psycopg2://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}@${POSTGRES_HOST:-db}:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-ss_tools}
STORAGE_ROOT_PATH: /app/storage STORAGE_ROOT_PATH: /app/storage
# Safe one-shot default: legacy revisions are reset; 0001_baseline is preserved. # Safe one-shot default: legacy revisions are reset; 0001_baseline is preserved.
RESET_DATABASE_SCHEMA: ${RESET_DATABASE_SCHEMA:-true} RESET_DATABASE_SCHEMA: ${RESET_DATABASE_SCHEMA:-true}
BACKEND_PORT: 8000 BACKEND_PORT: 8000
ALLOWED_ORIGINS: ${ALLOWED_ORIGINS:-} ALLOWED_ORIGINS: ${ALLOWED_ORIGINS:-}
AUTH_SECRET_KEY: ${AUTH_SECRET_KEY:?Set AUTH_SECRET_KEY in .env.enterprise-clean} AUTH_SECRET_KEY: ${AUTH_SECRET_KEY:?Set AUTH_SECRET_KEY in .env}
ENCRYPTION_KEY: ${ENCRYPTION_KEY:?ENCRYPTION_KEY обязателен — сгенерируйте и укажите в .env.enterprise-clean} ENCRYPTION_KEY: ${ENCRYPTION_KEY:?ENCRYPTION_KEY обязателен — сгенерируйте и укажите в .env}
ENABLE_BELIEF_STATE_LOGGING: ${ENABLE_BELIEF_STATE_LOGGING:-true} ENABLE_BELIEF_STATE_LOGGING: ${ENABLE_BELIEF_STATE_LOGGING:-true}
TASK_LOG_LEVEL: ${TASK_LOG_LEVEL:-INFO} TASK_LOG_LEVEL: ${TASK_LOG_LEVEL:-INFO}
INITIAL_ADMIN_CREATE: ${INITIAL_ADMIN_CREATE:-false} INITIAL_ADMIN_CREATE: ${INITIAL_ADMIN_CREATE:-false}
@@ -129,9 +129,9 @@ services:
LLM_MODEL: ${LLM_MODEL:-gpt-4o} LLM_MODEL: ${LLM_MODEL:-gpt-4o}
FASTAPI_URL: http://backend:8000 FASTAPI_URL: http://backend:8000
CERTS_PATH: /opt/certs CERTS_PATH: /opt/certs
AUTH_SECRET_KEY: ${AUTH_SECRET_KEY:?Set AUTH_SECRET_KEY in .env.enterprise-clean} AUTH_SECRET_KEY: ${AUTH_SECRET_KEY:?Set AUTH_SECRET_KEY in .env}
SERVICE_JWT: ${SERVICE_JWT:?Set SERVICE_JWT in .env — do not use a public default for the service secret} SERVICE_JWT: ${SERVICE_JWT:?Set SERVICE_JWT in .env — do not use a public default for the service secret}
DATABASE_URL: postgresql+psycopg2://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env.enterprise-clean}@${POSTGRES_HOST:-db}:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-ss_tools} DATABASE_URL: postgresql+psycopg2://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}@${POSTGRES_HOST:-db}:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-ss_tools}
STORAGE_ROOT_PATH: /app/storage STORAGE_ROOT_PATH: /app/storage
GRADIO_SERVER_PORT: 7860 GRADIO_SERVER_PORT: 7860
GRADIO_ROOT_PATH: /api/agent/gradio GRADIO_ROOT_PATH: /api/agent/gradio

View File

@@ -155,7 +155,7 @@ correctly building chains with intermediate CAs.
docker cp scripts/check_llm_certs.py superset-tools-backend-1:/tmp/ docker cp scripts/check_llm_certs.py superset-tools-backend-1:/tmp/
docker compose -f docker-compose.enterprise-clean.yml \ docker compose -f docker-compose.enterprise-clean.yml \
--env-file .env.enterprise-clean exec backend \ exec backend \
python3 /tmp/check_llm_certs.py --target https://lite.ai.rusal.com python3 /tmp/check_llm_certs.py --target https://lite.ai.rusal.com
``` ```
@@ -255,15 +255,15 @@ ls ./certs/
# RUSAL_ROOT.crt RGM_Issuing.crt UC_RUSAL_Policy_CA.crt etc. # RUSAL_ROOT.crt RGM_Issuing.crt UC_RUSAL_Policy_CA.crt etc.
docker compose -f docker-compose.enterprise-clean.yml \ docker compose -f docker-compose.enterprise-clean.yml \
--env-file .env.enterprise-clean down down
docker compose -f docker-compose.enterprise-clean.yml \ docker compose -f docker-compose.enterprise-clean.yml \
--env-file .env.enterprise-clean up -d up -d
# Verify # Verify
docker cp scripts/check_llm_certs.py superset-tools-backend-1:/tmp/ docker cp scripts/check_llm_certs.py superset-tools-backend-1:/tmp/
docker compose -f docker-compose.enterprise-clean.yml \ docker compose -f docker-compose.enterprise-clean.yml \
--env-file .env.enterprise-clean exec backend \ exec backend \
python3 /tmp/check_llm_certs.py --target https://lite.ai.rusal.com python3 /tmp/check_llm_certs.py --target https://lite.ai.rusal.com
``` ```

View File

@@ -85,7 +85,7 @@ cd /home/busya/dev/superset-tools
- `frontend` image с уже собранным SvelteKit bundle; - `frontend` image с уже собранным SvelteKit bundle;
- `postgres` image или внутренний pinned base image; - `postgres` image или внутренний pinned base image;
- `docker-compose.enterprise-clean.yml` для запуска в air-gapped окружении; - `docker-compose.enterprise-clean.yml` для запуска в air-gapped окружении;
- `.env.enterprise-clean.example` с обязательными переменными; - `.env.example` с обязательными переменными;
- manifest с версиями, sha256 и перечнем образов; - manifest с версиями, sha256 и перечнем образов;
- инструкции по `docker load` / `docker compose up` без обращения к внешним registry. - инструкции по `docker load` / `docker compose up` без обращения к внешним registry.
@@ -99,7 +99,7 @@ cd /home/busya/dev/superset-tools
# backend.v1.0.0-rc2-docker.tar.xz # backend.v1.0.0-rc2-docker.tar.xz
# frontend.v1.0.0-rc2-docker.tar.xz # frontend.v1.0.0-rc2-docker.tar.xz
# postgres.v1.0.0-rc2-docker.tar.xz # postgres.v1.0.0-rc2-docker.tar.xz
# manifest + sha256sums + docker-compose.enterprise-clean.yml + .env.enterprise-clean.example # manifest + sha256sums + docker-compose.enterprise-clean.yml + .env.example
# 2. Передать dist/docker/* в изолированный контур # 2. Передать dist/docker/* в изолированный контур
# 3. Импортировать образы локально (распаковка на лету) # 3. Импортировать образы локально (распаковка на лету)
@@ -108,7 +108,8 @@ xz -dc dist/docker/frontend.v1.0.0-rc2-docker.tar.xz | docker load
xz -dc dist/docker/postgres.v1.0.0-rc2-docker.tar.xz | docker load xz -dc dist/docker/postgres.v1.0.0-rc2-docker.tar.xz | docker load
# 4. Подготовить env из шаблона # 4. Подготовить env из шаблона
cp dist/docker/.env.enterprise-clean.example .env.enterprise-clean cd dist/docker
cp .env.example .env
# 4a. Для первого запуска задать bootstrap администратора # 4a. Для первого запуска задать bootstrap администратора
# INITIAL_ADMIN_CREATE=true # INITIAL_ADMIN_CREATE=true
@@ -116,7 +117,7 @@ cp dist/docker/.env.enterprise-clean.example .env.enterprise-clean
# INITIAL_ADMIN_PASSWORD=<temporary-strong-secret> # INITIAL_ADMIN_PASSWORD=<temporary-strong-secret>
# 5. Запустить только локальные образы # 5. Запустить только локальные образы
docker compose --env-file .env.enterprise-clean -f dist/docker/docker-compose.enterprise-clean.yml up -d docker compose -f docker-compose.enterprise-clean.yml up -d
``` ```
Для легковесного all-in-one образа (без Playwright, **~104 MB** вместо 575 MB): Для легковесного all-in-one образа (без Playwright, **~104 MB** вместо 575 MB):
@@ -139,7 +140,7 @@ docker compose -f dist/docker/docker-compose.light.yml up
Bootstrap администратора выполняется entrypoint-скриптом внутри backend container: Bootstrap администратора выполняется entrypoint-скриптом внутри backend container:
- если `INITIAL_ADMIN_CREATE=true`, контейнер вызывает [`create_admin.py`](backend/src/scripts/create_admin.py) перед стартом API; - если `INITIAL_ADMIN_CREATE=true`, контейнер вызывает [`create_admin.py`](backend/src/scripts/create_admin.py) перед стартом API;
- если администратор уже существует, учётная запись не меняется; - если администратор уже существует, учётная запись не меняется;
- теги в [`.env.enterprise-clean.example`](.env.enterprise-clean.example) должны совпадать с фактически загруженными образами `superset-tools-backend:v1.0.0-rc2-docker` и `superset-tools-frontend:v1.0.0-rc2-docker`; - runtime-параметры задаются стандартным Compose-файлом `.env` рядом с bundle compose;
- после первого входа пароль должен быть ротирован, а `INITIAL_ADMIN_CREATE` возвращён в `false`. - после первого входа пароль должен быть ротирован, а `INITIAL_ADMIN_CREATE` возвращён в `false`.
Ограничения для production-grade offline release: Ограничения для production-grade offline release:

View File

@@ -176,7 +176,7 @@ cd /home/busya/dev/superset-tools
- `sha256sums.v1.0.0-rc2-docker.txt` - `sha256sums.v1.0.0-rc2-docker.txt`
- `manifest.v1.0.0-rc2-docker.{txt,json}` - `manifest.v1.0.0-rc2-docker.{txt,json}`
- `docker-compose.enterprise-clean.yml` - `docker-compose.enterprise-clean.yml`
- `.env.enterprise-clean.example` - `.env.example`
Результат легковесного бандла: Результат легковесного бандла:
- `superset-tools.v1.0.0.tar` - `superset-tools.v1.0.0.tar`
@@ -200,7 +200,7 @@ docker load -i postgres.v1.0.0-rc2-docker.tar
### 4. Подготовка конфигурации ### 4. Подготовка конфигурации
```bash ```bash
cp .env.enterprise-clean.example .env.enterprise-clean cp .env.example .env
``` ```
Минимально проверьте: Минимально проверьте:
@@ -216,14 +216,14 @@ cp .env.enterprise-clean.example .env.enterprise-clean
- `INITIAL_ADMIN_PASSWORD=<temporary-strong-secret>` - `INITIAL_ADMIN_PASSWORD=<temporary-strong-secret>`
- `INITIAL_ADMIN_EMAIL=<optional>` - `INITIAL_ADMIN_EMAIL=<optional>`
Также проверьте, что теги образов в [`.env.enterprise-clean`](.env.enterprise-clean.example) совпадают с реально загруженными: Также проверьте, что теги образов в `.env` совпадают с реально загруженными:
- `BACKEND_IMAGE=superset-tools-backend:v1.0.0-rc2-docker` - `BACKEND_IMAGE=superset-tools-backend:v1.0.0-rc2-docker`
- `FRONTEND_IMAGE=superset-tools-frontend:v1.0.0-rc2-docker` - `FRONTEND_IMAGE=superset-tools-frontend:v1.0.0-rc2-docker`
### 5. Запуск в offline-контуре ### 5. Запуск в offline-контуре
```bash ```bash
docker compose --env-file .env.enterprise-clean -f docker-compose.enterprise-clean.yml up -d docker compose -f docker-compose.enterprise-clean.yml up -d
``` ```
Compose-файл использует `pull_policy: never`, поэтому runtime не должен обращаться к внешним registry. Compose-файл использует `pull_policy: never`, поэтому runtime не должен обращаться к внешним registry.
@@ -239,7 +239,7 @@ Compose-файл использует `pull_policy: never`, поэтому runti
После первого успешного входа обязательно: После первого успешного входа обязательно:
- смените bootstrap-пароль на постоянный организационный секрет; - смените bootstrap-пароль на постоянный организационный секрет;
- установите `INITIAL_ADMIN_CREATE=false`; - установите `INITIAL_ADMIN_CREATE=false`;
- перезапустите stack с обновлённым `.env.enterprise-clean`. - перезапустите stack с обновлённым `.env`.
Если bootstrap завершается ошибкой, backend не стартует это ожидаемый fail-fast режим для безопасного ввода в эксплуатацию. Если bootstrap завершается ошибкой, backend не стартует это ожидаемый fail-fast режим для безопасного ввода в эксплуатацию.

View File

@@ -24,7 +24,7 @@
# (fresh PostgreSQL, StartupEnvironmentWizard), так и "живой" проект с настроенными окружениями. # (fresh PostgreSQL, StartupEnvironmentWizard), так и "живой" проект с настроенными окружениями.
# @REJECTED Использование одного docker-compose файла для обоих стейджей — enterprise-clean требует # @REJECTED Использование одного docker-compose файла для обоих стейджей — enterprise-clean требует
# build из исходников + внешний PostgreSQL, а run.sh использует локальный dev compose. # build из исходников + внешний PostgreSQL, а run.sh использует локальный dev compose.
# @DATA_CONTRACT Input: тег релиза (аргумент), .env.enterprise-clean.example, backend/.env # @DATA_CONTRACT Input: тег релиза (аргумент), .env.example, backend/.env
# Output: dist/docker/*.tar.xz, dist/docker/manifest*.txt, playwright-report/ # Output: dist/docker/*.tar.xz, dist/docker/manifest*.txt, playwright-report/
# #endregion E2E.RunEnterpriseCleanE2E # #endregion E2E.RunEnterpriseCleanE2E

View File

@@ -35,7 +35,7 @@
- 1 TUI сценарий подготовки/проверки; - 1 TUI сценарий подготовки/проверки;
- 69 новых/обновлённых модулей (+config_loader, filesystem_scanner, db_cleanup_executor); - 69 новых/обновлённых модулей (+config_loader, filesystem_scanner, db_cleanup_executor);
- документация и контракты в пределах feature-папки; - документация и контракты в пределах feature-папки;
- runtime bootstrap администратора через переменные `.env.enterprise-clean` без hardcode секретов в образах. - runtime bootstrap администратора через стандартный Compose `.env` без hardcode секретов в образах.
## Constitution Check ## Constitution Check
@@ -169,7 +169,7 @@ frontend/
## Implementation Traceability & Final Notes ## Implementation Traceability & Final Notes
- Статус реализации: Phase 17 завершены (T001T044). - Статус реализации: Phase 17 завершены (T001T044).
- Новое расширение (post-release hardening, 2026-03-13): добавлен scope на управляемый bootstrap администратора через `.env.enterprise-clean` и docker startup flow. - Новое расширение (post-release hardening, 2026-03-13): добавлен scope на управляемый bootstrap администратора через `.env` и docker startup flow.
- Ключевые подтверждения polish-фазы: - Ключевые подтверждения polish-фазы:
- T039: smoke TUI сценария зафиксирован в [`quickstart.md`](./quickstart.md). - T039: smoke TUI сценария зафиксирован в [`quickstart.md`](./quickstart.md).
- T040: контрактная проверка API подтверждена тестом [`backend/src/api/routes/__tests__/test_clean_release_api.py`](../../backend/src/api/routes/__tests__/test_clean_release_api.py). - T040: контрактная проверка API подтверждена тестом [`backend/src/api/routes/__tests__/test_clean_release_api.py`](../../backend/src/api/routes/__tests__/test_clean_release_api.py).
@@ -179,12 +179,12 @@ frontend/
Итог: базовая feature готова к финальному релизному циклу с обязательным CI gate (`COMPLIANT` only) и операционной доказательной базой для аудита. Итог: базовая feature готова к финальному релизному циклу с обязательным CI gate (`COMPLIANT` only) и операционной доказательной базой для аудита.
## Post-Release Hardening Addendum — Admin Bootstrap via `.env.enterprise-clean` ## Post-Release Hardening Addendum — Admin Bootstrap via `.env`
Цель addendum: убрать ручной шаг создания initial admin после доставки offline bundle и сделать это управляемой частью container startup. Цель addendum: убрать ручной шаг создания initial admin после доставки offline bundle и сделать это управляемой частью container startup.
Архитектурные решения: Архитектурные решения:
1. В `.env.enterprise-clean.example` добавить параметры: 1. В `.env.example` добавить параметры:
- `INITIAL_ADMIN_CREATE=false` (default-safe), - `INITIAL_ADMIN_CREATE=false` (default-safe),
- `INITIAL_ADMIN_USERNAME=admin`, - `INITIAL_ADMIN_USERNAME=admin`,
- `INITIAL_ADMIN_PASSWORD=change-me`, - `INITIAL_ADMIN_PASSWORD=change-me`,
@@ -195,7 +195,7 @@ frontend/
- обрабатывает idempotency (существующий пользователь => без ошибки, лог `already exists`). - обрабатывает idempotency (существующий пользователь => без ошибки, лог `already exists`).
3. В `docker-compose.enterprise-clean.yml` прокинуть переменные bootstrap администратора только в `backend` service. 3. В `docker-compose.enterprise-clean.yml` прокинуть переменные bootstrap администратора только в `backend` service.
4. В операционном runbook зафиксировать обязательную ротацию bootstrap-пароля после первого входа. 4. В операционном runbook зафиксировать обязательную ротацию bootstrap-пароля после первого входа.
5. В offline bundle manifest оставить ссылку на `.env.enterprise-clean.example` как source-of-truth для параметров запуска. 5. В offline bundle manifest оставить ссылку на `.env.example` как source-of-truth для параметров запуска.
Нефункциональные ограничения: Нефункциональные ограничения:
- Никаких default production секретов в Git. - Никаких default production секретов в Git.

View File

@@ -73,9 +73,9 @@ cd /home/busya/dev/superset-tools
2. Повторно запустить проверку из того же TUI экрана (`F5`). 2. Повторно запустить проверку из того же TUI экрана (`F5`).
3. Повторять до статуса `COMPLIANT`. 3. Повторять до статуса `COMPLIANT`.
## Admin Bootstrap via `.env.enterprise-clean` (Docker Runtime) ## Admin Bootstrap via `.env` (Docker Runtime)
Для offline bundle deployment в контейнерах используйте runtime файл `.env.enterprise-clean` на базе шаблона `.env.enterprise-clean.example`. Для offline bundle deployment в контейнерах используйте стандартный runtime файл `.env` на базе шаблона `.env.example`.
Обязательные параметры bootstrap: Обязательные параметры bootstrap:
- `INITIAL_ADMIN_CREATE=true` для первого запуска; - `INITIAL_ADMIN_CREATE=true` для первого запуска;

View File

@@ -102,9 +102,9 @@
- **FR-018**: Стадия `NO_EXTERNAL_ENDPOINTS` MUST сканировать все текстовые файлы (включая код, конфиги, скрипты) на наличие URL/хостов и сверять каждый найденный endpoint с `allowed_sources`. - **FR-018**: Стадия `NO_EXTERNAL_ENDPOINTS` MUST сканировать все текстовые файлы (включая код, конфиги, скрипты) на наличие URL/хостов и сверять каждый найденный endpoint с `allowed_sources`.
- **FR-019**: Процесс clean-подготовки MUST включать стадию очистки БД от тестовых пользователей и демо-данных. Правила очистки (таблицы, условия, исключения) задаются в секции `database_cleanup` файла `.clean-release.yaml`. - **FR-019**: Процесс clean-подготовки MUST включать стадию очистки БД от тестовых пользователей и демо-данных. Правила очистки (таблицы, условия, исключения) задаются в секции `database_cleanup` файла `.clean-release.yaml`.
- **FR-020**: Структура `.clean-release.yaml` MUST включать секции: `profile`, `scan_mode`, `prohibited_categories`, `prohibited_paths`, `allowed_sources`, `ignore_paths`, `database_cleanup` (с подсекциями `tables` и `preserve`). - **FR-020**: Структура `.clean-release.yaml` MUST включать секции: `profile`, `scan_mode`, `prohibited_categories`, `prohibited_paths`, `allowed_sources`, `ignore_paths`, `database_cleanup` (с подсекциями `tables` и `preserve`).
- **FR-021**: Enterprise clean release bundle MUST включать `.env.enterprise-clean.example` с параметрами bootstrap администратора (`INITIAL_ADMIN_USERNAME`, `INITIAL_ADMIN_PASSWORD`, `INITIAL_ADMIN_EMAIL` optional, `INITIAL_ADMIN_CREATE`) и безопасными комментариями по ротации пароля. - **FR-021**: Enterprise clean release bundle MUST включать `.env.example` с параметрами bootstrap администратора (`INITIAL_ADMIN_USERNAME`, `INITIAL_ADMIN_PASSWORD`, `INITIAL_ADMIN_EMAIL` optional, `INITIAL_ADMIN_CREATE`) и безопасными комментариями по ротации пароля.
- **FR-022**: Docker startup flow backend MUST поддерживать idempotent bootstrap администратора при запуске контейнера: при `INITIAL_ADMIN_CREATE=true` система создаёт администратора только если пользователь отсутствует и не перезаписывает существующие credentials/roles. - **FR-022**: Docker startup flow backend MUST поддерживать idempotent bootstrap администратора при запуске контейнера: при `INITIAL_ADMIN_CREATE=true` система создаёт администратора только если пользователь отсутствует и не перезаписывает существующие credentials/roles.
- **FR-023**: Процесс публикации clean bundle MUST включать операторский сценарий заполнения runtime `.env.enterprise-clean` из шаблона и подтверждение, что bootstrap-пароль заменён на организационный секрет до первого production запуска. - **FR-023**: Процесс публикации clean bundle MUST включать операторский сценарий заполнения runtime `.env` из шаблона и подтверждение, что bootstrap-пароль заменён на организационный секрет до первого production запуска.
### Key Entities *(include if feature involves data)* ### Key Entities *(include if feature involves data)*

View File

@@ -143,9 +143,9 @@
## Phase 8: Post-Release Hardening — Admin Bootstrap in Docker ## Phase 8: Post-Release Hardening — Admin Bootstrap in Docker
**Purpose**: Автоматизировать первичное создание администратора через runtime `.env.enterprise-clean` в offline/enterprise deployment. **Purpose**: Автоматизировать первичное создание администратора через runtime `.env` в offline/enterprise deployment.
- [X] T045 Add admin bootstrap env contract to `.env.enterprise-clean.example` (`INITIAL_ADMIN_CREATE`, `INITIAL_ADMIN_USERNAME`, `INITIAL_ADMIN_PASSWORD`, optional `INITIAL_ADMIN_EMAIL`) - [X] T045 Add admin bootstrap env contract to `.env.example` (`INITIAL_ADMIN_CREATE`, `INITIAL_ADMIN_USERNAME`, `INITIAL_ADMIN_PASSWORD`, optional `INITIAL_ADMIN_EMAIL`)
- [X] T046 Wire admin bootstrap envs to backend runtime in `docker-compose.enterprise-clean.yml` - [X] T046 Wire admin bootstrap envs to backend runtime in `docker-compose.enterprise-clean.yml`
- [X] T047 Add backend entrypoint flow that performs idempotent admin bootstrap before app start in `docker/backend.Dockerfile` and new entrypoint script - [X] T047 Add backend entrypoint flow that performs idempotent admin bootstrap before app start in `docker/backend.Dockerfile` and new entrypoint script
- [X] T048 Extend admin creation script for optional email and deterministic exit behavior for existing user in `backend/src/scripts/create_admin.py` - [X] T048 Extend admin creation script for optional email and deterministic exit behavior for existing user in `backend/src/scripts/create_admin.py`