Compare commits
23 commits
main
...
smm-instal
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4ec88923b | ||
|
|
7b9cc79c53 | ||
|
|
e51c2b9bc1 | ||
|
|
0009e9f5e9 | ||
|
|
4e8abf82c3 | ||
|
|
b0a0726e5c | ||
|
|
5d4e8f063d | ||
|
|
3d153aa7b0 | ||
|
|
7191d54a40 | ||
|
|
a0d539b1f6 | ||
|
|
ae1c0741e5 | ||
|
|
7b11ce9da2 | ||
|
|
b18d834c9f | ||
|
|
4baf8f8b3c | ||
|
|
01968d79a7 | ||
|
|
71cc35e986 | ||
|
|
78e650a35b | ||
|
|
66b9c3730e | ||
|
|
4016d0e7e7 | ||
|
|
5bce599d2f | ||
|
|
d50d28369a | ||
|
|
29afdbeb6d | ||
|
|
9289eb8a13 |
14 changed files with 2119 additions and 0 deletions
15
.github/workflows/bash-syntax.yml
vendored
15
.github/workflows/bash-syntax.yml
vendored
|
|
@ -46,3 +46,18 @@ jobs:
|
||||||
|
|
||||||
- name: Test step 8 AI agent catalog
|
- name: Test step 8 AI agent catalog
|
||||||
run: bash tests/test-step8-agent-catalog.sh
|
run: bash tests/test-step8-agent-catalog.sh
|
||||||
|
|
||||||
|
- name: Test Server Monitor Manager enrollment
|
||||||
|
run: bash tests/test-monitor-manager-enrollment.sh
|
||||||
|
|
||||||
|
- name: Test Server Monitor Manager Link policies
|
||||||
|
run: bash tests/test-monitor-manager-links.sh
|
||||||
|
|
||||||
|
- name: Test Server Monitor Manager lifecycle
|
||||||
|
run: bash tests/test-monitor-manager-lifecycle.sh
|
||||||
|
|
||||||
|
- name: Test Server Monitor Manager extended metrics
|
||||||
|
run: bash tests/test-monitor-manager-metrics.sh
|
||||||
|
|
||||||
|
- name: Test Server Monitor Manager control layer installer
|
||||||
|
run: bash tests/test-monitor-manager-control-layer.sh
|
||||||
|
|
|
||||||
40
.github/workflows/monitor-manager-e2e.yml
vendored
Normal file
40
.github/workflows/monitor-manager-e2e.yml
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
name: Server Monitor Manager E2E
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ['**']
|
||||||
|
paths:
|
||||||
|
- 'ochenstarik-server-monitor-manager.sh'
|
||||||
|
- 'tests/e2e/**'
|
||||||
|
- '.github/workflows/monitor-manager-e2e.yml'
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- 'ochenstarik-server-monitor-manager.sh'
|
||||||
|
- 'tests/e2e/**'
|
||||||
|
- '.github/workflows/monitor-manager-e2e.yml'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
wireguard-nftables:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Install kernel networking tools
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y wireguard-tools nftables iproute2 netcat-openbsd
|
||||||
|
|
||||||
|
- name: Test real WireGuard and nftables data path
|
||||||
|
run: sudo bash tests/e2e/test-monitor-manager-wireguard-nftables.sh
|
||||||
|
|
||||||
|
reinstall-reboot:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Test repeated install and systemd reboot
|
||||||
|
run: bash tests/e2e/test-monitor-manager-systemd-reinstall.sh
|
||||||
43
.github/workflows/monitor-manager-release.yml
vendored
Normal file
43
.github/workflows/monitor-manager-release.yml
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
name: Server Monitor Manager installer release
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'smm-installer-v*'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
package:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Validate installer
|
||||||
|
run: bash -n ochenstarik-server-monitor-manager.sh
|
||||||
|
|
||||||
|
- name: Create installer checksum
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -Eeuo pipefail
|
||||||
|
install -d dist
|
||||||
|
install -m 0755 ochenstarik-server-monitor-manager.sh dist/ochenstarik-server-monitor-manager.sh
|
||||||
|
cd dist
|
||||||
|
sha256sum ochenstarik-server-monitor-manager.sh > SHA256SUMS
|
||||||
|
sha256sum --check SHA256SUMS
|
||||||
|
|
||||||
|
- name: Upload installer artifact
|
||||||
|
uses: actions/upload-artifact@v6
|
||||||
|
with:
|
||||||
|
name: ochenstarik-server-monitor-manager-installer
|
||||||
|
path: dist/*
|
||||||
|
|
||||||
|
- name: Attach installer to GitHub Release
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
prerelease: ${{ contains(github.ref_name, '-') }}
|
||||||
|
files: dist/*
|
||||||
80
README.md
80
README.md
|
|
@ -51,7 +51,9 @@ The wizard intentionally requires all module scripts to be present locally. Use
|
||||||
| `ochenstarik-server-panel-warp-6.sh` | 3x-ui panel and local Cloudflare WARP proxy | Optional |
|
| `ochenstarik-server-panel-warp-6.sh` | 3x-ui panel and local Cloudflare WARP proxy | Optional |
|
||||||
| `ochenstarik-server-backup-7.sh` | Protected initial snapshot and selected daily, weekly, or monthly schedules | Optional |
|
| `ochenstarik-server-backup-7.sh` | Protected initial snapshot and selected daily, weekly, or monthly schedules | Optional |
|
||||||
| `ochenstarik-server-ai-agents-8.sh` | Installs selected AI agents: Hermes, OpenClaw, OpenHands, OpenCode, Aider, AutoGPT, or Pi Coding Agent | Optional |
|
| `ochenstarik-server-ai-agents-8.sh` | Installs selected AI agents: Hermes, OpenClaw, OpenHands, OpenCode, Aider, AutoGPT, or Pi Coding Agent | Optional |
|
||||||
|
| `ochenstarik-server-monitor-manager.sh` | Installs the Server Monitor Manager SSH endpoint, public WireGuard Hub, or outbound-only Node | Optional; Hub needs a public UDP endpoint |
|
||||||
| `ochenstarik-server-uninstall.sh` | Removes project-managed settings so installation can start again | Use carefully |
|
| `ochenstarik-server-uninstall.sh` | Removes project-managed settings so installation can start again | Use carefully |
|
||||||
|
| `ochenstarik-server-monitor-manager.sh` | Installs monitoring-only, Hub, or Node roles for Server Monitor Manager | Yes |
|
||||||
|
|
||||||
Every module can be run independently from the full archive or cloned repository:
|
Every module can be run independently from the full archive or cloned repository:
|
||||||
|
|
||||||
|
|
@ -63,6 +65,84 @@ sudo ./SCRIPT_NAME.sh
|
||||||
|
|
||||||
Replace `SCRIPT_NAME.sh` with the required filename from the table.
|
Replace `SCRIPT_NAME.sh` with the required filename from the table.
|
||||||
|
|
||||||
|
The Server Monitor Manager installer supports repeatable role-aware commands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh install-monitor
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh install-hub
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh install-node
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh status
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh update
|
||||||
|
```
|
||||||
|
|
||||||
|
Release artifacts include `SHA256SUMS`. Verify the installer before running it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sha256sum --check SHA256SUMS
|
||||||
|
```
|
||||||
|
|
||||||
|
## Server Monitor Manager Hub and Nodes
|
||||||
|
|
||||||
|
The Hub needs a public IPv4 address or domain and an open UDP port (default `51820`). Secondary Nodes establish outbound WireGuard connections and do not need a public IP.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fLO https://raw.githubusercontent.com/ochenstarik-ui/lightweight-server/main/ochenstarik-server-monitor-manager.sh
|
||||||
|
chmod 700 ochenstarik-server-monitor-manager.sh
|
||||||
|
bash -n ochenstarik-server-monitor-manager.sh
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh hub
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a separate 10-minute enrollment code for each Node on the Hub, then run the same installer with `node` on the matching server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ochenstarik-smm node-code ai-agent
|
||||||
|
sudo ochenstarik-smm node-code home
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh node
|
||||||
|
```
|
||||||
|
|
||||||
|
Links are directional. The reverse direction requires its own rule:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ochenstarik-smm link-connect ai-agent home tcp 22 120
|
||||||
|
sudo ochenstarik-smm link-disconnect ai-agent home tcp 22
|
||||||
|
sudo ochenstarik-smm nodes
|
||||||
|
sudo ochenstarik-smm links
|
||||||
|
```
|
||||||
|
|
||||||
|
The Node installer creates its private WireGuard key locally and prints an `SMMREQ1` request. In a second terminal run `sudo ochenstarik-smm node-enroll` on the Hub, paste the request at the hidden prompt, and return the resulting `SMMACK1` code to the Node installer. The enrollment code expires after 10 minutes and is consumed by the first successful registration.
|
||||||
|
|
||||||
|
Role-aware maintenance commands create a root-only backup before destructive changes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh update
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh rollback
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh uninstall-node
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh uninstall-hub
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh uninstall-monitor
|
||||||
|
```
|
||||||
|
|
||||||
|
### Experimental persistent control layer
|
||||||
|
|
||||||
|
The first persistent Hub/Agent layer is available as an alpha for three-server testing. It uses self-contained single-file binaries, SQLite on the Hub, one-time enrollment codes, and outbound mTLS heartbeats from Nodes. The existing SSH/WireGuard layer remains installed as a fallback while this alpha is tested.
|
||||||
|
|
||||||
|
Install the Control service after the WireGuard Hub:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh install-control-hub
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh control-code home
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh control-device-code windows-pc
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy the resulting `SMMCTL1-...` code and install the Agent on the matching Node:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh install-control-agent
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a new code for every Node. The code contains the public Control CA certificate but never its private key. Release archives are verified against their published SHA-256 checksums before installation. The Hub listens on TCP `7443`; allow this port at the hosting provider firewall if an external firewall is used.
|
||||||
|
|
||||||
|
`control-device-code` creates a separate operator identity for the Windows application. Agent certificates cannot list all servers, change Links, or subscribe to the operator event stream. The Control service can invoke only the dedicated `link-connect` and `link-disconnect` policy wrapper through sudo; other Hub administration commands are not granted to it.
|
||||||
|
|
||||||
## Installation flow
|
## Installation flow
|
||||||
|
|
||||||
1. Select the wizard dialog language.
|
1. Select the wizard dialog language.
|
||||||
|
|
|
||||||
|
|
@ -49,10 +49,51 @@ sudo ./ochenstarik-server-install.sh
|
||||||
| `ochenstarik-server-panel-warp-6.sh` | Устанавливает 3x-ui и Cloudflare WARP, настраивает и проверяет их порты | Ubuntu 22.04/24.04/26.04 или Debian 12/13 |
|
| `ochenstarik-server-panel-warp-6.sh` | Устанавливает 3x-ui и Cloudflare WARP, настраивает и проверяет их порты | Ubuntu 22.04/24.04/26.04 или Debian 12/13 |
|
||||||
| `ochenstarik-server-backup-7.sh` | Создаёт неизменяемый первичный снимок и настраивает выбранные расписания резервного копирования | Да; зависимости устанавливаются автоматически |
|
| `ochenstarik-server-backup-7.sh` | Создаёт неизменяемый первичный снимок и настраивает выбранные расписания резервного копирования | Да; зависимости устанавливаются автоматически |
|
||||||
| `ochenstarik-server-ai-agents-8.sh` | Устанавливает выбранных AI-агентов: Hermes, OpenClaw, OpenHands, OpenCode, Aider, AutoGPT или Pi Coding Agent | Да; API-ключи настраиваются отдельно |
|
| `ochenstarik-server-ai-agents-8.sh` | Устанавливает выбранных AI-агентов: Hermes, OpenClaw, OpenHands, OpenCode, Aider, AutoGPT или Pi Coding Agent | Да; API-ключи настраиваются отдельно |
|
||||||
|
| `ochenstarik-server-monitor-manager.sh` | Устанавливает SSH endpoint, главный WireGuard Hub или подключаемый Node для Server Monitor Manager | Да; Hub требуется публичный UDP-адрес |
|
||||||
| `ochenstarik-server-uninstall.sh` | Удаляет настройки, службы и данные проекта для повторной установки с начала | Да; запускать только из сохранённой SSH-сессии |
|
| `ochenstarik-server-uninstall.sh` | Удаляет настройки, службы и данные проекта для повторной установки с начала | Да; запускать только из сохранённой SSH-сессии |
|
||||||
|
|
||||||
Файлы `*.env.example` являются только примерами. Не записывайте настоящие пароли, токены и приватные SSH-ключи в Git.
|
Файлы `*.env.example` являются только примерами. Не записывайте настоящие пароли, токены и приватные SSH-ключи в Git.
|
||||||
|
|
||||||
|
## Server Monitor Manager: Hub и вторичные серверы
|
||||||
|
|
||||||
|
Главному Hub нужен белый IPv4 или домен и открытый UDP-порт (по умолчанию `51820`). Вторичные Node подключаются исходящим WireGuard-соединением и не требуют белого IP.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fLO https://raw.githubusercontent.com/ochenstarik-ui/lightweight-server/main/ochenstarik-server-monitor-manager.sh
|
||||||
|
chmod 700 ochenstarik-server-monitor-manager.sh
|
||||||
|
bash -n ochenstarik-server-monitor-manager.sh
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh hub
|
||||||
|
```
|
||||||
|
|
||||||
|
На Hub создайте отдельный enrollment-код на 10 минут для каждого Node, после чего на соответствующем сервере запустите тот же файл в режиме `node`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ochenstarik-smm node-code ai-agent
|
||||||
|
sudo ochenstarik-smm node-code home
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh node
|
||||||
|
```
|
||||||
|
|
||||||
|
Links являются направленными:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ochenstarik-smm link-connect ai-agent home tcp 22 120
|
||||||
|
sudo ochenstarik-smm link-disconnect ai-agent home tcp 22
|
||||||
|
sudo ochenstarik-smm nodes
|
||||||
|
sudo ochenstarik-smm links
|
||||||
|
```
|
||||||
|
|
||||||
|
Установщик Node создаст приватный WireGuard-ключ локально и покажет запрос `SMMREQ1`. Во втором терминале выполните на Hub `sudo ochenstarik-smm node-enroll`, вставьте запрос по скрытому приглашению и верните полученный код `SMMACK1` в установщик Node. Enrollment-код действует 10 минут и погашается при первой успешной регистрации.
|
||||||
|
|
||||||
|
Команды обслуживания учитывают установленную роль и создают root-only backup перед изменениями:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh update
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh rollback
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh uninstall-node
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh uninstall-hub
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh uninstall-monitor
|
||||||
|
```
|
||||||
|
|
||||||
## Требования
|
## Требования
|
||||||
|
|
||||||
- Ubuntu Server или совместимая Debian-система с `systemd`;
|
- Ubuntu Server или совместимая Debian-система с `systemd`;
|
||||||
|
|
|
||||||
1380
ochenstarik-server-monitor-manager.sh
Normal file
1380
ochenstarik-server-monitor-manager.sh
Normal file
File diff suppressed because it is too large
Load diff
16
tests/e2e/Dockerfile.systemd
Normal file
16
tests/e2e/Dockerfile.systemd
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
FROM debian:bookworm-slim
|
||||||
|
|
||||||
|
ENV container=docker
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends systemd systemd-sysv dbus ca-certificates openssh-client \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& systemctl mask dev-hugepages.mount sys-fs-fuse-connections.mount systemd-remount-fs.service
|
||||||
|
|
||||||
|
COPY . /workspace
|
||||||
|
RUN chmod 700 /workspace/*.sh
|
||||||
|
|
||||||
|
STOPSIGNAL SIGRTMIN+3
|
||||||
|
CMD ["/sbin/init"]
|
||||||
93
tests/e2e/test-monitor-manager-systemd-reinstall.sh
Normal file
93
tests/e2e/test-monitor-manager-systemd-reinstall.sh
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.."
|
||||||
|
|
||||||
|
command -v docker >/dev/null || { echo 'docker is required' >&2; exit 1; }
|
||||||
|
command -v ssh-keygen >/dev/null || { echo 'ssh-keygen is required' >&2; exit 1; }
|
||||||
|
|
||||||
|
run_id="${GITHUB_RUN_ID:-local}-$$"
|
||||||
|
image="smm-systemd-e2e:${run_id}"
|
||||||
|
container="smm-systemd-e2e-${run_id}"
|
||||||
|
temporary="$(mktemp -d)"
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
docker rm -f "$container" >/dev/null 2>&1 || true
|
||||||
|
docker image rm -f "$image" >/dev/null 2>&1 || true
|
||||||
|
rm -rf -- "$temporary"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
ssh-keygen -q -t ed25519 -N '' -C 'smm-e2e' -f "$temporary/monitor-key"
|
||||||
|
public_key="$(<"$temporary/monitor-key.pub")"
|
||||||
|
|
||||||
|
docker build --pull -f tests/e2e/Dockerfile.systemd -t "$image" .
|
||||||
|
docker run -d \
|
||||||
|
--name "$container" \
|
||||||
|
--privileged \
|
||||||
|
--cgroupns=host \
|
||||||
|
--tmpfs /run \
|
||||||
|
--tmpfs /run/lock \
|
||||||
|
-v /sys/fs/cgroup:/sys/fs/cgroup:rw \
|
||||||
|
"$image" >/dev/null
|
||||||
|
|
||||||
|
for _ in $(seq 1 30); do
|
||||||
|
docker exec "$container" systemctl show --property=Version >/dev/null 2>&1 && break
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
docker exec "$container" systemctl show --property=Version >/dev/null
|
||||||
|
|
||||||
|
install_hub() {
|
||||||
|
docker exec \
|
||||||
|
-e "SERVER_MONITOR_PUBLIC_KEY=$public_key" \
|
||||||
|
-e SMM_HUB_ENDPOINT=203.0.113.10 \
|
||||||
|
-e SMM_WG_PORT=51820 \
|
||||||
|
"$container" \
|
||||||
|
/workspace/ochenstarik-server-monitor-manager.sh install-hub
|
||||||
|
}
|
||||||
|
|
||||||
|
install_hub
|
||||||
|
first_private_key_hash="$(docker exec "$container" sha256sum /etc/ochenstarik-server-monitor-manager/hub.key | awk '{ print $1 }')"
|
||||||
|
|
||||||
|
# A repeated install must repair units/configuration without rotating the Hub identity.
|
||||||
|
install_hub
|
||||||
|
second_private_key_hash="$(docker exec "$container" sha256sum /etc/ochenstarik-server-monitor-manager/hub.key | awk '{ print $1 }')"
|
||||||
|
[[ "$first_private_key_hash" == "$second_private_key_hash" ]]
|
||||||
|
[[ "$(docker exec "$container" grep -c 'ochenstarik-server-monitor' /var/lib/ochenstarik-server-monitor-manager/.ssh/authorized_keys)" -eq 1 ]]
|
||||||
|
|
||||||
|
# Restarting the systemd container is the CI reboot boundary: the writable rootfs is retained,
|
||||||
|
# PID 1 starts again, and only enabled units can reconstruct runtime state.
|
||||||
|
docker restart --timeout 20 "$container" >/dev/null
|
||||||
|
for _ in $(seq 1 45); do
|
||||||
|
if docker exec "$container" systemctl is-active --quiet wg-quick@smm0.service \
|
||||||
|
&& docker exec "$container" systemctl is-active --quiet ochenstarik-smm-firewall.timer \
|
||||||
|
&& docker exec "$container" systemctl is-active --quiet ssh.service; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
for unit in wg-quick@smm0.service ochenstarik-smm-firewall.timer ssh.service; do
|
||||||
|
if ! docker exec "$container" systemctl is-active --quiet "$unit"; then
|
||||||
|
state="$(docker exec "$container" systemctl show "$unit" \
|
||||||
|
--property=ActiveState,SubState,Result --value | tr '\n' ' ')"
|
||||||
|
journal="$(docker exec "$container" journalctl -u "$unit" -n 12 --no-pager 2>&1 \
|
||||||
|
| tr '\n' ' ' | sed 's/%/%25/g; s/\r/%0D/g')"
|
||||||
|
printf '::error title=Reboot unit failed::%s: %s; %s\n' "$unit" "$state" "$journal"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
docker exec "$container" systemctl is-enabled --quiet wg-quick@smm0.service
|
||||||
|
docker exec "$container" systemctl is-enabled --quiet ochenstarik-smm-firewall.service
|
||||||
|
docker exec "$container" systemctl is-enabled --quiet ochenstarik-smm-firewall.timer
|
||||||
|
docker exec "$container" systemctl is-active --quiet wg-quick@smm0.service
|
||||||
|
docker exec "$container" systemctl is-active --quiet ochenstarik-smm-firewall.timer
|
||||||
|
docker exec "$container" systemctl start ochenstarik-smm-firewall.service
|
||||||
|
docker exec "$container" ip address show dev smm0 | grep -Fq '10.77.0.1/24'
|
||||||
|
docker exec "$container" nft list table inet ochenstarik_smm | grep -Fq 'iifname "smm0" oifname "smm0" drop'
|
||||||
|
reboot_private_key_hash="$(docker exec "$container" \
|
||||||
|
sha256sum /etc/ochenstarik-server-monitor-manager/hub.key | awk '{ print $1 }')"
|
||||||
|
[[ "$reboot_private_key_hash" == "$first_private_key_hash" ]]
|
||||||
|
|
||||||
|
printf 'Server Monitor Manager repeated-install and reboot checks passed.\n'
|
||||||
149
tests/e2e/test-monitor-manager-wireguard-nftables.sh
Normal file
149
tests/e2e/test-monitor-manager-wireguard-nftables.sh
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.."
|
||||||
|
|
||||||
|
for command in ip wg nft nc timeout awk sed; do
|
||||||
|
command -v "$command" >/dev/null || { echo "$command is required" >&2; exit 1; }
|
||||||
|
done
|
||||||
|
[[ "$EUID" -eq 0 ]] || { echo 'run as root' >&2; exit 1; }
|
||||||
|
|
||||||
|
temporary="$(mktemp -d)"
|
||||||
|
suffix="${GITHUB_RUN_ID:-$$}"
|
||||||
|
hub="smm-hub-${suffix}"
|
||||||
|
source="smm-source-${suffix}"
|
||||||
|
target="smm-target-${suffix}"
|
||||||
|
listener_pid=''
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
[[ -z "$listener_pid" ]] || kill "$listener_pid" >/dev/null 2>&1 || true
|
||||||
|
ip netns delete "$source" >/dev/null 2>&1 || true
|
||||||
|
ip netns delete "$target" >/dev/null 2>&1 || true
|
||||||
|
ip netns delete "$hub" >/dev/null 2>&1 || true
|
||||||
|
rm -rf -- "$temporary"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
for namespace in "$hub" "$source" "$target"; do
|
||||||
|
ip netns add "$namespace"
|
||||||
|
ip -n "$namespace" link set lo up
|
||||||
|
done
|
||||||
|
|
||||||
|
ip link add smm-hub-source type veth peer name smm-source-wan
|
||||||
|
ip link set smm-hub-source netns "$hub"
|
||||||
|
ip link set smm-source-wan netns "$source"
|
||||||
|
ip -n "$hub" address add 192.0.2.1/30 dev smm-hub-source
|
||||||
|
ip -n "$source" address add 192.0.2.2/30 dev smm-source-wan
|
||||||
|
ip -n "$hub" link set smm-hub-source up
|
||||||
|
ip -n "$source" link set smm-source-wan up
|
||||||
|
|
||||||
|
ip link add smm-hub-target type veth peer name smm-target-wan
|
||||||
|
ip link set smm-hub-target netns "$hub"
|
||||||
|
ip link set smm-target-wan netns "$target"
|
||||||
|
ip -n "$hub" address add 192.0.2.5/30 dev smm-hub-target
|
||||||
|
ip -n "$target" address add 192.0.2.6/30 dev smm-target-wan
|
||||||
|
ip -n "$hub" link set smm-hub-target up
|
||||||
|
ip -n "$target" link set smm-target-wan up
|
||||||
|
|
||||||
|
umask 077
|
||||||
|
wg genkey > "$temporary/hub.key"
|
||||||
|
wg genkey > "$temporary/source.key"
|
||||||
|
wg genkey > "$temporary/target.key"
|
||||||
|
wg pubkey < "$temporary/hub.key" > "$temporary/hub.pub"
|
||||||
|
wg pubkey < "$temporary/source.key" > "$temporary/source.pub"
|
||||||
|
wg pubkey < "$temporary/target.key" > "$temporary/target.pub"
|
||||||
|
|
||||||
|
for namespace in "$hub" "$source" "$target"; do
|
||||||
|
ip -n "$namespace" link add smm0 type wireguard
|
||||||
|
done
|
||||||
|
ip netns exec "$hub" wg set smm0 \
|
||||||
|
private-key "$temporary/hub.key" listen-port 51820 \
|
||||||
|
peer "$(<"$temporary/source.pub")" allowed-ips 10.77.0.2/32 \
|
||||||
|
peer "$(<"$temporary/target.pub")" allowed-ips 10.77.0.3/32
|
||||||
|
ip netns exec "$source" wg set smm0 \
|
||||||
|
private-key "$temporary/source.key" \
|
||||||
|
peer "$(<"$temporary/hub.pub")" endpoint 192.0.2.1:51820 allowed-ips 10.77.0.0/24 persistent-keepalive 1
|
||||||
|
ip netns exec "$target" wg set smm0 \
|
||||||
|
private-key "$temporary/target.key" \
|
||||||
|
peer "$(<"$temporary/hub.pub")" endpoint 192.0.2.5:51820 allowed-ips 10.77.0.0/24 persistent-keepalive 1
|
||||||
|
|
||||||
|
ip -n "$hub" address add 10.77.0.1/24 dev smm0
|
||||||
|
ip -n "$source" address add 10.77.0.2/32 dev smm0
|
||||||
|
ip -n "$target" address add 10.77.0.3/32 dev smm0
|
||||||
|
for namespace in "$hub" "$source" "$target"; do
|
||||||
|
ip -n "$namespace" link set smm0 up
|
||||||
|
done
|
||||||
|
ip -n "$source" route add 10.77.0.0/24 dev smm0
|
||||||
|
ip -n "$target" route add 10.77.0.0/24 dev smm0
|
||||||
|
ip netns exec "$hub" sysctl -q -w net.ipv4.ip_forward=1
|
||||||
|
|
||||||
|
helper="$temporary/ochenstarik-smm-hub"
|
||||||
|
awk '
|
||||||
|
capture && /^EOF$/ { exit }
|
||||||
|
/cat > .*HUB_HELPER.*<</ { capture=1; next }
|
||||||
|
capture { print }
|
||||||
|
' ochenstarik-server-monitor-manager.sh > "$helper"
|
||||||
|
chmod 700 "$helper"
|
||||||
|
state="$temporary/state"
|
||||||
|
mkdir -p "$state/nodes" "$state/tokens"
|
||||||
|
sed -i "s|^readonly STATE_DIR=.*|readonly STATE_DIR=\"$state\"|" "$helper"
|
||||||
|
sed -i "s|^readonly WG_CONFIG=.*|readonly WG_CONFIG=\"$temporary/smm0.conf\"|" "$helper"
|
||||||
|
cat > "$state/hub.conf" <<'EOF'
|
||||||
|
HUB_ENDPOINT=203.0.113.10
|
||||||
|
WG_PORT=51820
|
||||||
|
HUB_ADDRESS=10.77.0.1
|
||||||
|
MESH_CIDR=10.77.0.0/24
|
||||||
|
EOF
|
||||||
|
cp "$temporary/hub.key" "$state/hub.key"
|
||||||
|
cat > "$state/nodes/source.node" <<EOF
|
||||||
|
NAME=source
|
||||||
|
ADDRESS=10.77.0.2
|
||||||
|
PUBLIC_KEY=$(<"$temporary/source.pub")
|
||||||
|
EOF
|
||||||
|
cat > "$state/nodes/target.node" <<EOF
|
||||||
|
NAME=target
|
||||||
|
ADDRESS=10.77.0.3
|
||||||
|
PUBLIC_KEY=$(<"$temporary/target.pub")
|
||||||
|
EOF
|
||||||
|
touch "$state/links" "$state/audit.jsonl"
|
||||||
|
printf '0\n' > "$state/policy.version"
|
||||||
|
|
||||||
|
start_listener() {
|
||||||
|
local namespace="$1"
|
||||||
|
ip netns exec "$namespace" sh -c 'printf allowed | timeout 10 nc -l 2222' &
|
||||||
|
listener_pid=$!
|
||||||
|
sleep 0.2
|
||||||
|
}
|
||||||
|
|
||||||
|
ip netns exec "$hub" "$helper" link-connect source target tcp 2222 120
|
||||||
|
start_listener "$target"
|
||||||
|
response="$(timeout 8 ip netns exec "$source" nc -w 5 10.77.0.3 2222)"
|
||||||
|
wait "$listener_pid"
|
||||||
|
listener_pid=''
|
||||||
|
[[ "$response" == allowed ]]
|
||||||
|
|
||||||
|
# The policy is directional: the reverse connection must remain blocked.
|
||||||
|
start_listener "$source"
|
||||||
|
if timeout 3 ip netns exec "$target" nc -w 2 10.77.0.2 2222 >/dev/null 2>&1; then
|
||||||
|
echo 'Reverse traffic bypassed the directional Link.' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
kill "$listener_pid" >/dev/null 2>&1 || true
|
||||||
|
wait "$listener_pid" 2>/dev/null || true
|
||||||
|
listener_pid=''
|
||||||
|
|
||||||
|
ip netns exec "$hub" "$helper" link-disconnect source target tcp 2222
|
||||||
|
start_listener "$target"
|
||||||
|
if timeout 3 ip netns exec "$source" nc -w 2 10.77.0.3 2222 >/dev/null 2>&1; then
|
||||||
|
echo 'Traffic remained available after the Link kill switch.' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
kill "$listener_pid" >/dev/null 2>&1 || true
|
||||||
|
wait "$listener_pid" 2>/dev/null || true
|
||||||
|
listener_pid=''
|
||||||
|
|
||||||
|
ip netns exec "$hub" wg show smm0 latest-handshakes | awk '$2 > 0 { found=1 } END { exit !found }'
|
||||||
|
grep -Fq '"state":"Active"' "$state/audit.jsonl"
|
||||||
|
grep -Fq '"state":"Disabled"' "$state/audit.jsonl"
|
||||||
|
|
||||||
|
printf 'Real WireGuard and nftables directional Link checks passed.\n'
|
||||||
29
tests/test-monitor-manager-control-layer.sh
Normal file
29
tests/test-monitor-manager-control-layer.sh
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.."
|
||||||
|
script="ochenstarik-server-monitor-manager.sh"
|
||||||
|
|
||||||
|
[[ -s "$script" ]]
|
||||||
|
grep -Fq 'readonly SMM_RELEASE_VERSION=' "$script"
|
||||||
|
grep -Fq 'server-monitor-manager-${runtime}.tar.gz' "$script"
|
||||||
|
grep -Fq 'sha256sum "$archive"' "$script"
|
||||||
|
grep -Fq 'SMMCTL1-' "$script"
|
||||||
|
grep -Fq 'SMMDEV1-' "$script"
|
||||||
|
grep -Fq 'control-code)' "$script"
|
||||||
|
grep -Fq 'install-control-hub)' "$script"
|
||||||
|
grep -Fq 'install-control-agent)' "$script"
|
||||||
|
grep -Fq 'control-device-code)' "$script"
|
||||||
|
grep -Fq 'ochenstarik-smm-policy-apply' "$script"
|
||||||
|
grep -Fq 'NoNewPrivileges=true' "$script"
|
||||||
|
grep -Fq 'ProtectSystem=strict' "$script"
|
||||||
|
grep -Fq 'SMM_EnrollToken=${token}' "$script"
|
||||||
|
grep -Fq 'systemctl enable --now ochenstarik-smm-control.service' "$script"
|
||||||
|
grep -Fq 'systemctl enable --now ochenstarik-smm-agent.service' "$script"
|
||||||
|
|
||||||
|
if grep -Eq 'CONTROL_JOIN_CODE=.*(ca\.key|control-ca\.pfx)' "$script"; then
|
||||||
|
echo 'Control join code must never contain the CA private key.' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'Server Monitor Manager control-layer installer checks passed.\n'
|
||||||
99
tests/test-monitor-manager-enrollment.sh
Normal file
99
tests/test-monitor-manager-enrollment.sh
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.."
|
||||||
|
script="ochenstarik-server-monitor-manager.sh"
|
||||||
|
temp_dir="$(mktemp -d)"
|
||||||
|
trap 'rm -rf -- "$temp_dir"' EXIT
|
||||||
|
|
||||||
|
[[ -s "$script" ]]
|
||||||
|
grep -Fq 'code="SMM2-' "$script"
|
||||||
|
grep -Fq 'request_code="SMMREQ1-' "$script"
|
||||||
|
grep -Fq 'SMMACK1-' "$script"
|
||||||
|
grep -Fq 'expires=$(( $(date +%s) + 600 ))' "$script"
|
||||||
|
grep -Fq 'mv -- "$token_file" "$consuming_file"' "$script"
|
||||||
|
grep -Fq 'private_key="$(wg genkey)"' "$script"
|
||||||
|
|
||||||
|
if grep -Fq 'PRIVATE_KEY=%s' "$script"; then
|
||||||
|
echo 'Enrollment payload must not contain a private WireGuard key.' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
helper="$temp_dir/ochenstarik-smm-hub"
|
||||||
|
awk '
|
||||||
|
capture && /^EOF$/ { exit }
|
||||||
|
/cat > .*HUB_HELPER.*<</ { capture=1; next }
|
||||||
|
capture { print }
|
||||||
|
' "$script" > "$helper"
|
||||||
|
chmod 700 "$helper"
|
||||||
|
|
||||||
|
state="$temp_dir/state"
|
||||||
|
mock_bin="$temp_dir/bin"
|
||||||
|
mkdir -p "$state/nodes" "$state/tokens" "$mock_bin"
|
||||||
|
sed -i "s|^readonly STATE_DIR=.*|readonly STATE_DIR=\"$state\"|" "$helper"
|
||||||
|
sed -i "s|^readonly WG_CONFIG=.*|readonly WG_CONFIG=\"$temp_dir/smm0.conf\"|" "$helper"
|
||||||
|
sed -i 's/^require_root() .*/require_root() { :; }/' "$helper"
|
||||||
|
sed -i 's/ -o root -g root//g' "$helper"
|
||||||
|
|
||||||
|
public_key='AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA='
|
||||||
|
cat > "$mock_bin/wg" <<EOF
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
if [[ "\${1:-}" == pubkey ]]; then
|
||||||
|
printf '%s\n' '$public_key'
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
EOF
|
||||||
|
cat > "$mock_bin/ip" <<'EOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
exit 1
|
||||||
|
EOF
|
||||||
|
chmod 700 "$mock_bin/wg" "$mock_bin/ip"
|
||||||
|
|
||||||
|
cat > "$state/hub.conf" <<'EOF'
|
||||||
|
HUB_ENDPOINT=hub.example.test
|
||||||
|
WG_PORT=51820
|
||||||
|
HUB_ADDRESS=10.77.0.1
|
||||||
|
MESH_CIDR=10.77.0.0/24
|
||||||
|
EOF
|
||||||
|
printf 'test-hub-private-key\n' > "$state/hub.key"
|
||||||
|
: > "$state/links"
|
||||||
|
|
||||||
|
output="$(PATH="$mock_bin:$PATH" "$helper" node-code test-node)"
|
||||||
|
join_code="$(printf '%s\n' "$output" | grep '^SMM2-')"
|
||||||
|
[[ -n "$join_code" ]]
|
||||||
|
|
||||||
|
decode_base64url() {
|
||||||
|
local data="$1"
|
||||||
|
data="${data//-/+}"
|
||||||
|
data="${data//_/\/}"
|
||||||
|
case $(( ${#data} % 4 )) in
|
||||||
|
2) data+='==' ;;
|
||||||
|
3) data+='=' ;;
|
||||||
|
esac
|
||||||
|
printf '%s' "$data" | base64 -d
|
||||||
|
}
|
||||||
|
|
||||||
|
payload="$(decode_base64url "${join_code#SMM2-}")"
|
||||||
|
token="$(printf '%s\n' "$payload" | awk -F= '$1 == "TOKEN" { print $2 }')"
|
||||||
|
name="$(printf '%s\n' "$payload" | awk -F= '$1 == "NAME" { print $2 }')"
|
||||||
|
address="$(printf '%s\n' "$payload" | awk -F= '$1 == "ADDRESS" { print $2 }')"
|
||||||
|
[[ "$name" == test-node ]]
|
||||||
|
[[ "$address" == 10.77.0.2/32 ]]
|
||||||
|
[[ "$token" =~ ^[a-f0-9]{64}$ ]]
|
||||||
|
[[ "$payload" != *PRIVATE_KEY* ]]
|
||||||
|
|
||||||
|
request_payload="$(printf 'VERSION=1\nTOKEN=%s\nNAME=%s\nADDRESS=%s\nPUBLIC_KEY=%s\n' \
|
||||||
|
"$token" "$name" "$address" "$public_key")"
|
||||||
|
request_code="SMMREQ1-$(printf '%s' "$request_payload" | base64 -w0 | tr '+/' '-_' | tr -d '=')"
|
||||||
|
enroll_output="$(PATH="$mock_bin:$PATH" SMM_ENROLL_REQUEST="$request_code" "$helper" node-enroll)"
|
||||||
|
grep -Eq '^SMMACK1-[a-f0-9]{64}$' <<< "$enroll_output"
|
||||||
|
grep -Fqx 'NAME=test-node' "$state/nodes/test-node.node"
|
||||||
|
grep -Fqx "PUBLIC_KEY=$public_key" "$state/nodes/test-node.node"
|
||||||
|
|
||||||
|
if PATH="$mock_bin:$PATH" SMM_ENROLL_REQUEST="$request_code" "$helper" node-enroll >/dev/null 2>&1; then
|
||||||
|
echo 'Enrollment token was accepted more than once.' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'Server Monitor Manager enrollment checks passed.\n'
|
||||||
24
tests/test-monitor-manager-lifecycle.sh
Normal file
24
tests/test-monitor-manager-lifecycle.sh
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.."
|
||||||
|
script="ochenstarik-server-monitor-manager.sh"
|
||||||
|
|
||||||
|
[[ -s "$script" ]]
|
||||||
|
grep -Fq 'sudo' "$script"
|
||||||
|
grep -Fq 'iputils-ping' "$script"
|
||||||
|
grep -Fq 'backup_state()' "$script"
|
||||||
|
grep -Fq 'rollback_state()' "$script"
|
||||||
|
grep -Fq 'update_installed()' "$script"
|
||||||
|
grep -Fq 'uninstall_monitor()' "$script"
|
||||||
|
grep -Fq '90-ochenstarik-server-monitor.conf' "$script"
|
||||||
|
grep -Fq 'PubkeyAuthentication yes' "$script"
|
||||||
|
grep -Fq 'uninstall_node()' "$script"
|
||||||
|
grep -Fq 'uninstall_hub()' "$script"
|
||||||
|
grep -Fq '/var/backups/${APP_NAME}' "$script"
|
||||||
|
grep -Fq 'systemctl disable --now ochenstarik-smm-firewall.timer' "$script"
|
||||||
|
grep -Fq 'nft delete table inet ochenstarik_smm' "$script"
|
||||||
|
grep -Fq 'sysctl --system' "$script"
|
||||||
|
grep -Fq 'uninstall) die "Укажите роль:' "$script"
|
||||||
|
|
||||||
|
printf 'Server Monitor Manager lifecycle checks passed.\n'
|
||||||
95
tests/test-monitor-manager-links.sh
Normal file
95
tests/test-monitor-manager-links.sh
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.."
|
||||||
|
script="ochenstarik-server-monitor-manager.sh"
|
||||||
|
temp_dir="$(mktemp -d)"
|
||||||
|
trap 'rm -rf -- "$temp_dir"' EXIT
|
||||||
|
|
||||||
|
helper="$temp_dir/ochenstarik-smm-hub"
|
||||||
|
awk '
|
||||||
|
capture && /^EOF$/ { exit }
|
||||||
|
/cat > .*HUB_HELPER.*<</ { capture=1; next }
|
||||||
|
capture { print }
|
||||||
|
' "$script" > "$helper"
|
||||||
|
chmod 700 "$helper"
|
||||||
|
|
||||||
|
state="$temp_dir/state"
|
||||||
|
mock_bin="$temp_dir/bin"
|
||||||
|
nft_capture="$temp_dir/nft.conf"
|
||||||
|
mkdir -p "$state/nodes" "$state/tokens" "$mock_bin"
|
||||||
|
sed -i "s|^readonly STATE_DIR=.*|readonly STATE_DIR=\"$state\"|" "$helper"
|
||||||
|
sed -i "s|^readonly WG_CONFIG=.*|readonly WG_CONFIG=\"$temp_dir/smm0.conf\"|" "$helper"
|
||||||
|
sed -i 's/^require_root() .*/require_root() { :; }/' "$helper"
|
||||||
|
sed -i 's/ -o root -g root//g' "$helper"
|
||||||
|
|
||||||
|
cat > "$mock_bin/nft" <<'EOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
previous=''
|
||||||
|
for argument in "$@"; do
|
||||||
|
if [[ "$previous" == -f ]]; then
|
||||||
|
cp -- "$argument" "$NFT_CAPTURE"
|
||||||
|
fi
|
||||||
|
previous="$argument"
|
||||||
|
done
|
||||||
|
exit 0
|
||||||
|
EOF
|
||||||
|
chmod 700 "$mock_bin/nft"
|
||||||
|
|
||||||
|
cat > "$state/hub.conf" <<'EOF'
|
||||||
|
HUB_ENDPOINT=hub.example.test
|
||||||
|
WG_PORT=51820
|
||||||
|
HUB_ADDRESS=10.77.0.1
|
||||||
|
MESH_CIDR=10.77.0.0/24
|
||||||
|
EOF
|
||||||
|
printf 'test-hub-private-key\n' > "$state/hub.key"
|
||||||
|
cat > "$state/nodes/ai-agent.node" <<'EOF'
|
||||||
|
NAME=ai-agent
|
||||||
|
ADDRESS=10.77.0.2
|
||||||
|
PUBLIC_KEY=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
|
||||||
|
EOF
|
||||||
|
cat > "$state/nodes/home.node" <<'EOF'
|
||||||
|
NAME=home
|
||||||
|
ADDRESS=10.77.0.3
|
||||||
|
PUBLIC_KEY=BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=
|
||||||
|
EOF
|
||||||
|
printf 'legacy-policy home\n' > "$state/links"
|
||||||
|
|
||||||
|
PATH="$mock_bin:$PATH" NFT_CAPTURE="$nft_capture" \
|
||||||
|
"$helper" link-connect ai-agent home tcp 2222 120
|
||||||
|
|
||||||
|
read -r source target cidr protocol port expires version < "$state/links"
|
||||||
|
[[ "$source" == ai-agent ]]
|
||||||
|
[[ "$target" == home ]]
|
||||||
|
[[ "$cidr" == 10.77.0.3/32 ]]
|
||||||
|
[[ "$protocol" == tcp ]]
|
||||||
|
[[ "$port" == 2222 ]]
|
||||||
|
(( expires > $(date +%s) ))
|
||||||
|
[[ "$version" =~ ^[0-9]+$ ]]
|
||||||
|
grep -Fq 'ip saddr 10.77.0.2 ip daddr 10.77.0.3/32 tcp dport 2222 accept' "$nft_capture"
|
||||||
|
grep -Fq '"state":"Connecting"' "$state/audit.jsonl"
|
||||||
|
grep -Fq '"state":"Active"' "$state/audit.jsonl"
|
||||||
|
|
||||||
|
if PATH="$mock_bin:$PATH" NFT_CAPTURE="$nft_capture" \
|
||||||
|
"$helper" link-connect ai-agent home tcp 70000 120 >/dev/null 2>&1; then
|
||||||
|
echo 'Invalid port was accepted.' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'ai-agent home 10.77.0.3/32 udp 53 1 99\n' >> "$state/links"
|
||||||
|
PATH="$mock_bin:$PATH" NFT_CAPTURE="$nft_capture" "$helper" firewall-restore
|
||||||
|
[[ "$(wc -l < "$state/links")" -eq 1 ]]
|
||||||
|
|
||||||
|
PATH="$mock_bin:$PATH" NFT_CAPTURE="$nft_capture" \
|
||||||
|
"$helper" link-disconnect ai-agent home tcp 2222
|
||||||
|
[[ ! -s "$state/links" ]]
|
||||||
|
grep -Fq '"state":"Expired"' "$state/audit.jsonl"
|
||||||
|
grep -Fq '"state":"Disconnecting"' "$state/audit.jsonl"
|
||||||
|
grep -Fq '"state":"Disabled"' "$state/audit.jsonl"
|
||||||
|
if grep -Fq 'dport 2222 accept' "$nft_capture"; then
|
||||||
|
echo 'Disconnected policy remained in nftables.' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
grep -Fq 'OnUnitActiveSec=1min' "$script"
|
||||||
|
printf 'Server Monitor Manager Link policy checks passed.\n'
|
||||||
15
tests/test-monitor-manager-metrics.sh
Normal file
15
tests/test-monitor-manager-metrics.sh
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.."
|
||||||
|
script="ochenstarik-server-monitor-manager.sh"
|
||||||
|
|
||||||
|
for key in \
|
||||||
|
SWAP_TOTAL_KB SWAP_FREE_KB \
|
||||||
|
DISK_INODES_TOTAL DISK_INODES_FREE \
|
||||||
|
NETWORK_RX_BYTES NETWORK_TX_BYTES \
|
||||||
|
SYSTEMD_SSH SYSTEMD_WIREGUARD; do
|
||||||
|
grep -Fq "$key" "$script"
|
||||||
|
done
|
||||||
|
|
||||||
|
printf 'Server Monitor Manager extended metrics checks passed.\n'
|
||||||
Loading…
Reference in a new issue