v0.5.13: gitignore разработческих файлов (DevOps-чистота)
This commit is contained in:
@@ -1,56 +0,0 @@
|
||||
# План доделок перед сдачей заказчику
|
||||
|
||||
> 2026-06-02
|
||||
|
||||
## 1. §4.7 — Агрегация CIDR в публичном /export
|
||||
|
||||
**Проблема:** публичный `/export` отдаёт сырой список, без агрегации.
|
||||
ТЗ: «подсети суммаризируются (агрегируются в минимальный набор CIDR)».
|
||||
|
||||
**Решение:** добавить `aggregateCIDRs()` в обработчик `server.js`.
|
||||
|
||||
**Файлы:** `server.js` — одна строка.
|
||||
|
||||
---
|
||||
|
||||
## 2. §4.1 — Фильтр «показать удалённые» для admin
|
||||
|
||||
**Проблема:** админ не может посмотреть soft-deleted записи.
|
||||
|
||||
**Решение:**
|
||||
- API: поддержать `?includeDeleted=true` в `GET /api/v1/entries`
|
||||
- UI: добавить чек-бокс «показать удалённые» на странице admin
|
||||
|
||||
**Файлы:** `src/api/routes/entries.js`, `views/index.ejs`.
|
||||
|
||||
---
|
||||
|
||||
## 3. §5 — Клиентская JS-валидация
|
||||
|
||||
**Проблема:** только HTML5 `pattern`, нет проверки приватных диапазонов и нормализации на клиенте.
|
||||
|
||||
**Решение:** добавить JS-функцию `validateClientIP()` в EJS-шаблон:
|
||||
- Проверка приватных/запрещённых диапазонов (показывать ошибку сразу)
|
||||
- Предпросмотр нормализации («будет сохранено как X.X.X.0/24»)
|
||||
|
||||
**Файлы:** `views/index.ejs`.
|
||||
|
||||
---
|
||||
|
||||
## 4. §5 — Уведомление о нормализации в UI
|
||||
|
||||
**Проблема:** API возвращает `wasNormalized`, но UI может не показывать.
|
||||
|
||||
**Решение:** проверить `ui/routes/entries.js` — передаёт ли `wasNormalized` в шаблон.
|
||||
Если нет — добавить. В шаблоне показать жёлтый alert.
|
||||
|
||||
**Файлы:** `ui/routes/entries.js`, `views/index.ejs`.
|
||||
|
||||
---
|
||||
|
||||
## Порядок:
|
||||
1. §4.7 — самая простая, одна строка
|
||||
2. §5 — уведомление о нормализации
|
||||
3. §5 — клиентская валидация
|
||||
4. §4.1 — фильтр удалённых (самая объёмная)
|
||||
5. Везде: тесты, VERSION++, коммит
|
||||
@@ -1,110 +0,0 @@
|
||||
# Чистка кластеров — 01.06.2026
|
||||
|
||||
## Кластер: iot-naeel (5.172.178.213)
|
||||
|
||||
### Удалено
|
||||
|
||||
| Группа | Штук | Причина |
|
||||
|---|---|---|
|
||||
| `fission-test-*` | 27 | Тестовые Fission namespace-ы с подами. Жрали ~24 CPU limits |
|
||||
| `fission-*` (с хешами) | 40 | Остатки Fission environment-ов. Сначала удалились, потом воссоздались через CRD — потребовалось удалить CRD `environments.fission.io` |
|
||||
| `bench-func-*` | 6 | Пустые bench namespace-ы |
|
||||
| `testns` | 1 | Пустой тестовый namespace |
|
||||
| `fission` (ядро, helm) | 1 | `helm uninstall fission -n fission` |
|
||||
| `fission-functions` | 1 | Пустой |
|
||||
| CRD Fission | 8 | `canaryconfigs, environments, functions, httptriggers, kuberneteswatchtriggers, messagequeuetriggers, packages, timetriggers` |
|
||||
|
||||
### Итого удалено: ~84 namespace-а + 8 CRD
|
||||
|
||||
### Ресурсы после чистки
|
||||
|
||||
| Нода | CPU req | CPU limits | MEM limits |
|
||||
|---|---|---|---|
|
||||
| `6f74n` | 19% | 97% | 36% |
|
||||
| `sc8p5` | 19% | 115% | 39% |
|
||||
| `v8zq4` | 20% | 126% | 55% |
|
||||
|
||||
**Свободно: ~19 ядер, ~41 Gi памяти**
|
||||
|
||||
---
|
||||
|
||||
## Кластер: naeel-test-3 (185.247.187.146)
|
||||
|
||||
### Удалено
|
||||
|
||||
| Группа | Штук | Причина |
|
||||
|---|---|---|
|
||||
| `sless-fn-cmp-op-*` | 20 | Пустые namespace-ы, 52 дня |
|
||||
| `sless-fn-test001` | 1 | SQS test, воссоздавался через `queueservice.sqs.kube5s.ru` CRD — удалили CRD `test-tenant-001` |
|
||||
| `sless-fn-test002` | 1 | Пустой |
|
||||
| `sless-16367aacb67a4a01` | 1 | Пустой |
|
||||
| `sless-fn-timing-ts` | 1 | SQS timing. Удалён CRD `test-tenant-timing-ts` + namespace |
|
||||
| `sless` | 1 | IoT платформа (Kafka OOMKilled, 100 рестартов) |
|
||||
| `shared-sqs` | 1 | SQS consumer |
|
||||
| `sqs-operator-system` | 1 | SQS оператор |
|
||||
| `1dbfe9da-...` | 1 | RabbitMQ managed |
|
||||
|
||||
### Починено: metrics-server
|
||||
|
||||
Проблема: 0/1 Ready 70 дней. Три бага платформы shturval:
|
||||
|
||||
1. **TLS**: kubelet-сертификаты без IP SANs → `--kubelet-insecure-tls`
|
||||
2. **readOnlyRootFilesystem**: не может создать `/apiserver.local.config` → `--cert-dir=/tmp` + `volumeMount: /tmp`
|
||||
3. **runAsNonRoot 1000**: порт 443 недоступен → `--secure-port=4443` + пробы HTTP:4443 + сервис `targetPort: 4443`
|
||||
|
||||
Итоговый deployment metrics-server:
|
||||
```yaml
|
||||
args:
|
||||
- --kubelet-insecure-tls
|
||||
- --kubelet-preferred-address-types=InternalIP
|
||||
- --cert-dir=/tmp
|
||||
- --secure-port=4443
|
||||
volumeMounts:
|
||||
- mountPath: /tmp
|
||||
name: tmp-dir
|
||||
volumes:
|
||||
- name: tmp-dir
|
||||
emptyDir: {}
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: 4443
|
||||
scheme: HTTP
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /livez
|
||||
port: 4443
|
||||
scheme: HTTP
|
||||
```
|
||||
|
||||
Service `metrics-server`:
|
||||
```yaml
|
||||
ports:
|
||||
- port: 443
|
||||
targetPort: 4443
|
||||
```
|
||||
|
||||
### Lucee
|
||||
|
||||
- Задеплоен в namespace `3d7657ee-...` → 1/1 Ready
|
||||
- Домен: `lucee-mfysayo333` (ошибка была `lucee-mysayo333`)
|
||||
- Платформа: `naeel-test-3`
|
||||
- git: `https://github.com/xahys/testlucee`
|
||||
- jsonEnv: оставлен пустым (формат KEY=VALUE, не JSON)
|
||||
|
||||
### Ресурсы после чистки (worker-ноды, 12 ядер total)
|
||||
|
||||
| Нода | CPU req | MEM req |
|
||||
|---|---|---|
|
||||
| `vxzch` | 6% | 7% |
|
||||
| `wwqj2` | 30% | 25% |
|
||||
| `zxnb4` | 37% | 29% |
|
||||
|
||||
---
|
||||
|
||||
## Важные уроки
|
||||
|
||||
1. **Fission**: Недостаточно `kubectl delete ns` — нужно сначала удалить CRD `environments`, иначе poolmgr воссоздаст namespace
|
||||
2. **SQS operator**: Недостаточно удалить namespace — нужно удалить CRD `queueservice` в `sqs-operator-system`
|
||||
3. **Удаление с finalizer**: Зависшие Terminating форсировать через `kubectl replace --raw /api/v1/namespaces/$ns/finalize`
|
||||
4. **metrics-server от shturval**: Имеет три бага из коробки, несовместим с security policy платформы
|
||||
@@ -1,51 +0,0 @@
|
||||
# Деплой на ВМ (отладка)
|
||||
|
||||
> 2026-06-02. Временное решение пока NodeJS-платформа не готова.
|
||||
|
||||
## Git — без изменений
|
||||
|
||||
Локально → `git add` + `git commit` + `git push` → gitea.services.ngcloud.ru/Nail/ipwhitelist-app.git
|
||||
|
||||
## Схема деплоя
|
||||
|
||||
```
|
||||
Локально (правки) → git push → gitea
|
||||
↓
|
||||
git pull на ВМ
|
||||
↓
|
||||
pm2 restart ipwhitelist
|
||||
↓
|
||||
https://italo.kube5s.ru (nginx → :3000)
|
||||
```
|
||||
|
||||
## ВМ
|
||||
|
||||
- IP: `5.172.178.213`
|
||||
- SSH: `ssh -i ~/.ssh/naeel_vm_id_ed25519 naeel@5.172.178.213`
|
||||
- Nginx: `/etc/nginx/conf.d/italo.kube5s.ru.conf` → `proxy_pass http://127.0.0.1:3000`
|
||||
- PM2: `pm2 start server.js --name ipwhitelist`
|
||||
|
||||
## PostgreSQL
|
||||
|
||||
Локальный на ВМ. `.env`: `DB_HOST=localhost`.
|
||||
|
||||
## Отличия от боевого деплоя
|
||||
|
||||
| Параметр | ВМ (отладка) | K8s (бой) |
|
||||
|---|---|---|
|
||||
| DB_HOST | `localhost` | `postgresqlk8s-master...svc.cluster.local` |
|
||||
| Аутентификация | Mock (DEV_MODE=true) | OIDC Keycloak |
|
||||
| URL | `https://italo.kube5s.ru` | `https://wipl...` (платформа) |
|
||||
| SSL | Let's Encrypt (kube5s.ru) | Платформа |
|
||||
| Деплой | rsync + git pull | Платформа (git clone) |
|
||||
|
||||
## Передача заказчику
|
||||
|
||||
После отладки:
|
||||
1. Репа: `https://gitea.services.ngcloud.ru/Nail/ipwhitelist-app.git`
|
||||
2. Схема БД: `sql/schema.sql`
|
||||
3. Документация: `docs/`
|
||||
- `ТЗ.md` — техзадание
|
||||
- `ТЗ-плюс.md` — уточнения
|
||||
- `keycloak-auth-reference.md` — OIDC-интеграция
|
||||
4. Тесты: `node tests/api.js` (121 тест)
|
||||
@@ -1,112 +0,0 @@
|
||||
# Дизайн-система платформы Nubes
|
||||
|
||||
> Извлечено из сохранённой страницы `h.h` (deck-test.ngcloud.ru)
|
||||
|
||||
---
|
||||
|
||||
## Сетка и контейнеры
|
||||
|
||||
| Элемент | Класс | Описание |
|
||||
|---|---|---|
|
||||
| Страница | `navigation:flex`, `services:grid` | Flex/grid на всём |
|
||||
| Карточка | `ui-kit:bg-card ui-kit:rounded-xl ui-kit:border ui-kit:shadow-sm` | Белая карточка, border-radius 12px |
|
||||
| Заголовок карточки | `ui-kit:bg-brand-grey-light ui-kit:px-3 ui-kit:py-3` | Серый фон `#f3f4f6`, padding 12px |
|
||||
| Тело карточки | `ui-kit:px-3 ui-kit:py-3` | padding 12px |
|
||||
|
||||
---
|
||||
|
||||
## Цвета (переменные)
|
||||
|
||||
| Переменная | Назначение | Примерный HEX |
|
||||
|---|---|---|
|
||||
| `--brand-primary` | Основной цвет | `#2563eb` (синий) |
|
||||
| `--brand-gray` | Цвет границ | `#d1d5db` |
|
||||
| `--brand-grey-light` | Фон заголовков | `#f3f4f6` |
|
||||
| `--brand-primary-dark` | Ховер ссылок | `#1d4ed8` |
|
||||
|
||||
---
|
||||
|
||||
## Формы
|
||||
|
||||
```
|
||||
form-table (класс services:):
|
||||
grid-template-columns: fit-content(200px) minmax(200px, 1fr) 0px
|
||||
gap: 8px 16px
|
||||
```
|
||||
|
||||
| Элемент | Класс | Стиль |
|
||||
|---|---|---|
|
||||
| Лейбл | `ui-kit:text-sm ui-kit:leading-none ui-kit:font-normal ui-kit:mb-1 ui-kit:ml-1` | 14px, sans-serif, отступ слева |
|
||||
| Инпут | `ui-kit:h-9 ui-kit:rounded-md ui-kit:border ui-kit:px-3 ui-kit:text-sm` | h=36px, border, padding |
|
||||
| Текстареа | `ui-kit:rounded-md ui-kit:border ui-kit:px-3 ui-kit:py-2 ui-kit:text-sm` | авто-height |
|
||||
|
||||
---
|
||||
|
||||
## Кнопки
|
||||
|
||||
| Тип | Стиль | Класс |
|
||||
|---|---|---|
|
||||
| Обычная | border, bg-white, hover:bg-accent | `ui-kit:border ui-kit:bg-background ui-kit:h-8 ui-kit:rounded-md` |
|
||||
| Удалить | bg-destructive, text-white | `ui-kit:bg-destructive ui-kit:text-white` |
|
||||
| Иконка | size-5 | `ui-kit:size-5 ui-kit:cursor-pointer` |
|
||||
|
||||
Все кнопки: `ui-kit:h-8 ui-kit:rounded-md ui-kit:gap-1.5 ui-kit:px-3`, 14px шрифт.
|
||||
|
||||
---
|
||||
|
||||
## Таблицы
|
||||
|
||||
| Элемент | Стиль |
|
||||
|---|---|
|
||||
| Обёртка | `ui-kit:rounded-md ui-kit:border ui-kit:overflow-hidden` |
|
||||
| Шапка (th) | `ui-kit:bg-brand-grey-light`, uppercase, `ui-kit:py-1 ui-kit:px-2`, border-right |
|
||||
| Ячейка (td) | `ui-kit:px-2 ui-kit:py-1`, border-right, border-bottom |
|
||||
| Строка (tr) | `ui-kit:border-b ui-kit:border-brand-gray-8`, hover: `ui-kit:bg-brand-grey-light/50` |
|
||||
|
||||
---
|
||||
|
||||
## Иконки
|
||||
|
||||
Используются: **Lucide** (`lucide-*`)
|
||||
|
||||
Часто используемые:
|
||||
- `lucide-square-pen` — редактировать
|
||||
- `lucide-rotate-cw` — перезапустить
|
||||
- `lucide-trash` — удалить
|
||||
- `lucide-pause` — остановить
|
||||
- `lucide-play` — запустить
|
||||
- `lucide-save` — сохранить
|
||||
- `lucide-x` — закрыть
|
||||
- `lucide-copy` — копировать
|
||||
- `lucide-check` — успех (зелёный)
|
||||
- `lucide-x` — ошибка (красный)
|
||||
|
||||
---
|
||||
|
||||
## Типографика
|
||||
|
||||
- Основной шрифт: system-ui (Segoe UI, Roboto, etc.)
|
||||
- Размер: `text-sm` = 14px, `text-base` = 16px
|
||||
- Межстрочный: `leading-none` (1), `leading-normal` (1.5)
|
||||
- Цвет текста: `#1a1a1a`
|
||||
- Muted: `text-muted-foreground` = серый `#6b7280`
|
||||
- Заголовки карточек: `font-semibold`, 16px
|
||||
|
||||
---
|
||||
|
||||
## Навигация (слева)
|
||||
|
||||
- Ширина: `var(--sidebar-width)` = 12rem (192px)
|
||||
- Свёрнуто: `var(--sidebar-width-icon)` = 4.5rem (72px)
|
||||
- Верхняя панель: h-20 (80px), border-t-4 border-t-blue-500
|
||||
- Лого: инлайн SVG, 150px ширина
|
||||
|
||||
---
|
||||
|
||||
## Состояния
|
||||
|
||||
| Статус | Цвет |
|
||||
|---|---|
|
||||
| Успех / running | `text-green-500` + иконка `lucide-check` |
|
||||
| Ошибка | `text-red-500` + иконка `lucide-x` |
|
||||
| Предупреждение | `text-amber-500` |
|
||||
@@ -1,61 +0,0 @@
|
||||
#!/bin/bash
|
||||
# API-тесты: все комбинации (без UI)
|
||||
# Запуск: bash docs/test-api.sh
|
||||
|
||||
BASE="https://white.nodejsk8s.dev.nubes.ru"
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
green() { echo -e "\033[32m$1\033[0m"; }
|
||||
red() { echo -e "\033[31m$1\033[0m"; }
|
||||
|
||||
check() { # check "описание" expected actual
|
||||
if [ "$2" = "$3" ]; then
|
||||
green " ✓ $1"
|
||||
PASS=$((PASS+1))
|
||||
else
|
||||
red " ✗ $1 (ожидалось: $2, получено: $3)"
|
||||
FAIL=$((FAIL+1))
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Получить mock JWT для заданного clientId ───────────────────
|
||||
get_token() {
|
||||
local CLIENT_ID="$1"
|
||||
# POST /dev-login для получения токена через API
|
||||
# Возвращает access_token из ответа
|
||||
local RESP=$(curl -s -c /tmp/jar-test.txt "$BASE/login" > /dev/null && \
|
||||
curl -s -b /tmp/jar-test.txt -c /tmp/jar-test.txt \
|
||||
-X POST "$BASE/login" \
|
||||
-d "clientId=$CLIENT_ID" \
|
||||
-D - 2>&1)
|
||||
# Извлечь токен из редиректа (он в сессии, получаем через API)
|
||||
# Используем /dev-login для прямого получения токена
|
||||
local CSRF=$(curl -s -b /tmp/jar-test.txt "$BASE/dev-login" | grep -oP 'name="_csrf" value="\K[^"]+')
|
||||
curl -s -b /tmp/jar-test.txt -c /tmp/jar-test.txt \
|
||||
-X POST "$BASE/dev-login" \
|
||||
-d "clientId=$CLIENT_ID&_csrf=$CSRF&email=test@test.local&companyName=TestCo" \
|
||||
> /dev/null
|
||||
# Получить api-токен через сессию
|
||||
# Пробуем получить через /login page (там токен генерится в сессию)
|
||||
# Возвращаем токен из cookie
|
||||
echo "TODO"
|
||||
}
|
||||
|
||||
echo "========================================="
|
||||
echo " API Tests v0.5.4"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
|
||||
# ── 1. Без токена → 401 ────────────────────────────────────────
|
||||
echo "--- 1. No token → 401 ---"
|
||||
CODE=$(curl -s -o /dev/null -w '%{http_code}' "$BASE/api/v1/entries")
|
||||
check "GET /entries без токена" "401" "$CODE"
|
||||
|
||||
CODE=$(curl -s -o /dev/null -w '%{http_code}' -X POST "$BASE/api/v1/entries" -H 'Content-Type: application/json' -d '{"value":"1.1.1.1/32"}')
|
||||
check "POST /entries без токена" "401" "$CODE"
|
||||
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo " Результат: $PASS/$((PASS+FAIL))"
|
||||
echo "========================================="
|
||||
@@ -1,104 +0,0 @@
|
||||
# Тесты: мульти-компания (2026-06-02)
|
||||
|
||||
> Запускать против `https://white.nodejsk8s.dev.nubes.ru`
|
||||
> Куки сохраняются между запросами (использовать `-c jar.txt -b jar.txt`)
|
||||
|
||||
## 1. Логин под мульти-компанией
|
||||
|
||||
```bash
|
||||
# Получить CSRF-токен и логин-форму
|
||||
curl -s -c jar.txt https://white.nodejsk8s.dev.nubes.ru/login > /dev/null
|
||||
|
||||
# Извлечь CSRF-токен
|
||||
CSRF=$(curl -s -b jar.txt https://white.nodejsk8s.dev.nubes.ru/login | grep -oP 'name="_csrf" value="\K[^"]+')
|
||||
|
||||
# Залогиниться как "multi"
|
||||
curl -s -b jar.txt -c jar.txt \
|
||||
-X POST https://white.nodejsk8s.dev.nubes.ru/login \
|
||||
-d "user=multi&_csrf=$CSRF" \
|
||||
-D - | head -1
|
||||
# Ожидаем: HTTP/1.1 302 → /
|
||||
|
||||
# Проверить что сессия содержит allClientIds
|
||||
curl -s -b jar.txt https://white.nodejsk8s.dev.nubes.ru/ | grep -c 'WZ01325'
|
||||
# Ожидаем: >0 (активная компания в интерфейсе)
|
||||
```
|
||||
|
||||
## 2. Переключатель компаний в UI
|
||||
|
||||
```bash
|
||||
# Страница должна содержать переключатель (<select name="switchTo">)
|
||||
curl -s -b jar.txt https://white.nodejsk8s.dev.nubes.ru/ | grep -c 'switchTo'
|
||||
# Ожидаем: >0
|
||||
|
||||
# Должны быть обе компании в options
|
||||
curl -s -b jar.txt https://white.nodejsk8s.dev.nubes.ru/ | grep -o 'WZ0[0-9]*'
|
||||
# Ожидаем: WZ01325 и WZ02001
|
||||
|
||||
# Переключиться на WZ02001
|
||||
curl -s -b jar.txt -c jar.txt \
|
||||
https://white.nodejsk8s.dev.nubes.ru/?switchTo=WZ02001 \
|
||||
> /dev/null
|
||||
|
||||
# Проверить что активная компания — WZ02001
|
||||
curl -s -b jar.txt https://white.nodejsk8s.dev.nubes.ru/ | grep -c 'WZ02001'
|
||||
# Ожидаем: >0
|
||||
```
|
||||
|
||||
## 3. Добавление записи в активную компанию
|
||||
|
||||
```bash
|
||||
# Создать запись в WZ02001 (после переключения на неё)
|
||||
CSRF=$(curl -s -b jar.txt https://white.nodejsk8s.dev.nubes.ru/ | grep -oP 'name="_csrf" value="\K[^"]+')
|
||||
|
||||
curl -s -b jar.txt -c jar.txt \
|
||||
-X POST https://white.nodejsk8s.dev.nubes.ru/add \
|
||||
-d "value=8.8.8.8/32&comment=multi-test&_csrf=$CSRF" \
|
||||
-D - | head -1
|
||||
# Ожидаем: HTTP/1.1 302
|
||||
|
||||
# Проверить что запись появилась в WZ02001
|
||||
curl -s -b jar.txt https://white.nodejsk8s.dev.nubes.ru/ | grep -c '8.8.8.8'
|
||||
# Ожидаем: >0
|
||||
```
|
||||
|
||||
## 4. Проверка изоляции компаний
|
||||
|
||||
```bash
|
||||
# Переключиться обратно на WZ01325
|
||||
curl -s -b jar.txt -c jar.txt \
|
||||
https://white.nodejsk8s.dev.nubes.ru/?switchTo=WZ01325 \
|
||||
> /dev/null
|
||||
|
||||
# Запись 8.8.8.8 из WZ02001 НЕ должна быть видна в WZ01325
|
||||
curl -s -b jar.txt https://white.nodejsk8s.dev.nubes.ru/ | grep -c '8.8.8.8'
|
||||
# Ожидаем: 0
|
||||
```
|
||||
|
||||
## 5. API Bearer-тест (опционально)
|
||||
|
||||
```bash
|
||||
# Выпустить mock JWT с clientid через запятую
|
||||
# (требует ручной JWT через /dev-login или issueMockToken)
|
||||
# Затем:
|
||||
curl -s -H "Authorization: Bearer <mock-jwt>" \
|
||||
https://white.nodejsk8s.dev.nubes.ru/api/v1/entries | jq .
|
||||
# Ожидаем: записи для первой компании (WZ01325)
|
||||
```
|
||||
|
||||
## 6. Негативные тесты
|
||||
|
||||
```bash
|
||||
# Переключение на несуществующую компанию — игнорируется
|
||||
curl -s -b jar.txt -c jar.txt \
|
||||
https://white.nodejsk8s.dev.nubes.ru/?switchTo=WZ99999 \
|
||||
> /dev/null
|
||||
|
||||
# Должен остаться на WZ01325
|
||||
curl -s -b jar.txt https://white.nodejsk8s.dev.nubes.ru/ | grep -c 'WZ01325'
|
||||
# Ожидаем: >0
|
||||
|
||||
# Одиночная компания (test, не multi) — переключателя быть не должно
|
||||
# Залогиниться как test и проверить:
|
||||
# grep -c 'switchTo' → ожидаем 0
|
||||
```
|
||||
Reference in New Issue
Block a user