3 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
633bdf3ef0 |
fix(auth): закрыть критические дыры — orphan login, self-delete, owner-delete, override-баннер
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 46s
CI / Web (React + Vite) (push) Successful in 41s
Docker API / Build + push API (push) Successful in 1m12s
Docker Web / Build + push Web (push) Successful in 31s
Docker API / Deploy API on stage (push) Successful in 17s
Docker Web / Deploy Web on stage (push) Successful in 12s
Аудит 2026-04-27. Полный отчёт — docs/audit-2026-04-27.md. Что закрыто: — /connect/token (AuthorizationController) теперь отказывает в login если AppUser привязан к удалённой/архивной Organization. SuperAdmin обходит проверку (ему org не нужна). Жалоба: nurnetps@gmail.com мог логиниться после удаления своей org из SuperAdmin консоли. — SuperAdminOrganizationsController.Delete (DELETE org) каскадно деактивирует всех AppUser привязанных к этой org (IsActive=false, OrganizationId=null) и помечает Status='revoked' для всех их OpenIddictTokens. Раньше Org удалялась, а юзеры оставались валидными с активными refresh-tokens на 30 дней. — EmployeesController.Delete теперь soft-delete (IsActive=false, FiredAt). Запрещены: 403 если попытка удалить себя; 403 если попытка удалить Owner (Organization.AccountOwnerUserId == employee.UserId). Сообщения с инструкцией («передайте права», «покинуть через настройки»). — /api/me возвращает hasLiveOrg и hasActiveEmployee — frontend использует это для редиректа на /no-organization вместо белого экрана. — Новая страница /no-organization (NoOrganizationPage) — fallback для orphan AppUser. CTA: создать новую org через публичный /signup или попросить инвайт. Кнопка «выйти». TenantRouteGuard редиректит orphan юзеров туда. — SuperAdminAsOrgBanner: добавлена проверка через useMe — баннер рендерится только если у текущего юзера есть Identity-роль SuperAdmin. Lingering localStorage override от прошлой сессии (другой юзер логинился до этого) автоматически чистится. — auth.ts: clearTokens() теперь сбрасывает superAdminAsOrg и superAdminEditMode. login() вызывает clearTokens() ПЕРЕД запросом чтобы новый юзер не унаследовал override-состояние от предыдущего. — deploy/recovery-restore-orphan-owners.sql — идемпотентный скрипт деактивирующий уже накопленных orphan AppUser (как nurnetps) и revoke их токены. Применён на стейдже: 1 user деактивирован, 9 токенов revoked. — deploy/Dockerfile.api: убран `--no-restore` из publish — два раздельных шага роняли build с NETSDK1064 на свежих analyzer- зависимостях, теперь restore идёт внутри publish. Smoke (стейдж): - nurnetps@gmail.com /connect/token → invalid_grant. - admin@food-market.local /connect/token → access_token выдан. - food-market.zat.kz/, /signup/, app.../login, /health → 200. |
||
|
|
71a2d46bf2 |
deploy: mirror all base images into local registry — builds no longer need internet
Any block on mcr.microsoft.com or docker.io from KZ would stall our
builds. Mirror docker base images into 127.0.0.1:5001 under mirror/*
via daily systemd timer, and point Dockerfiles + compose + CI at the
local copies.
Mirror:
node:20-alpine → 127.0.0.1:5001/mirror/node:20-alpine
nginx:1.27-alpine → 127.0.0.1:5001/mirror/nginx:1.27-alpine
postgres:16-alpine → 127.0.0.1:5001/mirror/postgres:16-alpine
mcr.microsoft.com/dotnet/sdk:8.0 → 127.0.0.1:5001/mirror/dotnet-sdk:8.0
mcr.microsoft.com/dotnet/aspnet:8.0 → 127.0.0.1:5001/mirror/dotnet-aspnet:8.0
Infra (committed for reproducibility):
- deploy/mirror-base-images.sh — pull/tag/push (idempotent)
- deploy/food-market-mirror-base-images.{service,timer} — daily refresh,
installed on stage server
Usage in build-time:
- Dockerfile.api/web take ARG LOCAL_REGISTRY=127.0.0.1:5001 with the local
copy as default, so the same Dockerfile still builds from docker.io if
you pass --build-arg LOCAL_REGISTRY=docker.io (well, almost).
- docker-compose.yml postgres: image via ${REGISTRY}/mirror/postgres.
- ci.yml postgres service container: local mirror.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
dfa7ce075a |
ci/deploy: GitHub Actions + Docker images + DB backup + 24x7 plan
.github/workflows/ci.yml — on push/PR:
- backend job: dotnet restore/build/test with a live postgres service
- web job: pnpm install + vite build + tsc, uploads dist artifact
- pos job: windows-latest, dotnet publish self-contained win-x64
single-file exe as artifact
.github/workflows/docker.yml — on push to main (if src changed) or manual:
- api image → ghcr.io/nurdotnet/food-market-api:{latest,sha}
- web image → ghcr.io/nurdotnet/food-market-web:{latest,sha}
- uses buildx + GHA cache
deploy/Dockerfile.api — multi-stage (.NET 8 sdk → aspnet runtime),
healthcheck on /health, App_Data + logs volumes mounted.
deploy/Dockerfile.web — node20 build → nginx 1.27 runtime; ships the
Vite dist + nginx.conf that proxies /api, /connect, /health to api
service and serves the SPA with fallback to index.html.
deploy/nginx.conf — SPA + API reverse-proxy configuration.
deploy/docker-compose.yml — production-shape stack: postgres 16 +
api (from ghcr image) + web (from ghcr image), named volumes, env-
driven tags so stage/prod can pin specific SHAs.
deploy/backup.sh — pg_dump wrapper with 3 modes: local (brew
postgres), --docker (compose container), --remote HOST:PORT. Writes
gzipped dumps to ~/food-market-backups, 30-day retention.
docs/24x7.md — explains where Claude/CI/stage live, which pieces
depend on the Mac, and the exact steps to hand off secrets via
~/.food-market-secrets/ so I can push them into GitHub Secrets.
Next, once user supplies Proxmox + FTP + Telegram creds: stage deploy
workflow, notification workflow, and (optional) claude-runner VM so
I no longer depend on the Mac being awake.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|