v0.5.13: gitignore разработческих файлов (DevOps-чистота)

This commit is contained in:
2026-06-03 06:19:55 +03:00
parent 8feabc339d
commit 2841e3ac27
194 changed files with 16 additions and 47323 deletions
-56
View File
@@ -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++, коммит
-110
View File
@@ -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 платформы
-51
View File
@@ -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 тест)
-112
View File
@@ -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` |
-61
View File
@@ -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 "========================================="
-104
View File
@@ -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
```