chore(#16): skeleton репозитория — README, Makefile, линтеры, зависимости
This commit is contained in:
@@ -0,0 +1,22 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.py]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
max_line_length = 100
|
||||||
|
|
||||||
|
[*.{yml,yaml,json,ts,tsx,js,css,html}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[Makefile]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
.venv/
|
||||||
|
.venv*/
|
||||||
|
*.egg-info/
|
||||||
|
.pytest_cache/
|
||||||
|
.mypy_cache/
|
||||||
|
.ruff_cache/
|
||||||
|
.coverage
|
||||||
|
coverage.xml
|
||||||
|
htmlcov/
|
||||||
|
|
||||||
|
# UI
|
||||||
|
node_modules/
|
||||||
|
ui/dist/
|
||||||
|
ui/.vite/
|
||||||
|
|
||||||
|
# Runtime / состояние шлюза (живёт в томах, не в репозитории)
|
||||||
|
data/
|
||||||
|
config/
|
||||||
|
*.db
|
||||||
|
*.db-shm
|
||||||
|
*.db-wal
|
||||||
|
|
||||||
|
# Секреты и конфиги клиентов
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
*.conf
|
||||||
|
!deploy/*.conf.example
|
||||||
|
|
||||||
|
# IDE / OS
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
.DS_Store
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
repos:
|
||||||
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
|
rev: v0.6.9
|
||||||
|
hooks:
|
||||||
|
- id: ruff
|
||||||
|
args: [--fix]
|
||||||
|
- id: ruff-format
|
||||||
|
|
||||||
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
|
rev: v1.11.2
|
||||||
|
hooks:
|
||||||
|
- id: mypy
|
||||||
|
files: ^backend/
|
||||||
|
additional_dependencies: [pydantic>=2.9]
|
||||||
|
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: v4.6.0
|
||||||
|
hooks:
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
- id: trailing-whitespace
|
||||||
|
- id: check-yaml
|
||||||
|
- id: check-merge-conflict
|
||||||
|
- id: check-added-large-files
|
||||||
|
args: [--maxkb=512]
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
PY ?= python3
|
||||||
|
VENV ?= .venv
|
||||||
|
BIN := $(VENV)/bin
|
||||||
|
IMAGE ?= awg-dash:dev
|
||||||
|
COMPOSE_DEV := deploy/docker-compose.dev.yml
|
||||||
|
|
||||||
|
.PHONY: help venv lint fmt test build dev-up dev-down dev-logs test-netns
|
||||||
|
|
||||||
|
help:
|
||||||
|
@grep -E '^[a-zA-Z_-]+:' $(MAKEFILE_LIST) | sed 's/:.*//' | sort -u
|
||||||
|
|
||||||
|
venv:
|
||||||
|
$(PY) -m venv $(VENV)
|
||||||
|
$(BIN)/pip install -U pip
|
||||||
|
$(BIN)/pip install -r requirements-dev.txt
|
||||||
|
|
||||||
|
lint:
|
||||||
|
$(BIN)/ruff check backend
|
||||||
|
$(BIN)/mypy backend
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
$(BIN)/ruff format backend
|
||||||
|
$(BIN)/ruff check --fix backend
|
||||||
|
|
||||||
|
test:
|
||||||
|
$(BIN)/pytest
|
||||||
|
|
||||||
|
build:
|
||||||
|
@test -f deploy/Dockerfile || { echo 'deploy/Dockerfile ещё нет — задача #18'; exit 1; }
|
||||||
|
docker build -f deploy/Dockerfile -t $(IMAGE) .
|
||||||
|
|
||||||
|
dev-up:
|
||||||
|
@test -f $(COMPOSE_DEV) || { echo '$(COMPOSE_DEV) ещё нет — задача #21'; exit 1; }
|
||||||
|
docker compose -f $(COMPOSE_DEV) up -d --build
|
||||||
|
|
||||||
|
dev-down:
|
||||||
|
docker compose -f $(COMPOSE_DEV) down
|
||||||
|
|
||||||
|
dev-logs:
|
||||||
|
docker compose -f $(COMPOSE_DEV) logs -f --tail=100
|
||||||
|
|
||||||
|
test-netns:
|
||||||
|
@test -d tests/netns || { echo 'tests/netns ещё нет — задача #21'; exit 1; }
|
||||||
|
bash tests/netns/run.sh
|
||||||
@@ -1,40 +1,64 @@
|
|||||||
# awg-dash
|
# awg-dash
|
||||||
|
|
||||||
# awg-dash 🚀
|
VPN-шлюз **AmneziaWG** с интеллектуальной маршрутизацией: один Docker-образ = туннель + policy routing + split-tunnel (GeoIP / DNS) + REST API v1 + Web UI (тёмная тема).
|
||||||
|
|
||||||
**awg-dash** — это легковесная и удобная веб-панель (Dashboard) для визуального управления сервером **Amnezia WireGuard (AWG)**. Она позволяет создавать, удалять и просматривать конфигурации пользователей в один клик через современный веб-интерфейс, защищенный от блокировок.
|
- Эпик и декомпозиция: Gitea issue **#15** (`embeddevio/awg-dash`).
|
||||||
|
- Исполнение: Hermes Kanban, борда **`awg-dash`** (`hermes kanban --board awg-dash list`).
|
||||||
|
- PoC-референс: `embeddevio/amneziawg-docker-gateway` (bash + iptables, `docs/technical-specification.md`).
|
||||||
|
|
||||||
[](https://opensource.org)
|
## Архитектура
|
||||||
[](https://github.com)
|
|
||||||
|
|
||||||
---
|
Два процесса в одном образе:
|
||||||
|
|
||||||
## ✨ Особенности / Features
|
| Процесс | Пользователь | Ответственность |
|
||||||
|
|---|---|---|
|
||||||
|
| `awg-agent` | root | awg/wg-интерфейс, iptables/ipset, dnsmasq, policy routing, метрики |
|
||||||
|
| `awg-api` | непривилегированный | FastAPI: REST API v1, WebSocket, статика UI |
|
||||||
|
|
||||||
- 🛠️ **Полная поддержка Amnezia WireGuard:** Тонкая настройка параметров обфускации (`Jc`, `Jmin`, `Jmax`, `S1`, `S2`, `H1`, `H2`, `H3`, `H4`) прямо из панели.
|
Обмен — unix-socket `/run/awg/agent.sock`; состояние — SQLite в `/data`, конфиги `.conf` в `/config`.
|
||||||
- 👥 **Управление пользователями:** Создание, удаление, временная заморозка и управление лимитами пиров (клиентов).
|
Принятые решения зафиксированы в `docs/adr/`.
|
||||||
- 📊 **Мониторинг в реальном времени:** Графики потребления трафика, статус подключения клиентов и общая нагрузка на сервер.
|
|
||||||
- 📱 **QR-коды и конфиги:** Мгновенная генерация QR-кодов и скачивание `.conf` файлов для импорта в официальное приложение Amnezia.
|
|
||||||
- 🔒 **Безопасность:** Авторизация по паролю/токену, поддержка сессий и возможность работы за обратным прокси (Nginx, Caddy).
|
|
||||||
- 🐳 **Docker-first:** Быстрый запуск одной командой через Docker Compose.
|
|
||||||
|
|
||||||
---
|
## Быстрый старт (после релиза 1.0)
|
||||||
|
|
||||||
## 🛠️ Технологический стек / Tech Stack
|
```bash
|
||||||
|
docker run -dit --name=vpn-gateway \
|
||||||
|
--network=host \
|
||||||
|
--device=/dev/net/tun:/dev/net/tun \
|
||||||
|
--cap-add=NET_ADMIN --cap-add=SYS_MODULE \
|
||||||
|
--restart always \
|
||||||
|
-v /srv/awg/config:/config -v /srv/awg/data:/data \
|
||||||
|
registry.example.com/vpn-gateway:latest
|
||||||
|
```
|
||||||
|
|
||||||
- **Backend:** Node.js (Express) / Python (FastAPI) / Go *(выберите нужное)*
|
Web UI: `http://<host>:8080`. До релиза образ собирается локально: `make build`.
|
||||||
- **Frontend:** Vue.js / React / Простой HTML+JS *(выберите нужное)*
|
|
||||||
- **База данных:** SQLite / JSON-file (минималистично, без тяжелых БД)
|
|
||||||
- **Ядро:** Amnezia WireGuard (модифицированная утилита `wg`)
|
|
||||||
|
|
||||||
---
|
## Разработка
|
||||||
|
|
||||||
## 🚀 Быстрый старт / Quick Start
|
```bash
|
||||||
|
make venv # локальное окружение (.venv)
|
||||||
|
make lint # ruff + mypy
|
||||||
|
make test # pytest + coverage (порог 70%)
|
||||||
|
make build # docker build образа (задача #18)
|
||||||
|
make dev-up # dev-стенд (задача #21)
|
||||||
|
```
|
||||||
|
|
||||||
### Способ 1: Через Docker Compose (Рекомендуемый)
|
Сетевые тесты выполняются в netns-стенде (`tests/netns/`), без реального VPN-провайдера.
|
||||||
|
|
||||||
1. Клонируйте репозиторий:
|
## Структура репозитория
|
||||||
```bash
|
|
||||||
git clone https://github.com
|
| Путь | Назначение |
|
||||||
cd awg-dash
|
|---|---|
|
||||||
```
|
| `backend/awg_agent/` | привилегированный агент: туннель, маршрутизация, GeoIP, DNS, метрики |
|
||||||
|
| `backend/awg_api/` | FastAPI-приложение (REST + WS + статика UI) |
|
||||||
|
| `backend/tests/` | unit/integration-тесты (pytest) |
|
||||||
|
| `ui/` | React + TypeScript + Tailwind + shadcn-ui |
|
||||||
|
| `deploy/` | Dockerfile, compose-профили, entrypoint, Grafana-дашборд |
|
||||||
|
| `docs/adr/` | архитектурные решения |
|
||||||
|
| `tests/netns/` | сетевой тестовый стенд |
|
||||||
|
|
||||||
|
## Процесс разработки
|
||||||
|
|
||||||
|
1 задача = 1 issue = 1 ветка `feat/<issue>-slug` = 1 PR.
|
||||||
|
|
||||||
|
Гейты мержа: CI green, coverage нового кода ≥ 70 %, security scan low/none, ревью владельца роли.
|
||||||
|
Merge в `main` и деплой в prod — только TechLead после гейтов. Все операции с репозиторием — через Gitea MCP.
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
[project]
|
||||||
|
name = "awg-dash"
|
||||||
|
version = "0.0.1"
|
||||||
|
description = "AmneziaWG gateway with intelligent routing: REST API + Web UI + split-tunnel"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
dependencies = []
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
line-length = 100
|
||||||
|
target-version = "py312"
|
||||||
|
extend-exclude = ["ui", ".venv", "backend/tests"]
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
select = ["E", "F", "W", "I", "N", "UP", "B", "ASYNC", "S", "RUF"]
|
||||||
|
ignore = ["S101"]
|
||||||
|
|
||||||
|
[tool.ruff.lint.per-file-ignores]
|
||||||
|
"backend/tests/*" = ["S", "D"]
|
||||||
|
|
||||||
|
[tool.mypy]
|
||||||
|
python_version = "3.12"
|
||||||
|
mypy_path = "backend"
|
||||||
|
files = ["backend"]
|
||||||
|
strict = true
|
||||||
|
ignore_missing_imports = true
|
||||||
|
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
testpaths = ["backend/tests"]
|
||||||
|
pythonpath = ["backend"]
|
||||||
|
addopts = "-q --cov=awg_agent --cov=awg_api --cov-report=term-missing --cov-fail-under=70"
|
||||||
|
asyncio_mode = "auto"
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
-r requirements.txt
|
||||||
|
|
||||||
|
ruff>=0.6.9
|
||||||
|
mypy>=1.11
|
||||||
|
pytest>=8.3
|
||||||
|
pytest-cov>=5.0
|
||||||
|
pytest-asyncio>=0.24
|
||||||
|
pre-commit>=3.8
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Runtime (контроль-плоскость)
|
||||||
|
fastapi>=0.115
|
||||||
|
uvicorn[standard]>=0.32
|
||||||
|
pydantic>=2.9
|
||||||
|
pydantic-settings>=2.5
|
||||||
|
aiosqlite>=0.20
|
||||||
|
httpx>=0.27
|
||||||
|
structlog>=24.4
|
||||||
|
prometheus-client>=0.21
|
||||||
|
|
||||||
|
# Сетевой слой вызывается через бинари (awg, iptables, ipset, dnsmasq),
|
||||||
|
# поэтому python-зависимостей для сети не требуется.
|
||||||
Reference in New Issue
Block a user