Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Public / Build + push Public (test + latest) (push) Waiting to run
Docker Public / Deploy :test → test.food-market.kz (push) Blocked by required conditions
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
Координатор отротировал мастер-пароль стенда: теперь значение живёт в ~/.fm-watchdog/stage-shared-password на dev-vm (не коммитится) и в QUICK_LOGIN_MASTER_PASSWORD в stage-env на prod-vm. Старый дефолт '123456' на обоих сторонах убран — он мог вводить в заблуждение и был записан в бандл. Клиент-серверный контракт: - Server (AuthorizationController.IsMasterPassword) принимает ДВА пароля как мастер-ключ: (a) QuickLoginOptions.MasterPassword (константное сравнение, FixedTimeEquals); (b) публичный sentinel QuickLoginOptions.SentinelPassword = '__QUICK_LOGIN_PWLESS__'. Оба гейтованы EffectivelyEnabled — вне стенда отбиваются как любой чужой пароль. - SPA (LoginPage.handleQuickLogin) при клике карточки шлёт sentinel в поле password. Реальный пароль в JS-бандл больше не попадает; ротация секрета больше не требует rebuild'а веба. - Форму мы НЕ наполняем sentinel'ом — поле password остаётся пустым, чтобы ни одно значение не светилось в DOM. Default QuickLoginOptions.MasterPassword = "" (пустая строка не матчится в IsMasterPassword). deploy/docker-compose.yml дефолт QUICK_LOGIN_MASTER_PASSWORD тоже пустой. Тесты: - integration (3/3 ok) — добавлены sentinel-кейсы: пропускает активного при Enabled=true, отвергается при Enabled=false. Admin12345!-санити- логин в Disabled-тесте перенесён вперёд, чтобы снять lockout-счётчик от соседей по коллекции (Identity lockoutOnFailure=true). - e2e stage-quick-login (4/4 ok) — ql02 шлёт sentinel вместо '123456' (симулирует реальный SPA flow). docs/quick-login.md: - без упоминания реального пароля; хранилище — ~/.fm-watchdog/ stage-shared-password; ротация-рецепт через python читает файл в-процессе (не экспонирует значение в ps/логи). - раздел «Доступ к стенду» — host-nginx basic-auth для внешнего интернета, 192.168.1.x бьёт без неё. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
97 lines
4.3 KiB
YAML
97 lines
4.3 KiB
YAML
services:
|
||
postgres:
|
||
image: ${REGISTRY:-127.0.0.1:5001}/mirror/postgres:16-alpine
|
||
container_name: food-market-postgres
|
||
restart: unless-stopped
|
||
environment:
|
||
POSTGRES_DB: food_market
|
||
POSTGRES_USER: food_market
|
||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-food_market_dev}
|
||
PGDATA: /var/lib/postgresql/data/pgdata
|
||
# Stage VM already uses 5432 (host postgres) — map ours to 5434 to avoid clash.
|
||
ports:
|
||
- "127.0.0.1:5434:5432"
|
||
volumes:
|
||
- postgres-data:/var/lib/postgresql/data
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "pg_isready -U food_market -d food_market"]
|
||
interval: 10s
|
||
timeout: 5s
|
||
retries: 5
|
||
|
||
api:
|
||
image: ${REGISTRY:-127.0.0.1:5001}/food-market-api:${API_TAG:-latest}
|
||
container_name: food-market-api
|
||
restart: unless-stopped
|
||
depends_on:
|
||
postgres:
|
||
condition: service_healthy
|
||
environment:
|
||
ASPNETCORE_ENVIRONMENT: Production
|
||
ConnectionStrings__Default: Host=postgres;Port=5432;Database=food_market;Username=food_market;Password=${POSTGRES_PASSWORD:-food_market_dev}
|
||
# Публичный issuer токенов — обязателен за прокси, иначе берётся из запроса
|
||
# (или дефолт localhost из appsettings, что неверно для прод).
|
||
OpenIddict__Issuer: ${OPENIDDICT_ISSUER:-https://admin.food-market.kz/}
|
||
# Пароль PFX-сертификатов OpenIddict (пусто = сертификаты без пароля).
|
||
OpenIddict__CertPassword: ${OPENIDDICT_CERT_PASSWORD:-}
|
||
# Sprint 13: rate-limit на signup. На stage'е переопределяется в
|
||
# .env'е через RATE_SIGNUP_HOUR / RATE_SIGNUP_DAY для прохождения
|
||
# e2e/smoke; в prod'е оставляем дефолты 3/час, 10/сутки.
|
||
RateLimiting__SignupPerIpPerHour: ${RATE_SIGNUP_HOUR:-3}
|
||
RateLimiting__SignupPerIpPerDay: ${RATE_SIGNUP_DAY:-10}
|
||
# Sprint 30: «быстрый вход» на тестовом стенде. По умолчанию выключено.
|
||
# На stage включается через QUICK_LOGIN_ENABLED=true в .env.
|
||
# QUICK_LOGIN_MASTER_PASSWORD задаётся секрет-паролем стенда (значение
|
||
# хранится вне репозитория — на dev-vm в ~/.fm-watchdog/stage-shared-
|
||
# password). Если переменная пустая — master-password-режим отключён
|
||
# (IsMasterPassword отбивает пустую строку). SPA отправляет публичный
|
||
# sentinel '__QUICK_LOGIN_PWLESS__' — реальный пароль в JS не попадает.
|
||
# Code имеет safety-override: даже с Enabled=true, если OpenIddict__
|
||
# Issuer смотрит на admin.food-market.kz — быстрый вход принудительно
|
||
# выключен (см. QuickLoginOptions.EffectivelyEnabled).
|
||
QuickLogin__Enabled: ${QUICK_LOGIN_ENABLED:-false}
|
||
QuickLogin__MasterPassword: ${QUICK_LOGIN_MASTER_PASSWORD:-}
|
||
# Host port mapping: pick free ports on existing stage server (80/443 taken by
|
||
# legacy nginx, 5000/5002/5005 taken by legacy .NET apps).
|
||
ports:
|
||
- "8080:8080" # api
|
||
|
||
healthcheck:
|
||
# Готовность = БД отвечает + миграции применены (см. /health/ready).
|
||
test: ["CMD-SHELL", "curl -fsS http://localhost:8080/health/ready || exit 1"]
|
||
interval: 30s
|
||
timeout: 5s
|
||
retries: 5
|
||
start_period: 30s
|
||
|
||
volumes:
|
||
- api-data:/app/App_Data
|
||
- api-logs:/app/logs
|
||
- /opt/food-market-data/uploads:/app/uploads
|
||
|
||
web:
|
||
image: ${REGISTRY:-127.0.0.1:5001}/food-market-web:${WEB_TAG:-latest}
|
||
container_name: food-market-web
|
||
restart: unless-stopped
|
||
depends_on:
|
||
api:
|
||
condition: service_healthy
|
||
ports:
|
||
- "8081:80" # web SPA, not on 80 (legacy nginx holds it)
|
||
|
||
public:
|
||
image: ${REGISTRY:-127.0.0.1:5001}/food-market-public:${PUBLIC_TAG:-latest}
|
||
container_name: food-market-public
|
||
restart: unless-stopped
|
||
ports:
|
||
- "8082:80" # marketing astro static
|
||
|
||
volumes:
|
||
postgres-data:
|
||
name: food-market-postgres-data
|
||
api-data:
|
||
name: food-market-api-data
|
||
api-logs:
|
||
name: food-market-api-logs
|
||
|