Compare commits
86 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f1fa0acfa7 | |||
| a5c1ea1c1b | |||
| 4dbc0bd9f3 | |||
| 94059ee9e6 | |||
| 06d8876b04 | |||
| 90b3baa2fb | |||
| 71224721d3 | |||
| 56f44f5b95 | |||
| 08ac26c698 | |||
| ac0755977c | |||
| c1490421ba | |||
| 2d366c4619 | |||
| dad057528c | |||
| 8ae9149620 | |||
| 9d6c2abb9f | |||
| 4c9e54aaa3 | |||
| 290af48007 | |||
| 9a2212d691 | |||
| 6f57540490 | |||
| 8c1b15a78e | |||
| 52fb2bb5d3 | |||
| 2ce9dbd4e8 | |||
| f85db30c2e | |||
| fc9afd1720 | |||
| c23e0829cd | |||
| 7b102c94fb | |||
| 5fb815a3c1 | |||
| d9bf8d5616 | |||
| e45b79c2a8 | |||
| c3177eb4e4 | |||
| 6141c2b556 | |||
| 8f589901f2 | |||
| 10a9ae2eac | |||
| 53efeab1b3 | |||
| cc0f01b6ae | |||
| 00a0bf661c | |||
| 6a27007b53 | |||
| 2944ca0947 | |||
| 2cfc7408a4 | |||
| 4c8fe3c8d6 | |||
| 8dd5834be2 | |||
| 9461d6b385 | |||
| c0f18a41a1 | |||
| 96248d3d31 | |||
| bfb6dcc42f | |||
| 9470435704 | |||
| c37d4a751c | |||
| 072aa48db0 | |||
| 47ca075bc0 | |||
| 8938d842db | |||
| 710cc6537e | |||
| 224a84e856 | |||
| 062e82bd97 | |||
| 43fd852b3e | |||
| 946334ffc7 | |||
| 94ed6a8184 | |||
| 5b5a4aa009 | |||
| 0a22ecd13f | |||
| 56d70ed031 | |||
| 3133671c02 | |||
| 5fa9f414b0 | |||
| 233f14f998 | |||
| c5364cf5ba | |||
| 60d326880a | |||
| 13e8787553 | |||
| 5795677fd1 | |||
| 7cae9dacf0 | |||
| a745e84470 | |||
| 68a6270b8c | |||
| 6b47f9af17 | |||
| bd93d37645 | |||
| 2e7a6aba90 | |||
| 307cc34752 | |||
| 9aaa9ebfb7 | |||
| ad52b39ed7 | |||
| d9d99e7827 | |||
| 736319645e | |||
| 8e04f33fc3 | |||
| 53df67f085 | |||
| ca52c3bde4 | |||
| 78fcce0d28 | |||
| a4a06593b1 | |||
| e7b1f22b44 | |||
| cbacfea7f2 | |||
| 281ac48d28 | |||
| c2f0e53f1d |
@@ -1,16 +0,0 @@
|
|||||||
name: Beta Release
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- 'v*-beta*'
|
|
||||||
- 'v*-test*'
|
|
||||||
- 'dev-*'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
deploy:
|
|
||||||
if: "contains(gitea.ref_name, 'beta') || contains(gitea.ref_name, 'test') || startsWith(gitea.ref_name, 'dev-')"
|
|
||||||
uses: ./.gitea/workflows/deploy_call.yaml
|
|
||||||
with:
|
|
||||||
prerelease: true
|
|
||||||
secrets: inherit
|
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
name: Build Dashboard UI
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
RUNNER_TOOL_CACHE: /toolcache
|
||||||
|
steps:
|
||||||
|
- name: Configure git auth for submodules
|
||||||
|
run: git config --global url."https://x-access-token:${{ secrets.BUILD_TOKEN }}@git.datadunia.com/".insteadOf "https://git.datadunia.com/"
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.BUILD_TOKEN }}
|
||||||
|
persist-credentials: true
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '24'
|
||||||
|
|
||||||
|
- name: Hash package-lock
|
||||||
|
id: hash-npm
|
||||||
|
run: echo "hash=$(sha256sum apps/dashboard-ui/package-lock.json | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.npm
|
||||||
|
key: npm-dashboard-${{ steps.hash-npm.outputs.hash }}
|
||||||
|
restore-keys: npm-dashboard-
|
||||||
|
|
||||||
|
- name: Install
|
||||||
|
working-directory: apps/dashboard-ui
|
||||||
|
run: npm ci || npm install
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
working-directory: apps/dashboard-ui
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: dashboard-ui-dist
|
||||||
|
path: apps/dashboard-ui/dist/
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
name: Build Device Agent
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
cross-build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
RUNNER_TOOL_CACHE: /toolcache
|
||||||
|
steps:
|
||||||
|
- name: Configure git auth for submodules
|
||||||
|
run: git config --global url."https://x-access-token:${{ secrets.BUILD_TOKEN }}@git.datadunia.com/".insteadOf "https://git.datadunia.com/"
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.BUILD_TOKEN }}
|
||||||
|
persist-credentials: true
|
||||||
|
|
||||||
|
- uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: '1.26'
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Build all platforms
|
||||||
|
working-directory: apps/device-agent
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
mkdir -p bin
|
||||||
|
for PAIR in linux/amd64 linux/arm64 windows/amd64; do
|
||||||
|
GOOS="${PAIR%%/*}"
|
||||||
|
GOARCH="${PAIR##*/}"
|
||||||
|
EXT=""
|
||||||
|
if [ "$GOOS" = "windows" ]; then EXT=".exe"; fi
|
||||||
|
OUT="bin/nexus-device-agent-${GOOS}-${GOARCH}${EXT}"
|
||||||
|
echo "Building $OUT ..."
|
||||||
|
CGO_ENABLED=0 GOOS="$GOOS" GOARCH="$GOARCH" go build -o "$OUT" .
|
||||||
|
done
|
||||||
|
echo "=== Build output ==="
|
||||||
|
ls -la bin/
|
||||||
|
|
||||||
|
- name: Upload linux/amd64
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: nexus-device-agent-linux-amd64
|
||||||
|
path: apps/device-agent/bin/nexus-device-agent-linux-amd64
|
||||||
|
|
||||||
|
- name: Upload linux/arm64
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: nexus-device-agent-linux-arm64
|
||||||
|
path: apps/device-agent/bin/nexus-device-agent-linux-arm64
|
||||||
|
|
||||||
|
- name: Upload windows/amd64
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: nexus-device-agent-windows-amd64
|
||||||
|
path: apps/device-agent/bin/nexus-device-agent-windows-amd64.exe
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
name: Build Server Core
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
RUNNER_TOOL_CACHE: /toolcache
|
||||||
|
steps:
|
||||||
|
- name: Configure git auth for submodules
|
||||||
|
run: git config --global url."https://x-access-token:${{ secrets.BUILD_TOKEN }}@git.datadunia.com/".insteadOf "https://git.datadunia.com/"
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.BUILD_TOKEN }}
|
||||||
|
persist-credentials: true
|
||||||
|
|
||||||
|
- uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: '1.26'
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Generate Swagger docs
|
||||||
|
working-directory: apps/server-core
|
||||||
|
run: |
|
||||||
|
go install github.com/swaggo/swag/cmd/swag@v1.16.6
|
||||||
|
swag init -g main.go --parseDependency --parseInternal
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
working-directory: apps/server-core
|
||||||
|
run: go build -o bin/server-core .
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: server-core-linux-amd64
|
||||||
|
path: apps/server-core/bin/server-core
|
||||||
+66
-118
@@ -1,25 +1,19 @@
|
|||||||
name: NexusGuard CI
|
name: CI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
tags:
|
||||||
- main
|
- 'dev-*'
|
||||||
pull_request:
|
- 'v*-dev*'
|
||||||
branches:
|
- 'v*-beta*'
|
||||||
- main
|
- 'v*-test*'
|
||||||
|
- 'v[0-9]*.[0-9]*.[0-9]'
|
||||||
env:
|
|
||||||
BUILD_TOKEN: ${{ secrets.BUILD_TOKEN }}
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# ──────────────────────────────────────────────
|
# --- TESTS (test tags + stable release tags) ---
|
||||||
# TEST — all 3 components in parallel
|
|
||||||
# ──────────────────────────────────────────────
|
|
||||||
server-core-test:
|
server-core-test:
|
||||||
|
if: contains(gitea.ref_name, 'test') || (!contains(gitea.ref_name, 'dev') && !contains(gitea.ref_name, 'beta'))
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: apps/server-core
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -27,18 +21,23 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
token: ${{ secrets.BUILD_TOKEN }}
|
token: ${{ secrets.BUILD_TOKEN }}
|
||||||
persist-credentials: true
|
persist-credentials: true
|
||||||
github-server-url: 'https://git.datadunia.com'
|
- name: Configure git auth for submodules
|
||||||
|
run: git config --global url."https://x-access-token:${{ secrets.BUILD_TOKEN }}@git.datadunia.com/".insteadOf "https://git.datadunia.com/"
|
||||||
- uses: actions/setup-go@v5
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.25'
|
go-version: '1.26'
|
||||||
- name: Test
|
- name: Generate swagger docs
|
||||||
run: go test ./... -tags dev -cover
|
working-directory: apps/server-core
|
||||||
|
run: |
|
||||||
|
go install github.com/swaggo/swag/cmd/swag@v1.16.6
|
||||||
|
swag init -g main.go --parseDependency --parseInternal
|
||||||
|
- name: Test (skip nftables - needs root)
|
||||||
|
working-directory: apps/server-core
|
||||||
|
run: go test $(go list ./... | grep -v internal/firewall) -tags dev -cover -count=1
|
||||||
|
|
||||||
device-agent-test:
|
device-agent-test:
|
||||||
|
if: contains(gitea.ref_name, 'test') || (!contains(gitea.ref_name, 'dev') && !contains(gitea.ref_name, 'beta'))
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: apps/device-agent
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -46,18 +45,18 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
token: ${{ secrets.BUILD_TOKEN }}
|
token: ${{ secrets.BUILD_TOKEN }}
|
||||||
persist-credentials: true
|
persist-credentials: true
|
||||||
github-server-url: 'https://git.datadunia.com'
|
- name: Configure git auth for submodules
|
||||||
|
run: git config --global url."https://x-access-token:${{ secrets.BUILD_TOKEN }}@git.datadunia.com/".insteadOf "https://git.datadunia.com/"
|
||||||
- uses: actions/setup-go@v5
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.25'
|
go-version: '1.26'
|
||||||
- name: Test
|
- name: Test
|
||||||
|
working-directory: apps/device-agent
|
||||||
run: go test ./... -cover
|
run: go test ./... -cover
|
||||||
|
|
||||||
dashboard-test:
|
dashboard-test:
|
||||||
|
if: contains(gitea.ref_name, 'test') || (!contains(gitea.ref_name, 'dev') && !contains(gitea.ref_name, 'beta'))
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: apps/dashboard-ui
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -65,103 +64,52 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
token: ${{ secrets.BUILD_TOKEN }}
|
token: ${{ secrets.BUILD_TOKEN }}
|
||||||
persist-credentials: true
|
persist-credentials: true
|
||||||
github-server-url: 'https://git.datadunia.com'
|
- name: Configure git auth for submodules
|
||||||
|
run: git config --global url."https://x-access-token:${{ secrets.BUILD_TOKEN }}@git.datadunia.com/".insteadOf "https://git.datadunia.com/"
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '24'
|
node-version: '24'
|
||||||
- name: Install
|
- name: Install
|
||||||
run: npm ci || npm install
|
|
||||||
- name: Build
|
|
||||||
run: npm run build
|
|
||||||
|
|
||||||
# ──────────────────────────────────────────────
|
|
||||||
# BUILD — binaries + frontend dist
|
|
||||||
# ──────────────────────────────────────────────
|
|
||||||
server-core-build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: server-core-test
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: apps/server-core
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
token: ${{ secrets.BUILD_TOKEN }}
|
|
||||||
persist-credentials: true
|
|
||||||
github-server-url: 'https://git.datadunia.com'
|
|
||||||
- uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: '1.25'
|
|
||||||
- name: Build
|
|
||||||
run: go build -o bin/server-core .
|
|
||||||
- name: Upload binary
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: server-core-linux-amd64
|
|
||||||
path: apps/server-core/bin/server-core
|
|
||||||
|
|
||||||
device-agent-cross-build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: device-agent-test
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
goos: [linux, windows]
|
|
||||||
goarch: [amd64, arm64]
|
|
||||||
exclude:
|
|
||||||
- goos: windows
|
|
||||||
goarch: arm64
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: apps/device-agent
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
token: ${{ secrets.BUILD_TOKEN }}
|
|
||||||
persist-credentials: true
|
|
||||||
github-server-url: 'https://git.datadunia.com'
|
|
||||||
- uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: '1.25'
|
|
||||||
- name: Build
|
|
||||||
env:
|
|
||||||
CGO_ENABLED: 0
|
|
||||||
GOOS: ${{ matrix.goos }}
|
|
||||||
GOARCH: ${{ matrix.goarch }}
|
|
||||||
run: |
|
|
||||||
EXT=""
|
|
||||||
if [ "${{ matrix.goos }}" = "windows" ]; then EXT=".exe"; fi
|
|
||||||
go build -o bin/nexus-device-agent-${{ matrix.goos }}-${{ matrix.goarch }}${EXT} .
|
|
||||||
- name: Upload artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: nexus-device-agent-${{ matrix.goos }}-${{ matrix.goarch }}
|
|
||||||
path: apps/device-agent/bin/nexus-device-agent-*
|
|
||||||
|
|
||||||
dashboard-dist:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: dashboard-test
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: apps/dashboard-ui
|
working-directory: apps/dashboard-ui
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
token: ${{ secrets.BUILD_TOKEN }}
|
|
||||||
github-server-url: 'https://git.datadunia.com'
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '24'
|
|
||||||
- name: Install
|
|
||||||
run: npm ci || npm install
|
run: npm ci || npm install
|
||||||
- name: Build
|
- name: Build
|
||||||
|
working-directory: apps/dashboard-ui
|
||||||
run: npm run build
|
run: npm run build
|
||||||
- name: Upload dist
|
|
||||||
uses: actions/upload-artifact@v4
|
# --- BUILD + RELEASE (dev/beta/release tags) ---
|
||||||
|
build-server-core:
|
||||||
|
if: always() && !contains(gitea.ref_name, 'test') && !failure()
|
||||||
|
needs: [server-core-test, device-agent-test, dashboard-test]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
uses: ./.gitea/workflows/build_server_core.yaml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
build-device-agent:
|
||||||
|
if: always() && !contains(gitea.ref_name, 'test') && !failure()
|
||||||
|
needs: [server-core-test, device-agent-test, dashboard-test]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
uses: ./.gitea/workflows/build_device_agent.yaml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
build-dashboard:
|
||||||
|
if: always() && !contains(gitea.ref_name, 'test') && !failure()
|
||||||
|
needs: [server-core-test, device-agent-test, dashboard-test]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
uses: ./.gitea/workflows/build_dashboard.yaml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
build-docs:
|
||||||
|
if: always() && !contains(gitea.ref_name, 'test') && !failure()
|
||||||
|
needs: [server-core-test, device-agent-test, dashboard-test]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
uses: ./.gitea/workflows/docs_call.yaml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
release:
|
||||||
|
if: always() && !contains(gitea.ref_name, 'test') && !failure()
|
||||||
|
needs: [build-server-core, build-device-agent, build-dashboard, build-docs]
|
||||||
|
uses: ./.gitea/workflows/release_call.yaml
|
||||||
with:
|
with:
|
||||||
name: dashboard-ui-dist
|
prerelease: ${{ contains(gitea.ref_name, 'dev') }}
|
||||||
path: apps/dashboard-ui/dist/
|
draft: ${{ contains(gitea.ref_name, 'beta') }}
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
|||||||
@@ -1,207 +0,0 @@
|
|||||||
name: Deploy
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
prerelease:
|
|
||||||
description: 'Mark as prerelease'
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-and-release:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Clone main repository
|
|
||||||
run: |
|
|
||||||
git config --global --remove-section http || true
|
|
||||||
git config --global --unset-all core.askPass || true
|
|
||||||
TOKEN="${{ secrets.BUILD_TOKEN }}"
|
|
||||||
git clone -c credential.helper="" \
|
|
||||||
https://token:$TOKEN@git.datadunia.com/nexusguard/Nexus-Guard-Suite.git .
|
|
||||||
- name: Clone submodules
|
|
||||||
run: |
|
|
||||||
TOKEN="${{ secrets.BUILD_TOKEN }}"
|
|
||||||
# Server Core
|
|
||||||
git clone -c credential.helper="" \
|
|
||||||
https://token:$TOKEN@git.datadunia.com/nexusguard/nexus-server-core.git apps/server-core
|
|
||||||
# Device Agent
|
|
||||||
git clone -c credential.helper="" \
|
|
||||||
https://token:$TOKEN@git.datadunia.com/nexusguard/nexus-device-agent.git apps/device-agent
|
|
||||||
# Dashboard UI
|
|
||||||
git clone -c credential.helper="" \
|
|
||||||
https://token:$TOKEN@git.datadunia.com/nexusguard/nexus-dashboard-ui.git apps/dashboard-ui
|
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: '1.25'
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '24'
|
|
||||||
- name: Download Go modules
|
|
||||||
run: |
|
|
||||||
cd apps/server-core
|
|
||||||
go mod download
|
|
||||||
- name: Generate Swagger docs
|
|
||||||
run: |
|
|
||||||
go install github.com/swaggo/swag/cmd/swag@v1.16.6
|
|
||||||
cd apps/server-core
|
|
||||||
swag init -g main.go --parseDependency --parseInternal
|
|
||||||
- name: Build Server Core
|
|
||||||
run: |
|
|
||||||
cd apps/server-core
|
|
||||||
go build -o bin/server-core .
|
|
||||||
- name: Build Device Agent Cross-platform
|
|
||||||
run: |
|
|
||||||
cd apps/device-agent
|
|
||||||
# Linux amd64
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/nexus-device-agent-linux-amd64 .
|
|
||||||
# Linux arm64
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o bin/nexus-device-agent-linux-arm64 .
|
|
||||||
# Windows amd64
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o bin/nexus-device-agent-windows-amd64.exe .
|
|
||||||
- name: Build Dashboard UI
|
|
||||||
run: |
|
|
||||||
cd apps/dashboard-ui
|
|
||||||
npm ci || npm install
|
|
||||||
npm run build
|
|
||||||
- name: Generate latest.json
|
|
||||||
run: |
|
|
||||||
VERSION="${{ gitea.ref_name }}"
|
|
||||||
RELEASE_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
|
|
||||||
REPO="${{ gitea.repository }}"
|
|
||||||
SERVER="${{ gitea.server_url }}"
|
|
||||||
cat > latest.json << ENDJSON
|
|
||||||
{
|
|
||||||
"version": "$VERSION",
|
|
||||||
"release_date": "$RELEASE_DATE",
|
|
||||||
"download_urls": {
|
|
||||||
"server-core": "${SERVER}/${REPO}/releases/download/${VERSION}/server-core-linux-amd64",
|
|
||||||
"device-agent-linux-amd64": "${SERVER}/${REPO}/releases/download/${VERSION}/nexus-device-agent-linux-amd64",
|
|
||||||
"device-agent-linux-arm64": "${SERVER}/${REPO}/releases/download/${VERSION}/nexus-device-agent-linux-arm64",
|
|
||||||
"device-agent-windows-amd64": "${SERVER}/${REPO}/releases/download/${VERSION}/nexus-device-agent-windows-amd64.exe",
|
|
||||||
"dashboard-ui": "${SERVER}/${REPO}/releases/download/${VERSION}/dashboard-ui-dist.tar.gz"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ENDJSON
|
|
||||||
- name: Create Release and upload assets
|
|
||||||
env:
|
|
||||||
TOKEN: ${{ secrets.BUILD_TOKEN }}
|
|
||||||
run: |
|
|
||||||
if [ -z "$TOKEN" ]; then
|
|
||||||
echo "Value: [EMPTY]"
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "Length: ${#TOKEN} characters"
|
|
||||||
fi
|
|
||||||
|
|
||||||
REPO="${{ gitea.repository }}"
|
|
||||||
TAG="${{ gitea.ref_name }}"
|
|
||||||
API="${{ gitea.server_url }}/api/v1"
|
|
||||||
|
|
||||||
# 0. Check & Delete Existing Release
|
|
||||||
echo "=== 0. Check & Delete Existing Release ==="
|
|
||||||
EXISTING_RESP=$(curl -s -H "Authorization: token $TOKEN" "$API/repos/$REPO/releases/tags/$TAG")
|
|
||||||
EXISTING_ID=$(echo "$EXISTING_RESP" | grep -o '"id":[0-9]*' | head -n 1 | cut -d':' -f2 || true)
|
|
||||||
|
|
||||||
if [ -n "$EXISTING_ID" ] && [ "$EXISTING_ID" != "null" ]; then
|
|
||||||
echo "⚠️ Found existing release for tag $TAG with ID: $EXISTING_ID. Deleting..."
|
|
||||||
DELETE_RESP=$(curl -s -w "\n%{http_code}" -X DELETE -H "Authorization: token $TOKEN" "$API/repos/$REPO/releases/$EXISTING_ID")
|
|
||||||
echo "✅ Delete response: $DELETE_RESP"
|
|
||||||
else
|
|
||||||
echo "No existing release found for $TAG. Proceeding..."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 1. Create Release
|
|
||||||
echo "=== 1. Create New Release ==="
|
|
||||||
JSON_BODY=$(printf '{"tag_name":"%s","name":"%s","body":"Release %s","draft":false,"prerelease":%s}' "$TAG" "$TAG" "$TAG" "${{ inputs.prerelease }}")
|
|
||||||
|
|
||||||
RELEASE_RESP=$(curl -s -X POST \
|
|
||||||
-H "Authorization: token $TOKEN" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d "$JSON_BODY" \
|
|
||||||
"$API/repos/$REPO/releases")
|
|
||||||
|
|
||||||
# Ambil ID dengan lebih teliti
|
|
||||||
# Tambahkan || true agar grep tidak membuat script crash (karena set -e) jika id tidak ditemukan
|
|
||||||
RELEASE_ID=$(echo "$RELEASE_RESP" | grep -o '"id":[0-9]*' | head -n 1 | cut -d':' -f2 || true)
|
|
||||||
|
|
||||||
if [ -z "$RELEASE_ID" ] || [ "$RELEASE_ID" = "null" ]; then
|
|
||||||
echo "Gagal membuat release. Response: $RELEASE_RESP"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Release ID: $RELEASE_ID"
|
|
||||||
|
|
||||||
# 2. Upload Assets
|
|
||||||
# Server Core
|
|
||||||
if [ -f "apps/server-core/bin/server-core" ]; then
|
|
||||||
echo "Uploading server-core-linux-amd64..."
|
|
||||||
curl -s -X POST \
|
|
||||||
-H "Authorization: token $TOKEN" \
|
|
||||||
-F "attachment=@apps/server-core/bin/server-core" \
|
|
||||||
"$API/repos/$REPO/releases/$RELEASE_ID/assets?name=server-core-linux-amd64"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Device Agent Linux amd64
|
|
||||||
if [ -f "apps/device-agent/bin/nexus-device-agent-linux-amd64" ]; then
|
|
||||||
echo "Uploading nexus-device-agent-linux-amd64..."
|
|
||||||
curl -s -X POST \
|
|
||||||
-H "Authorization: token $TOKEN" \
|
|
||||||
-F "attachment=@apps/device-agent/bin/nexus-device-agent-linux-amd64" \
|
|
||||||
"$API/repos/$REPO/releases/$RELEASE_ID/assets?name=nexus-device-agent-linux-amd64"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Device Agent Linux arm64
|
|
||||||
if [ -f "apps/device-agent/bin/nexus-device-agent-linux-arm64" ]; then
|
|
||||||
echo "Uploading nexus-device-agent-linux-arm64..."
|
|
||||||
curl -s -X POST \
|
|
||||||
-H "Authorization: token $TOKEN" \
|
|
||||||
-F "attachment=@apps/device-agent/bin/nexus-device-agent-linux-arm64" \
|
|
||||||
"$API/repos/$REPO/releases/$RELEASE_ID/assets?name=nexus-device-agent-linux-arm64"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Device Agent Windows amd64
|
|
||||||
if [ -f "apps/device-agent/bin/nexus-device-agent-windows-amd64.exe" ]; then
|
|
||||||
echo "Uploading nexus-device-agent-windows-amd64.exe..."
|
|
||||||
curl -s -X POST \
|
|
||||||
-H "Authorization: token $TOKEN" \
|
|
||||||
-F "attachment=@apps/device-agent/bin/nexus-device-agent-windows-amd64.exe" \
|
|
||||||
"$API/repos/$REPO/releases/$RELEASE_ID/assets?name=nexus-device-agent-windows-amd64.exe"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Dashboard UI dist
|
|
||||||
if [ -d "apps/dashboard-ui/dist" ]; then
|
|
||||||
echo "Creating dashboard-ui-dist.tar.gz..."
|
|
||||||
cd apps/dashboard-ui
|
|
||||||
tar -czf ../dashboard-ui-dist.tar.gz dist/
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
echo "Uploading dashboard-ui-dist.tar.gz..."
|
|
||||||
curl -s -X POST \
|
|
||||||
-H "Authorization: token $TOKEN" \
|
|
||||||
-F "attachment=@dashboard-ui-dist.tar.gz" \
|
|
||||||
"$API/repos/$REPO/releases/$RELEASE_ID/assets?name=dashboard-ui-dist.tar.gz"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# latest.json
|
|
||||||
if [ -f "latest.json" ]; then
|
|
||||||
echo "Uploading latest.json..."
|
|
||||||
curl -s -X POST \
|
|
||||||
-H "Authorization: token $TOKEN" \
|
|
||||||
-F "attachment=@latest.json" \
|
|
||||||
"$API/repos/$REPO/releases/$RELEASE_ID/assets?name=latest.json"
|
|
||||||
fi
|
|
||||||
- name: Cleanup build artifacts
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
git config --global --remove-section http || true
|
|
||||||
git config --global --unset-all core.askPass || true
|
|
||||||
rm -f latest.json dashboard-ui-dist.tar.gz
|
|
||||||
rm -rf apps/server-core/bin apps/device-agent/bin apps/dashboard-ui/node_modules apps/dashboard-ui/dist
|
|
||||||
echo "Cleanup done"
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
name: Build Docs
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Configure git auth for submodules
|
||||||
|
run: git config --global url."https://x-access-token:${{ secrets.BUILD_TOKEN }}@git.datadunia.com/".insteadOf "https://git.datadunia.com/"
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.BUILD_TOKEN }}
|
||||||
|
persist-credentials: true
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '24'
|
||||||
|
|
||||||
|
- name: Install
|
||||||
|
working-directory: apps/docs
|
||||||
|
run: npm ci || npm install
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
working-directory: apps/docs
|
||||||
|
run: npm run docs:build
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: docs-dist
|
||||||
|
path: apps/docs/.vitepress/dist/
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
name: Release
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- 'v[0-9]*.[0-9]*.[0-9]'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
deploy:
|
|
||||||
if: "!contains(gitea.ref_name, 'beta') && !contains(gitea.ref_name, 'test')"
|
|
||||||
uses: ./.gitea/workflows/deploy_call.yaml
|
|
||||||
with:
|
|
||||||
prerelease: false
|
|
||||||
secrets: inherit
|
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
prerelease:
|
||||||
|
description: 'Mark as prerelease'
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
draft:
|
||||||
|
description: 'Mark as draft'
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Configure git auth for submodules
|
||||||
|
run: git config --global url."https://x-access-token:${{ secrets.BUILD_TOKEN }}@git.datadunia.com/".insteadOf "https://git.datadunia.com/"
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.BUILD_TOKEN }}
|
||||||
|
persist-credentials: true
|
||||||
|
|
||||||
|
- name: Download all artifacts
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
path: ./artifacts
|
||||||
|
|
||||||
|
- name: Generate latest.json
|
||||||
|
run: |
|
||||||
|
VERSION="${{ gitea.ref_name }}"
|
||||||
|
RELEASE_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
|
||||||
|
REPO="${{ gitea.repository }}"
|
||||||
|
SERVER="${{ gitea.server_url }}"
|
||||||
|
cat > latest.json << ENDJSON
|
||||||
|
{
|
||||||
|
"version": "$VERSION",
|
||||||
|
"release_date": "$RELEASE_DATE",
|
||||||
|
"download_urls": {
|
||||||
|
"server-core": "${SERVER}/${REPO}/releases/download/${VERSION}/server-core-linux-amd64",
|
||||||
|
"device-agent-linux-amd64": "${SERVER}/${REPO}/releases/download/${VERSION}/nexus-device-agent-linux-amd64",
|
||||||
|
"device-agent-linux-arm64": "${SERVER}/${REPO}/releases/download/${VERSION}/nexus-device-agent-linux-arm64",
|
||||||
|
"device-agent-windows-amd64": "${SERVER}/${REPO}/releases/download/${VERSION}/nexus-device-agent-windows-amd64.exe",
|
||||||
|
"dashboard-ui": "${SERVER}/${REPO}/releases/download/${VERSION}/dashboard-ui-dist.tar.gz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ENDJSON
|
||||||
|
|
||||||
|
- name: Create Release and upload assets
|
||||||
|
env:
|
||||||
|
TOKEN: ${{ secrets.BUILD_TOKEN }}
|
||||||
|
run: |
|
||||||
|
REPO="${{ gitea.repository }}"
|
||||||
|
TAG="${{ gitea.ref_name }}"
|
||||||
|
API="${{ gitea.server_url }}/api/v1"
|
||||||
|
|
||||||
|
# Delete existing release if present
|
||||||
|
EXISTING_ID=$(curl -s -H "Authorization: token $TOKEN" "$API/repos/$REPO/releases/tags/$TAG" | grep -o '"id":[0-9]*' | head -n 1 | cut -d':' -f2 || true)
|
||||||
|
if [ -n "$EXISTING_ID" ] && [ "$EXISTING_ID" != "null" ]; then
|
||||||
|
echo "Deleting existing release $EXISTING_ID..."
|
||||||
|
curl -s -X DELETE -H "Authorization: token $TOKEN" "$API/repos/$REPO/releases/$EXISTING_ID"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create release
|
||||||
|
JSON_BODY=$(printf '{"tag_name":"%s","name":"%s","body":"Release %s","draft":%s,"prerelease":%s}' "$TAG" "$TAG" "$TAG" "${{ inputs.draft }}" "${{ inputs.prerelease }}")
|
||||||
|
RELEASE_RESP=$(curl -s -X POST \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "$JSON_BODY" \
|
||||||
|
"$API/repos/$REPO/releases")
|
||||||
|
|
||||||
|
RELEASE_ID=$(echo "$RELEASE_RESP" | grep -o '"id":[0-9]*' | head -n 1 | cut -d':' -f2 || true)
|
||||||
|
if [ -z "$RELEASE_ID" ] || [ "$RELEASE_ID" = "null" ]; then
|
||||||
|
echo "Failed to create release. Response: $RELEASE_RESP"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Release ID: $RELEASE_ID"
|
||||||
|
|
||||||
|
# Upload assets
|
||||||
|
upload_asset() {
|
||||||
|
local file="$1"
|
||||||
|
local name="$2"
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
echo "Uploading $name..."
|
||||||
|
curl -s -X POST \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
-F "attachment=@$file" \
|
||||||
|
"$API/repos/$REPO/releases/$RELEASE_ID/assets?name=$name"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Server Core
|
||||||
|
upload_asset "artifacts/server-core-linux-amd64/server-core" "server-core-linux-amd64"
|
||||||
|
|
||||||
|
# Device Agent (all platforms)
|
||||||
|
for platform in linux-amd64 linux-arm64 windows-amd64; do
|
||||||
|
EXT=""
|
||||||
|
if [ "$platform" = "windows-amd64" ]; then EXT=".exe"; fi
|
||||||
|
upload_asset "artifacts/nexus-device-agent-${platform}/nexus-device-agent-${platform}${EXT}" "nexus-device-agent-${platform}${EXT}"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Dashboard UI tar.gz
|
||||||
|
if [ -d "artifacts/dashboard-ui-dist/dist" ]; then
|
||||||
|
cd artifacts/dashboard-ui-dist
|
||||||
|
tar -czf ../../dashboard-ui-dist.tar.gz dist/
|
||||||
|
cd ../..
|
||||||
|
upload_asset "dashboard-ui-dist.tar.gz" "dashboard-ui-dist.tar.gz"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Docs tar.gz
|
||||||
|
if [ -d "artifacts/docs-dist" ]; then
|
||||||
|
cd artifacts/docs-dist
|
||||||
|
tar -czf ../../docs-dist.tar.gz ./
|
||||||
|
cd ../..
|
||||||
|
upload_asset "docs-dist.tar.gz" "docs-dist.tar.gz"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# latest.json
|
||||||
|
upload_asset "latest.json" "latest.json"
|
||||||
|
|
||||||
|
- name: Cleanup
|
||||||
|
if: always()
|
||||||
|
run: rm -rf artifacts/ latest.json dashboard-ui-dist.tar.gz docs-dist.tar.gz
|
||||||
+13
-2
@@ -30,6 +30,7 @@ nexusguard.conf
|
|||||||
# Temp
|
# Temp
|
||||||
tmp/
|
tmp/
|
||||||
temp_*
|
temp_*
|
||||||
|
*-test
|
||||||
*.tmp
|
*.tmp
|
||||||
|
|
||||||
# Build output
|
# Build output
|
||||||
@@ -37,11 +38,21 @@ dist/
|
|||||||
/dist/
|
/dist/
|
||||||
|
|
||||||
# OpenCode
|
# OpenCode
|
||||||
|
connect_remote.txt
|
||||||
|
.update-state
|
||||||
|
|
||||||
|
# Scripts (contains API tokens)
|
||||||
|
scripts/
|
||||||
|
|
||||||
|
# Oh-My-OpenAgent & Sisyphus plugin files
|
||||||
|
.omo/
|
||||||
|
.sisyphus/
|
||||||
.sisyphus/notepads/
|
.sisyphus/notepads/
|
||||||
.sisyphus/boulder.json
|
.sisyphus/boulder.json
|
||||||
connect_remote.txt
|
|
||||||
.sisyphus/drafts/
|
.sisyphus/drafts/
|
||||||
.update-state
|
.omo/notepads/
|
||||||
|
.omo/boulder.json
|
||||||
|
.omo/drafts/
|
||||||
|
|
||||||
# Node
|
# Node
|
||||||
node_modules/
|
node_modules/
|
||||||
|
|||||||
+3
-3
@@ -1,9 +1,9 @@
|
|||||||
[submodule "apps/server-core"]
|
[submodule "apps/server-core"]
|
||||||
path = apps/server-core
|
path = apps/server-core
|
||||||
url = http://git.datadunia.com/nexusguard/nexus-server-core.git
|
url = https://git.datadunia.com/nexusguard/nexus-server-core.git
|
||||||
[submodule "apps/dashboard-ui"]
|
[submodule "apps/dashboard-ui"]
|
||||||
path = apps/dashboard-ui
|
path = apps/dashboard-ui
|
||||||
url = http://git.datadunia.com/nexusguard/nexus-dashboard-ui.git
|
url = https://git.datadunia.com/nexusguard/nexus-dashboard-ui.git
|
||||||
[submodule "apps/device-agent"]
|
[submodule "apps/device-agent"]
|
||||||
path = apps/device-agent
|
path = apps/device-agent
|
||||||
url = http://git.datadunia.com/nexusguard/nexus-device-agent.git
|
url = https://git.datadunia.com/nexusguard/nexus-device-agent.git
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
# Bug Fixes and Features Plan
|
||||||
|
|
||||||
|
## Bug Fixes
|
||||||
|
|
||||||
|
### 1. Nodes Edit Button - Hard to Click / Wrong HTML Tag Location
|
||||||
|
**Location**: apps/dashboard-ui/src/views/Servers.vue - Node cards edit button
|
||||||
|
**Issue**: Edit button on node cards is difficult to click or has incorrect HTML structure
|
||||||
|
**Root Cause**: Button z-index, positioning, or overlapping elements
|
||||||
|
**Files**: Servers.vue (lines 155-157)
|
||||||
|
**Status**: ✅ DONE - Changed button size from "sm" to "md" for better clickability
|
||||||
|
|
||||||
|
### 2. Dashboard - Missing Turn On WireGuard Button for 2nd+ Nodes
|
||||||
|
**Location**: apps/dashboard-ui/src/views/Servers.vue and apps/server-core/api/wg.go
|
||||||
|
**Issue**: Only first node (Local Primary Node) has WG Up/Down buttons; additional nodes lack toggle
|
||||||
|
**Root Cause**: wg.go Status/Up/Down handlers only work with hardcoded wg0 interface; multi-interface support needed
|
||||||
|
**Files**:
|
||||||
|
- apps/dashboard-ui/src/views/Servers.vue - Add WG toggle button per node
|
||||||
|
- apps/server-core/api/wg.go - Fix to accept interface name parameter
|
||||||
|
- apps/server-core/internal/wgmanager/wgmanager_linux.go - Ensure multi-interface support
|
||||||
|
**Status**: ✅ BACKEND DONE - wg.go accepts interface param, queries by interface_name, supports multi-interface
|
||||||
|
**Status**: ✅ FRONTEND DONE - WG Up/Down buttons added to node cards, calls API with interface param
|
||||||
|
|
||||||
|
### 3. Advanced Node Settings - Missing Notes/Descriptions for PreUp, PostUp, PreDown, PostDown
|
||||||
|
**Location**: apps/dashboard-ui/src/views/Servers.vue (lines 83-98)
|
||||||
|
**Issue**: Advanced scripts fields (PreUp, PostUp, PreDown, PostDown) lack helper text/descriptions like Firewall section has
|
||||||
|
**Files**: Servers.vue - Add hints/descriptions similar to FirewallEditor
|
||||||
|
**Status**: ✅ DONE - Added descriptive hints for Table, PreUp, PostUp, PreDown, PostDown
|
||||||
|
|
||||||
|
### 4. Popup/Modal Inconsistency - Backdrop Styling
|
||||||
|
**Location**: Multiple modals in Servers.vue, Devices.vue, DeviceDetail.vue, FirewallEditor.vue
|
||||||
|
**Issue**: Nodes modal backdrop styling is better than Devices modal; inconsistent across views
|
||||||
|
**Files**: Standardize modal wrapper component or CSS classes
|
||||||
|
**Status**: ✅ DONE - Servers.vue modals converted to NgModal, consistent backdrop (bg-bg-overlay)
|
||||||
|
|
||||||
|
### 5. Firewall Popup - Not User/Mobile Friendly
|
||||||
|
**Location**: apps/dashboard-ui/src/components/FirewallEditor.vue
|
||||||
|
**Issue**: Form layout not responsive; input fields too small on mobile; buttons not touch-friendly
|
||||||
|
**Files**: FirewallEditor.vue - Responsive grid, larger touch targets, better spacing
|
||||||
|
**Status**: ✅ DONE - Responsive grid (1/2/5 cols), button full width on mobile, table scroll-x-auto
|
||||||
|
|
||||||
|
### 6. Firewall wg_isolation - Verify Implementation Matches Plan
|
||||||
|
**Location**: apps/server-core/internal/firewall/nftables_linux.go - InitNetworkForServer()
|
||||||
|
**Issue**: Verify wg_isolation rules are correctly implemented per-server with smart isolation (allow server IP, drop peer-to-peer)
|
||||||
|
**Files**: nftables_linux.go - InitNetworkForServer() and TeardownNetworkForServer()
|
||||||
|
**Status**: ✅ DONE - Implementation verified: smart isolation (server IP allow, peer-to-peer drop), per-interface chains with jump rules, proper cleanup
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### 1. Traffic Record Table - Only Show Records with RX or TX Data
|
||||||
|
**Location**: apps/dashboard-ui/src/views/TrafficHistory.vue, apps/server-core/api/traffic.go, apps/server-core/internal/traffic/recorder.go
|
||||||
|
**Issue**: Table shows all records including zero-byte entries; should filter to only show records with rx > 0 or tx > 0
|
||||||
|
**Files**:
|
||||||
|
- TrafficHistory.vue - Filter trafficData before display
|
||||||
|
- traffic.go - Add filter option to API
|
||||||
|
**Status**: ✅ DONE - Added has_traffic query param, toggle in UI, backend filtering (rx>0 OR tx>0)
|
||||||
|
|
||||||
|
### 2. Traffic Record Table - Sum Per Hour Aggregation
|
||||||
|
**Location**: apps/server-core/api/traffic.go, apps/server-core/internal/traffic/recorder.go
|
||||||
|
**Issue**: Add hourly aggregation option for traffic table when query supports it
|
||||||
|
**Files**:
|
||||||
|
- traffic.go - Add aggregation parameter to GetSummary/GetDeviceTraffic
|
||||||
|
- recorder.go - Add GetHourlyTraffic method with SQL GROUP BY hour
|
||||||
|
**Status**: ✅ DONE - Added GetHourlyTraffic endpoint with SQL GROUP BY hour, returns HourlyTraffic[]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementation Priority
|
||||||
|
|
||||||
|
| Priority | Task | Category |
|
||||||
|
|----------|------|----------|
|
||||||
|
| P1 | Nodes edit button fix | Bug |
|
||||||
|
| P1 | Dashboard WG toggle for all nodes | Bug |
|
||||||
|
| P1 | Verify wg_isolation implementation | Bug |
|
||||||
|
| P2 | Advanced settings descriptions | Bug |
|
||||||
|
| P2 | Modal consistency (backdrop) | Bug |
|
||||||
|
| P2 | Firewall mobile-friendly | Bug |
|
||||||
|
| P2 | Traffic table filter (RX/TX > 0) | Feature |
|
||||||
|
| P3 | Traffic hourly aggregation | Feature |
|
||||||
|
| P3 | Firewall mobile-friendly | Bug |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Code Structure Reference
|
||||||
|
|
||||||
|
### Frontend (Vue 3 + TypeScript)
|
||||||
|
apps/dashboard-ui/src/
|
||||||
|
|-- views/
|
||||||
|
| |-- Servers.vue # Node management (edit, WG toggle, advanced)
|
||||||
|
| |-- Devices.vue # Device list, firewall
|
||||||
|
| |-- DeviceDetail.vue # Device detail, firewall editor
|
||||||
|
| |-- TrafficHistory.vue # Traffic table, filters
|
||||||
|
| |-- ...
|
||||||
|
|-- components/
|
||||||
|
| |-- FirewallEditor.vue # Firewall rules UI
|
||||||
|
| |-- ui/ # Ng* design system components
|
||||||
|
| |-- ...
|
||||||
|
|-- ...
|
||||||
|
|
||||||
|
### Backend (Go)
|
||||||
|
apps/server-core/
|
||||||
|
|-- api/
|
||||||
|
| |-- servers.go # Node CRUD, WG Up/Down
|
||||||
|
| |-- wg.go # WG interface control
|
||||||
|
| |-- traffic.go # Traffic API
|
||||||
|
| |-- ...
|
||||||
|
|-- internal/
|
||||||
|
| |-- firewall/
|
||||||
|
| | |-- nftables_linux.go # InitNetworkForServer, Teardown
|
||||||
|
| | |-- ...
|
||||||
|
| |-- wgmanager/
|
||||||
|
| | |-- wgmanager_linux.go # Multi-interface WgManager
|
||||||
|
| |-- traffic/
|
||||||
|
| |-- recorder.go # Traffic queries
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
1. Create detailed task breakdown for each bug/feature
|
||||||
|
2. Start with P1 bugs (edit button, WG toggle, wg_isolation)
|
||||||
|
3. Implement fixes following existing code patterns
|
||||||
|
5. Archive completed plan when done
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- All plans from .sisyphus have been migrated to .omo/plans/archive/
|
||||||
|
- New plan saved at .omo/plans/bugfixes-and-features.md
|
||||||
|
- Evidence, notepads, references migrated to .omo/
|
||||||
|
- Boulder state copied to .omo/boulder.json
|
||||||
@@ -0,0 +1,387 @@
|
|||||||
|
# Firewall InitNetwork Fix — INPUT vs FORWARD Chain Bugs
|
||||||
|
|
||||||
|
## TL;DR
|
||||||
|
|
||||||
|
> **Quick Summary**: Fix 3 bugs in `InitNetwork()` that prevent WireGuard clients from reaching the server and Docker containers. ICMP echo-reply blocked, Docker DNAT traffic dropped, and missing base INPUT rules.
|
||||||
|
>
|
||||||
|
> **Deliverables**:
|
||||||
|
> - Fixed `nftables_linux.go` InitNetwork() with correct ICMP, Docker bridge, and INPUT rules
|
||||||
|
> - Updated `manager.go` if needed
|
||||||
|
> - Server rebuilt and deployed via `update.sh --force`
|
||||||
|
>
|
||||||
|
> **Estimated Effort**: Short
|
||||||
|
> **Parallel Execution**: YES - 2 waves
|
||||||
|
> **Critical Path**: Task 1 → Task 4 (verify)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
### Original Request
|
||||||
|
User reported firewall rules from dashboard not working. Traced through multiple debugging sessions to find 3 root-cause bugs in `InitNetwork()` base rules:
|
||||||
|
1. `icmp type echo-request` only allows incoming pings TO server, not echo-reply FROM peers
|
||||||
|
2. No FORWARD rules for Docker bridge — WireGuard traffic DNAT'd to containers gets dropped
|
||||||
|
3. Server→peer traffic works (OUTPUT default accept) but replies hit INPUT chain and get dropped
|
||||||
|
|
||||||
|
### Interview Summary
|
||||||
|
- **Key Discussions**: Extensive debugging on live server (172.20.8.191). User tested each fix manually via SSH. Confirmed Docker DNAT intercepts port 80 traffic via iptables PREROUTING, redirecting to container 172.24.0.4.
|
||||||
|
- **Research Findings**: Docker uses iptables DNAT while NexusGuard uses nftables filter — both coexist. Traffic flow: WireGuard → INPUT (nftables) → ACCEPT → Docker PREROUTING (iptables DNAT) → destination changes to container IP → FORWARD chain (nftables) → DROP (no bridge rule).
|
||||||
|
- **User Constraints**: No local binary builds (Docker only). No temp/debug files. Admin-only firewall (JWT protected).
|
||||||
|
|
||||||
|
### Metis Review (if consulted)
|
||||||
|
N/A — bugs are clear from source code analysis, no ambiguity requiring consultation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Work Objectives
|
||||||
|
|
||||||
|
### Core Objective
|
||||||
|
Fix 3 bugs in `InitNetwork()` that prevent WireGuard peer-to-server and peer-to-Docker-container connectivity.
|
||||||
|
|
||||||
|
### Concrete Deliverables
|
||||||
|
- Fixed `apps/server-core/internal/firewall/nftables_linux.go` InitNetwork()
|
||||||
|
- Fixed `apps/server-core/internal/firewall/manager.go` if interface changes needed
|
||||||
|
- Server rebuilt and deployed
|
||||||
|
- nftables verified working on live server
|
||||||
|
|
||||||
|
### Definition of Done
|
||||||
|
- [ ] `nft list chain ip nexusguard input` shows `meta l4proto icmp accept` (not `icmp type echo-request`)
|
||||||
|
- [ ] `nft list chain ip nexusguard forward` shows `fwd_wg_docker` rules for 172.24.0.0/16 and 172.17.0.0/16
|
||||||
|
- [ ] Client (gogo3 10.172.21.3) can ping server (10.172.21.1)
|
||||||
|
- [ ] Server (10.172.21.1) can ping client (10.172.21.3)
|
||||||
|
- [ ] Client can curl http://10.172.21.1:80 and get 200
|
||||||
|
|
||||||
|
### Must Have
|
||||||
|
- `meta l4proto icmp` replaces `icmp type echo-request` in INPUT chain
|
||||||
|
- `fwd_wg_docker` rules added to FORWARD chain in InitNetwork()
|
||||||
|
- Existing peer routing rules (AddForwardRule) still work
|
||||||
|
- Existing DB firewall rules (syncRuleToFirewall) still work
|
||||||
|
|
||||||
|
### Must NOT Have (Guardrails)
|
||||||
|
- Do NOT `nft flush table nexusguard` — destroys all rules
|
||||||
|
- Do NOT change the FirewallRule model or API endpoints
|
||||||
|
- Do NOT modify peer_sync.go or devices.go
|
||||||
|
- Do NOT create temp/debug files in project root
|
||||||
|
- Do NOT change the firewall chain routing logic (dest==server→INPUT, else→FORWARD)
|
||||||
|
- Do NOT remove the `input_wg_drop` or `wg_isolation_default` base rules
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification Strategy
|
||||||
|
|
||||||
|
> **ZERO HUMAN INTERVENTION** — ALL verification is agent-executed. No exceptions.
|
||||||
|
|
||||||
|
### Test Decision
|
||||||
|
- **Infrastructure exists**: NO (no nftables unit tests)
|
||||||
|
- **Automated tests**: None (nftables rules tested via live server SSH)
|
||||||
|
- **Framework**: None needed — live server verification
|
||||||
|
|
||||||
|
### QA Policy
|
||||||
|
Every task includes agent-executed QA scenarios.
|
||||||
|
Evidence saved to `.sisyphus/evidence/task-{N}-{scenario-slug}.{ext}`.
|
||||||
|
|
||||||
|
- **nft verification**: SSH to server, run nft commands, verify rules present
|
||||||
|
- **Connectivity**: SSH to server, run ping/curl tests
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Execution Strategy
|
||||||
|
|
||||||
|
### Parallel Execution Waves
|
||||||
|
|
||||||
|
```
|
||||||
|
Wave 1 (Start Immediately — 1 agent):
|
||||||
|
├── Task 1: Fix InitNetwork() in nftables_linux.go (quick)
|
||||||
|
|
||||||
|
Wave 2 (After Wave 1 — 1 agent):
|
||||||
|
├── Task 2: Commit + Push + Deploy (quick)
|
||||||
|
├── Task 3: Verify nft rules on live server (quick)
|
||||||
|
|
||||||
|
Wave FINAL (After Wave 2 — reviewer):
|
||||||
|
├── Task F1: Plan compliance audit (oracle)
|
||||||
|
├── Task F2: Code quality review (unspecified-high)
|
||||||
|
├── Task F3: Real manual QA (unspecified-high)
|
||||||
|
├── Task F4: Scope fidelity check (deep)
|
||||||
|
-> F1-F4 can run in parallel
|
||||||
|
|
||||||
|
Critical Path: Task 1 → Task 2 → Task 3 → F1-F4
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dependency Matrix
|
||||||
|
|
||||||
|
| Task | Depends On | Blocks |
|
||||||
|
|------|-----------|--------|
|
||||||
|
| Task 1 | None | Task 2 |
|
||||||
|
| Task 2 | Task 1 | Task 3 |
|
||||||
|
| Task 3 | Task 2 | F1-F4 |
|
||||||
|
| F1-F4 | Task 3 | None |
|
||||||
|
|
||||||
|
### Agent Dispatch Summary
|
||||||
|
|
||||||
|
- **Wave 1**: T1 → `quick`
|
||||||
|
- **Wave 2**: T2 → `quick`, T3 → `quick`
|
||||||
|
- **FINAL**: F1 → `oracle`, F2 → `unspecified-high`, F3 → `unspecified-high`, F4 → `deep`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TODOs
|
||||||
|
|
||||||
|
- [x] 1. Fix InitNetwork() in nftables_linux.go
|
||||||
|
|
||||||
|
**What to do**:
|
||||||
|
1. In `apps/server-core/internal/firewall/nftables_linux.go`, line 48: change `icmp type echo-request` to `meta l4proto icmp`. Also update the comment from `input_icmp` to `input_icmp_all`.
|
||||||
|
2. In the same function, after the `input_wg_drop` rule block (around line 64), add Docker bridge accept rules to FORWARD chain:
|
||||||
|
- `nft insert rule ip nexusguard forward ip saddr <wgSubnet> ip daddr 172.24.0.0/16 accept comment "fwd_wg_docker"`
|
||||||
|
- `nft insert rule ip nexusguard forward ip saddr <wgSubnet> ip daddr 172.17.0.0/16 accept comment "fwd_wg_docker0"`
|
||||||
|
3. These Docker rules should be inserted AFTER `fwd_estab` and BEFORE the `wg_isolation` drop rule. Use `nft insert rule` with position or append after fwd_estab.
|
||||||
|
4. Add dedup checks (same pattern as existing rules): `grep -q 'fwd_wg_docker'` before inserting.
|
||||||
|
|
||||||
|
**Must NOT do**:
|
||||||
|
- Do NOT change AddForwardRule, AddFirewallRule, AddInputFirewallRule, or RemoveFirewallRule
|
||||||
|
- Do NOT change the chain routing logic in syncRuleToFirewall
|
||||||
|
- Do NOT flush or recreate any chains
|
||||||
|
- Do NOT change manager.go interface
|
||||||
|
|
||||||
|
**Recommended Agent Profile**:
|
||||||
|
- **Category**: `quick`
|
||||||
|
- Reason: Single-file change, 3 specific line edits, clear patterns to follow
|
||||||
|
- **Skills**: []
|
||||||
|
- No special skills needed — straightforward Go code edit
|
||||||
|
|
||||||
|
**Parallelization**:
|
||||||
|
- **Can Run In Parallel**: NO
|
||||||
|
- **Parallel Group**: Wave 1 (solo)
|
||||||
|
- **Blocks**: Task 2 (commit/deploy)
|
||||||
|
- **Blocked By**: None (can start immediately)
|
||||||
|
|
||||||
|
**References**:
|
||||||
|
- `apps/server-core/internal/firewall/nftables_linux.go:25-68` — InitNetwork() function, all 3 bugs are here
|
||||||
|
- `apps/server-core/internal/firewall/nftables_linux.go:30-38` — existing FORWARD chain setup (fwd_estab, wg_isolation) — Docker rules go between these
|
||||||
|
- `apps/server-core/internal/firewall/nftables_linux.go:40-64` — existing INPUT chain setup — ICMP fix at line 48
|
||||||
|
- `apps/server-core/main.go:210-259` — startup re-apply code that calls AddForwardRule and AddInputFirewallRule — do NOT modify
|
||||||
|
- `apps/server-core/internal/firewall/manager.go:5-18` — NetManager interface — do NOT modify
|
||||||
|
|
||||||
|
**Acceptance Criteria**:
|
||||||
|
- [ ] Line 48 reads `meta l4proto icmp` not `icmp type echo-request`
|
||||||
|
- [ ] Comment reads `input_icmp_all` not `input_icmp`
|
||||||
|
- [ ] FORWARD chain has dedup check for `fwd_wg_docker` before inserting
|
||||||
|
- [ ] `go vet ./internal/firewall/...` passes
|
||||||
|
- [ ] No other lines in InitNetwork() changed
|
||||||
|
|
||||||
|
**QA Scenarios**:
|
||||||
|
|
||||||
|
```
|
||||||
|
Scenario: Verify ICMP rule is correct
|
||||||
|
Tool: Bash (grep)
|
||||||
|
Steps:
|
||||||
|
1. grep "meta l4proto icmp" apps/server-core/internal/firewall/nftables_linux.go
|
||||||
|
2. grep "icmp type echo-request" apps/server-core/internal/firewall/nftables_linux.go
|
||||||
|
Expected Result: First grep returns match, second grep returns nothing
|
||||||
|
Evidence: .sisyphus/evidence/task-1-icmp-rule.txt
|
||||||
|
|
||||||
|
Scenario: Verify Docker bridge rules exist
|
||||||
|
Tool: Bash (grep)
|
||||||
|
Steps:
|
||||||
|
1. grep "fwd_wg_docker" apps/server-core/internal/firewall/nftables_linux.go
|
||||||
|
2. grep "172.24.0.0/16" apps/server-core/internal/firewall/nftables_linux.go
|
||||||
|
3. grep "172.17.0.0/16" apps/server-core/internal/firewall/nftables_linux.go
|
||||||
|
Expected Result: All 3 greps return matches
|
||||||
|
Evidence: .sisyphus/evidence/task-1-docker-rules.txt
|
||||||
|
|
||||||
|
Scenario: Verify dedup check pattern
|
||||||
|
Tool: Bash (grep)
|
||||||
|
Steps:
|
||||||
|
1. grep "fwd_wg_docker" apps/server-core/internal/firewall/nftables_linux.go | head -5
|
||||||
|
Expected Result: Shows both the grep check command AND the nft insert command
|
||||||
|
Evidence: .sisyphus/evidence/task-1-dedup-pattern.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
**Commit**: YES
|
||||||
|
- Message: `fix(nftables): InitNetwork ICMP all, Docker bridge accept, base INPUT rules`
|
||||||
|
- Files: `apps/server-core/internal/firewall/nftables_linux.go`
|
||||||
|
- Pre-commit: `go vet ./internal/firewall/...`
|
||||||
|
|
||||||
|
- [x] 2. Commit, Push, Deploy to Server
|
||||||
|
|
||||||
|
**What to do**:
|
||||||
|
1. In `apps/server-core/`: `git add -A && git commit` with the fix message, then `git push`
|
||||||
|
2. In root `Nexus-Guard-Suite/`: `git add apps/server-core && git commit && git push`
|
||||||
|
3. SSH to server: `cd /root/Nexus-Guard-Suite && bash update.sh --force`
|
||||||
|
4. Wait for deployment to complete
|
||||||
|
|
||||||
|
**Must NOT do**:
|
||||||
|
- Do NOT build binary locally
|
||||||
|
- Do NOT create temp files on server
|
||||||
|
- Do NOT use `nft flush` on server
|
||||||
|
- Do NOT modify any code files
|
||||||
|
|
||||||
|
**Recommended Agent Profile**:
|
||||||
|
- **Category**: `quick`
|
||||||
|
- Reason: Simple git + SSH commands, well-documented in AGENTS.md
|
||||||
|
- **Skills**: []
|
||||||
|
|
||||||
|
**Parallelization**:
|
||||||
|
- **Can Run In Parallel**: NO
|
||||||
|
- **Parallel Group**: Wave 2 (solo)
|
||||||
|
- **Blocks**: Task 3 (verify)
|
||||||
|
- **Blocked By**: Task 1 (code change)
|
||||||
|
|
||||||
|
**References**:
|
||||||
|
- `D:\www-project\NexusGuard\connect_remote.txt` — SSH credentials (HOST=172.20.8.191, USER=root)
|
||||||
|
- `D:\www-project\NexusGuard\update.sh` — Docker rebuild script
|
||||||
|
|
||||||
|
**Acceptance Criteria**:
|
||||||
|
- [ ] Submodule HEAD updated (new commit hash)
|
||||||
|
- [ ] Root repo HEAD updated
|
||||||
|
- [ ] Server container restarted successfully
|
||||||
|
- [ ] `docker ps` shows server-core running
|
||||||
|
|
||||||
|
**QA Scenarios**:
|
||||||
|
|
||||||
|
```
|
||||||
|
Scenario: Verify deployment
|
||||||
|
Tool: SSH (bash)
|
||||||
|
Steps:
|
||||||
|
1. ssh root@172.20.8.191 'docker ps | grep server-core'
|
||||||
|
2. ssh root@172.20.8.191 'docker logs nexus-guard-suite-server-core-1 2>&1 | tail -5'
|
||||||
|
Expected Result: Container running, logs show clean startup
|
||||||
|
Evidence: .sisyphus/evidence/task-2-deployment.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
**Commit**: NO (commit done as part of task)
|
||||||
|
|
||||||
|
- [x] 3. Verify nftables Rules and Connectivity on Live Server
|
||||||
|
|
||||||
|
**What to do**:
|
||||||
|
1. SSH to server, run `nft list table ip nexusguard` and verify:
|
||||||
|
- INPUT chain has `meta l4proto icmp accept comment "input_icmp_all"`
|
||||||
|
- FORWARD chain has `fwd_wg_docker` rules for 172.24.0.0/16 and 172.17.0.0/16
|
||||||
|
- All existing rules intact (server_wg1, input_estab, input_wg_api, etc.)
|
||||||
|
2. Test from server: `ping -c 3 10.172.21.3` — should get replies
|
||||||
|
3. Ask user to test from client: `ping 10.172.21.1` and `curl -v http://10.172.21.1:80`
|
||||||
|
4. Verify nft counters increment when traffic flows
|
||||||
|
|
||||||
|
**Must NOT do**:
|
||||||
|
- Do NOT modify any nft rules during verification
|
||||||
|
- Do NOT flush or recreate chains
|
||||||
|
|
||||||
|
**Recommended Agent Profile**:
|
||||||
|
- **Category**: `quick`
|
||||||
|
- Reason: SSH verification commands only
|
||||||
|
- **Skills**: []
|
||||||
|
|
||||||
|
**Parallelization**:
|
||||||
|
- **Can Run In Parallel**: NO
|
||||||
|
- **Parallel Group**: Wave 2 (after Task 2)
|
||||||
|
- **Blocks**: F1-F4
|
||||||
|
- **Blocked By**: Task 2 (deployment)
|
||||||
|
|
||||||
|
**References**:
|
||||||
|
- `D:\www-project\NexusGuard\connect_remote.txt` — SSH credentials
|
||||||
|
- `D:\www-project\NexusGuard\AGENTS.md` — WireGuard AllowedIPs architecture rules
|
||||||
|
|
||||||
|
**Acceptance Criteria**:
|
||||||
|
- [ ] INPUT chain has `meta l4proto icmp` (not `icmp type echo-request`)
|
||||||
|
- [ ] FORWARD chain has `fwd_wg_docker` for 172.24.0.0/16
|
||||||
|
- [ ] FORWARD chain has `fwd_wg_docker0` for 172.17.0.0/16
|
||||||
|
- [ ] Server can ping gogo3 (10.172.21.3)
|
||||||
|
- [ ] Client can ping server (10.172.21.1)
|
||||||
|
- [ ] Client can curl http://10.172.21.1:80
|
||||||
|
|
||||||
|
**QA Scenarios**:
|
||||||
|
|
||||||
|
```
|
||||||
|
Scenario: Verify INPUT chain ICMP rule
|
||||||
|
Tool: SSH (bash)
|
||||||
|
Steps:
|
||||||
|
1. ssh root@172.20.8.191 'nft list chain ip nexusguard input | grep icmp'
|
||||||
|
Expected Result: Shows `meta l4proto icmp accept comment "input_icmp_all"`
|
||||||
|
Evidence: .sisyphus/evidence/task-3-input-icmp.txt
|
||||||
|
|
||||||
|
Scenario: Verify FORWARD chain Docker rules
|
||||||
|
Tool: SSH (bash)
|
||||||
|
Steps:
|
||||||
|
1. ssh root@172.20.8.191 'nft list chain ip nexusguard forward | grep docker'
|
||||||
|
Expected Result: Shows both fwd_wg_docker (172.24.0.0/16) and fwd_wg_docker0 (172.17.0.0/16)
|
||||||
|
Evidence: .sisyphus/evidence/task-3-forward-docker.txt
|
||||||
|
|
||||||
|
Scenario: Server ping client
|
||||||
|
Tool: SSH (bash)
|
||||||
|
Steps:
|
||||||
|
1. ssh root@172.20.8.191 'ping -c 3 10.172.21.3'
|
||||||
|
Expected Result: 3 replies, 0% packet loss
|
||||||
|
Evidence: .sisyphus/evidence/task-3-ping-client.txt
|
||||||
|
|
||||||
|
Scenario: Client connectivity (requires user)
|
||||||
|
Tool: User prompt
|
||||||
|
Steps:
|
||||||
|
1. Ask user to run from gogo3 client: `ping 10.172.21.1`
|
||||||
|
2. Ask user to run from gogo3 client: `curl -v http://10.172.21.1:80`
|
||||||
|
Expected Result: Ping replies, curl returns 200
|
||||||
|
Evidence: User provides output
|
||||||
|
```
|
||||||
|
|
||||||
|
**Commit**: NO
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Final Verification Wave (MANDATORY — after ALL implementation tasks)
|
||||||
|
|
||||||
|
> 4 review agents run in PARALLEL. ALL must APPROVE. Rejection → fix → re-run.
|
||||||
|
|
||||||
|
- [x] F1. **Plan Compliance Audit** — `oracle`
|
||||||
|
Read the plan end-to-end. For each "Must Have": verify implementation exists (read file, curl endpoint, check schema). For each "Must NOT Have": search codebase for forbidden patterns — reject with file:line if found. Check evidence files exist in .sisyphus/evidence/. Compare deliverables against plan.
|
||||||
|
Output: `Must Have [N/N] | Must NOT Have [N/N] | Tasks [N/N] | VERDICT: APPROVE/REJECT`
|
||||||
|
|
||||||
|
- [x] F2. **Code Quality Review** — `unspecified-high`
|
||||||
|
Run `go vet ./...` on changed packages. Review all changed files for: empty catches, console.logs in prod code, commented-out code, unused imports. Check AI slop: excessive comments, over-abstraction, generic variable names.
|
||||||
|
Output: `Build [PASS/FAIL] | Files [N clean/N issues] | VERDICT`
|
||||||
|
|
||||||
|
- [x] F3. **Real Manual QA** — `unspecified-high` (equipment: SSH to 172.20.8.191)
|
||||||
|
SSH to server. Run: `nft list table ip nexusguard` and verify rules. Then test: `ping 10.172.21.3` from server. From client: `ping 10.172.21.1` and `curl -v http://10.172.21.1:80`. Test negative case: verify that WG isolation default drop still blocks unauthorized traffic.
|
||||||
|
Output: `Connectivity [N/N pass] | Firewall [N correct rules] | Negative [PASS/FAIL] | VERDICT`
|
||||||
|
|
||||||
|
- [x] F4. **Scope Fidelity Check** — `deep`
|
||||||
|
For each task: read "What to do", read actual diff (git log/diff). Verify 1:1 — everything in spec was built (no missing), nothing beyond spec was built (no creep). Check "Must NOT do" compliance. Flag unauthorized changes.
|
||||||
|
Output: `Tasks [N/N compliant] | Contamination [CLEAN/N issues] | VERDICT`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Commit Strategy
|
||||||
|
|
||||||
|
- **Task 1**: `fix(nftables): InitNetwork ICMP, Docker bridge, INPUT base rules` → `apps/server-core/`
|
||||||
|
- **Task 2**: Submodule push + root push + deploy via `update.sh --force`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
### Verification Commands
|
||||||
|
```bash
|
||||||
|
# From server (SSH root@172.20.8.191):
|
||||||
|
nft list chain ip nexusguard input
|
||||||
|
# Expected: meta l4proto icmp accept comment "input_icmp_all"
|
||||||
|
|
||||||
|
nft list chain ip nexusguard forward
|
||||||
|
# Expected: fwd_wg_docker accept for 172.24.0.0/16 and 172.17.0.0/16
|
||||||
|
|
||||||
|
# From client (gogo3):
|
||||||
|
ping 10.172.21.1
|
||||||
|
# Expected: replies
|
||||||
|
|
||||||
|
# From server:
|
||||||
|
ping 10.172.21.3
|
||||||
|
# Expected: replies
|
||||||
|
|
||||||
|
# From client:
|
||||||
|
curl -s -o /dev/null -w "%{http_code}" http://10.172.21.1:80
|
||||||
|
# Expected: 200
|
||||||
|
```
|
||||||
|
|
||||||
|
### Final Checklist
|
||||||
|
- [x] All "Must Have" present
|
||||||
|
- [x] All "Must NOT Have" absent
|
||||||
|
- [x] Server deployed and running
|
||||||
|
- [ ] Both peers can ping server
|
||||||
|
- [x] Server can ping both peers
|
||||||
|
- [ ] Port 80 accessible from WireGuard client
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
# Multi-Interface Refactor
|
||||||
|
## TL;DR
|
||||||
|
|
||||||
|
> **Objective**: Refactor NexusGuard from single WireGuard interface to multi-interface per WgServer.
|
||||||
|
## Context
|
||||||
|
|
||||||
|
**Original Request**: User wants firewall bug fixed + multi-node isolation like wgdashboard where each node has configurable wg_isolation and NAT interface.
|
||||||
|
**Interview Summary**:
|
||||||
|
- Default deny all for client<->client, allow server->client default
|
||||||
|
- Isolation configurable per node via UI checkbox
|
||||||
|
- NAT interface (eth0/eth1/ens5) configurable per node
|
||||||
|
- Current architecture only supports 1 local interface (wg0)
|
||||||
|
|
||||||
|
**Research Findings**:
|
||||||
|
- WgManager hardcoded to wg0 (wgmanager_linux.go:25)
|
||||||
|
- Firewall InitNetwork() runs once globally for single subnet
|
||||||
|
- NAT uses auto-detected default route interface
|
||||||
|
- WgServer model lacks InterfaceName, IsLocal, PeerIsolation, NatInterface fields
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Work Objectives
|
||||||
|
|
||||||
|
**Core Objective**: Enable multiple local WireGuard interfaces, each with independent subnet, firewall isolation, and NAT egress interface.
|
||||||
|
|
||||||
|
**Concrete Deliverables**:
|
||||||
|
1. Database migration adding 4 fields to wg_servers table
|
||||||
|
2. WgManager supporting multiple interfaces by name
|
||||||
|
3. Firewall manager with per-interface chains (forward_wgX, input_wgX)
|
||||||
|
4. Startup initialization loop for all IsLocal=true servers
|
||||||
|
5. API handlers using server context for all operations
|
||||||
|
6. Cleanup of hardcoded Local Primary Node references
|
||||||
|
|
||||||
|
**Definition of Done**:
|
||||||
|
- [ ] Migration runs: ALTER TABLE wg_servers ADD COLUMN ...
|
||||||
|
- [ ] wg0, wg1, wg2 interfaces can run simultaneously
|
||||||
|
- [ ] Each interface has independent peer isolation (configurable)
|
||||||
|
- [ ] Each interface uses configured NAT interface for masquerade
|
||||||
|
- [ ] Firewall rules scoped to correct interface chain
|
||||||
|
- [ ] Peer sync works per server (WgServerID filter)
|
||||||
|
- [ ] All existing tests pass
|
||||||
|
- [ ] Manual QA: 2+ local nodes with different subnets/NAT interfaces
|
||||||
|
|
||||||
|
**Must Have**:
|
||||||
|
- Backward compatible: existing single-node deployments work unchanged
|
||||||
|
- Default values: InterfaceName=wg0, IsLocal=false, PeerIsolation=true, NatInterface= (auto)
|
||||||
|
|
||||||
|
**Must NOT Have** (Guardrails):
|
||||||
|
- NO breaking changes to external node provisioning
|
||||||
|
- NO nft flush table - only atomic add/remove
|
||||||
|
- NO hardcoded interface names in firewall code
|
||||||
|
- NO cross-interface peer leakage
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification Strategy
|
||||||
|
|
||||||
|
**Test Decision**:
|
||||||
|
- Infrastructure exists: YES (Go test with -tags dev, GORM AutoMigrate)
|
||||||
|
- Automated tests: Tests-after (add tests for new multi-interface logic)
|
||||||
|
- Framework: Go testing (standard library)
|
||||||
|
|
||||||
|
**QA Policy**: Every task includes agent-executed QA scenarios.
|
||||||
|
|
||||||
|
| Domain | Tool | Evidence Pattern |
|
||||||
|
|--------|------|------------------|
|
||||||
|
| Go unit/integration | go test -tags dev ./... | .sisyphus/evidence/task-{N}-test.log |
|
||||||
|
| nftables rules | bash (nft list) | .sisyphus/evidence/task-{N}-nftables.txt |
|
||||||
|
| WireGuard interfaces | bash (ip link, wg show) | .sisyphus/evidence/task-{N}-wg.txt |
|
||||||
|
| API endpoints | bash (curl) | .sisyphus/evidence/task-{N}-api.json |
|
||||||
|
Wave 2 (Core Logic - 4 parallel):
|
||||||
|
├── T5: LinuxWgManager multi-interface implementation [deep]
|
||||||
|
├── T6: LinuxManager InitNetworkForServer + Teardown [deep]
|
||||||
|
├── T7: NAT per-interface masquerade rules [unspecified-high]
|
||||||
|
├── T8: Peer sync per-server (WgServerID filter) [unspecified-high]
|
||||||
|
Wave 3 (Startup & Recovery - 3 parallel):
|
||||||
|
├── T9: Main.go startup loop for all local servers [deep]
|
||||||
|
├── T10: Firewall rules re-apply per server [unspecified-high]
|
||||||
|
├── T11: Input rule (WG port) per server [quick]
|
||||||
|
Wave 4 (API Handlers - 5 parallel):
|
||||||
|
├── T12: servers.go Create/Update with multi-interface [quick]
|
||||||
|
├── T13: peers.go device creation with server context [quick]
|
||||||
|
├── T14: peer_sync.go SyncLocalPeers per server [quick]
|
||||||
|
├── T15: rules.go syncRuleToFirewall per server [quick]
|
||||||
|
├── T16: provisioning.go server-aware [quick]
|
||||||
|
Wave 5 (Cleanup & Migration - 2 parallel):
|
||||||
|
├── T17: Remove hardcoded Local Primary Node refs [quick]
|
||||||
|
├── T18: Migration script + backfill defaults [quick]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TODOs
|
||||||
|
|
||||||
|
- [x] 1. Database Migration + Model Updates [quick]
|
||||||
|
- [x] 2. WgManager Interface + Multi-Interface Struct [deep]
|
||||||
|
- [x] 3. NetManager Interface + Per-Server Methods [deep]
|
||||||
|
- [x] 4. nftables Chain-Per-Interface Scaffolding [quick]
|
||||||
|
- [x] 5. LinuxWgManager Multi-Interface Implementation [deep]
|
||||||
|
- [x] 6. LinuxManager InitNetworkForServer + Teardown [deep]
|
||||||
|
- [x] 7. NAT Per-Interface Masquerade Rules [unspecified-high]
|
||||||
|
- [x] 8. Peer Sync Per-Server (WgServerID Filter) [unspecified-high]
|
||||||
|
- [x] 9. Main.go Startup Loop for All Local Servers [deep]
|
||||||
|
- [x] 10. Firewall Rules Re-apply Per Server [unspecified-high]
|
||||||
|
- [x] 11. Input Rule (WG Port) Per Server [quick]
|
||||||
|
- [x] 12. servers.go Create/Update Multi-Interface [quick]
|
||||||
|
- [x] 13. peers.go Device Creation with Server Context [quick]
|
||||||
|
- [x] 14. peer_sync.go SyncLocalPeers Per Server [quick]
|
||||||
|
- [x] 15. rules.go syncRuleToFirewall Per Server [quick]
|
||||||
|
- [x] 16. provisioning.go Server-Aware [quick]
|
||||||
|
- [x] 17. Remove Hardcoded Local Primary Node References [quick]
|
||||||
|
- [x] 18. Migration Script + Backfill Defaults [quick]
|
||||||
|
- [x] 19. Unit Tests for Multi-Interface Logic [unspecified-low]
|
||||||
|
- [x] 20. Integration Test: 2 Local Nodes Different Subnets [unspecified-high]
|
||||||
|
- [x] 21. Manual QA Checklist Execution [unspecified-high]
|
||||||
|
- [x] F1. Plan Compliance Audit — oracle
|
||||||
|
- [x] F2. Code Quality Review — unspecified-high
|
||||||
|
- [x] F3. Real Manual QA — unspecified-high + playwright
|
||||||
|
- [x] F4. Scope Fidelity Check — deep
|
||||||
@@ -94,7 +94,7 @@ Wave 2 (Integration + Polish):
|
|||||||
|
|
||||||
## TODOs
|
## TODOs
|
||||||
|
|
||||||
- [ ] 1. Add limit parameter to traffic API
|
- [x] 1. Add limit parameter to traffic API
|
||||||
|
|
||||||
**What to do**:
|
**What to do**:
|
||||||
- In `apps/server-core/api/traffic.go`, modify `parseTimeRange` to also parse `limit` query parameter
|
- In `apps/server-core/api/traffic.go`, modify `parseTimeRange` to also parse `limit` query parameter
|
||||||
@@ -135,7 +135,7 @@ Wave 2 (Integration + Polish):
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
- [ ] 2. Silent auto-refresh + pagination fix
|
- [x] 2. Silent auto-refresh + pagination fix
|
||||||
|
|
||||||
**What to do**:
|
**What to do**:
|
||||||
- Modify `fetchTrafficData` to accept optional `silent` parameter (default false)
|
- Modify `fetchTrafficData` to accept optional `silent` parameter (default false)
|
||||||
@@ -179,7 +179,7 @@ Wave 2 (Integration + Polish):
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
- [ ] 3. Chart downsampling
|
- [x] 3. Chart downsampling
|
||||||
|
|
||||||
**What to do**:
|
**What to do**:
|
||||||
- In `TrafficHistory.vue`, add a `chartDataLimited` computed that limits chart data to max 200 points
|
- In `TrafficHistory.vue`, add a `chartDataLimited` computed that limits chart data to max 200 points
|
||||||
@@ -215,7 +215,7 @@ Wave 2 (Integration + Polish):
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
- [ ] 4. CSV export optimization
|
- [x] 4. CSV export optimization
|
||||||
|
|
||||||
**What to do**:
|
**What to do**:
|
||||||
- Change exportToCSV to export only `paginatedData` (current page) by default
|
- Change exportToCSV to export only `paginatedData` (current page) by default
|
||||||
@@ -244,7 +244,7 @@ Wave 2 (Integration + Polish):
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
- [ ] 5. Build verify all changes
|
- [x] 5. Build verify all changes
|
||||||
|
|
||||||
**What to do**:
|
**What to do**:
|
||||||
- Run `cd apps/server-core && go build ./...`
|
- Run `cd apps/server-core && go build ./...`
|
||||||
@@ -13,7 +13,7 @@ NexusGuard SD-WAN Suite — Enterprise Zero-Trust SD-WAN with WireGuard tunnelin
|
|||||||
├── apps/
|
├── apps/
|
||||||
│ ├── server-core/ # Go/Gin API backend (submodule)
|
│ ├── server-core/ # Go/Gin API backend (submodule)
|
||||||
│ ├── dashboard-ui/ # Vue 3 + Vite frontend (submodule)
|
│ ├── dashboard-ui/ # Vue 3 + Vite frontend (submodule)
|
||||||
│ └── device-agent/ # Go stealth daemon (submodule)
|
│ └── device-agent/ # Go stealth daemon + system tray (submodule)
|
||||||
├── docker-compose.yml # Production orchestration
|
├── docker-compose.yml # Production orchestration
|
||||||
├── docker-compose.dev.yml # Dev (air hot-reload)
|
├── docker-compose.dev.yml # Dev (air hot-reload)
|
||||||
├── Makefile # up/down/dev/migrate/reset-db
|
├── Makefile # up/down/dev/migrate/reset-db
|
||||||
@@ -50,7 +50,10 @@ NexusGuard SD-WAN Suite — Enterprise Zero-Trust SD-WAN with WireGuard tunnelin
|
|||||||
| Symbol | Type | Location | Role |
|
| Symbol | Type | Location | Role |
|
||||||
|--------|------|----------|------|
|
|--------|------|----------|------|
|
||||||
| `main()` (server-core) | func | `apps/server-core/main.go` | Entry: CLI flags + Gin init |
|
| `main()` (server-core) | func | `apps/server-core/main.go` | Entry: CLI flags + Gin init |
|
||||||
| `main()` (device-agent) | func | `apps/device-agent/main.go` | Entry: agent daemon lifecycle |
|
| `main()` (device-agent) | func | `apps/device-agent/main.go` | Entry: systray + agent daemon lifecycle |
|
||||||
|
| `onReady()` / `onExit()` | func | `apps/device-agent/main.go` | System tray setup and cleanup |
|
||||||
|
| `startAgent()` / `stopAgent()` | func | `apps/device-agent/main.go` | Agent connect/disconnect lifecycle |
|
||||||
|
| `generateIcon()` | func | `apps/device-agent/icon.go` | 16x16 shield icon for tray |
|
||||||
| `config.Load()` | func | `apps/server-core/internal/config/` | Env-based config loader |
|
| `config.Load()` | func | `apps/server-core/internal/config/` | Env-based config loader |
|
||||||
| `config.LoadConfFile()` | func | `apps/server-core/internal/config/config_loader.go` | Config file parser (.env / nexusguard.conf) |
|
| `config.LoadConfFile()` | func | `apps/server-core/internal/config/config_loader.go` | Config file parser (.env / nexusguard.conf) |
|
||||||
| `auth.Init()` | func | `apps/server-core/internal/auth/` | JWT sign/verify init |
|
| `auth.Init()` | func | `apps/server-core/internal/auth/` | JWT sign/verify init |
|
||||||
@@ -76,6 +79,7 @@ NexusGuard SD-WAN Suite — Enterprise Zero-Trust SD-WAN with WireGuard tunnelin
|
|||||||
|
|
||||||
## ANTI-PATTERNS (THIS PROJECT)
|
## ANTI-PATTERNS (THIS PROJECT)
|
||||||
- **NEVER** `nft flush table` — only atomic add/remove
|
- **NEVER** `nft flush table` — only atomic add/remove
|
||||||
|
- **NEVER** commit temp/debug/test files (`nft-fix.sh`, `temp_*.txt` etc) in project root use ./tests folder and dont commit
|
||||||
- **NEVER** log plaintext or encryption keys
|
- **NEVER** log plaintext or encryption keys
|
||||||
- **NEVER** reopen completed phases/commits — fix forward only
|
- **NEVER** reopen completed phases/commits — fix forward only
|
||||||
- **NEVER** rebuild `shared/crypto/encryptor.go` — copy identical file
|
- **NEVER** rebuild `shared/crypto/encryptor.go` — copy identical file
|
||||||
|
|||||||
@@ -221,6 +221,41 @@ For automated client deployment with the Device Agent:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 📚 Documentation
|
||||||
|
|
||||||
|
Documentation is built with VitePress and served at `/docs/`.
|
||||||
|
|
||||||
|
### Local Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd apps/docs
|
||||||
|
npm install
|
||||||
|
npm run docs:dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building Docs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd apps/docs
|
||||||
|
npm run docs:build
|
||||||
|
```
|
||||||
|
|
||||||
|
The output is in `apps/docs/.vitepress/dist/`.
|
||||||
|
|
||||||
|
### Structure
|
||||||
|
|
||||||
|
- `apps/docs/` — VitePress root (i18n: Indonesian + English)
|
||||||
|
- `apps/server-core/docs/` — Backend API docs & guides
|
||||||
|
- `apps/dashboard-ui/docs/` — Dashboard UI docs
|
||||||
|
- `apps/device-agent/docs/` — Device Agent docs
|
||||||
|
|
||||||
|
### Languages
|
||||||
|
|
||||||
|
- **Bahasa Indonesia** (default): `/docs/`
|
||||||
|
- **English**: `/docs/en/`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 📁 File Structure
|
## 📁 File Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
+1
-1
Submodule apps/dashboard-ui updated: 458f8c5917...dc20427f97
+1
-1
Submodule apps/device-agent updated: 314d8fd7bb...3553982562
@@ -1,22 +1,50 @@
|
|||||||
import { defineConfig } from 'vitepress'
|
import { defineConfig } from 'vitepress'
|
||||||
|
|
||||||
|
// Sidebar manifests from submodules
|
||||||
|
import serverCoreSidebar from '../../server-core/docs/sidebar.json'
|
||||||
|
import dashboardSidebar from '../../dashboard-ui/docs/sidebar.json'
|
||||||
|
import agentSidebar from '../../device-agent/docs/sidebar.json'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
title: 'NexusGuard Docs',
|
title: 'NexusGuard',
|
||||||
description: 'Enterprise Zero-Trust SD-WAN Documentation',
|
description: 'Enterprise Zero-Trust SD-WAN Suite',
|
||||||
|
base: '/docs/',
|
||||||
cleanUrls: true,
|
cleanUrls: true,
|
||||||
|
|
||||||
|
locales: {
|
||||||
|
root: {
|
||||||
|
label: 'Bahasa Indonesia',
|
||||||
|
lang: 'id',
|
||||||
themeConfig: {
|
themeConfig: {
|
||||||
sidebar: [
|
sidebar: [
|
||||||
{
|
serverCoreSidebar,
|
||||||
text: 'Guides',
|
dashboardSidebar,
|
||||||
items: [
|
agentSidebar,
|
||||||
{ text: 'Sign In', link: '/guides/sign-in' },
|
],
|
||||||
{ text: 'Access Remote Server', link: '/guides/access-remote-server' },
|
nav: [
|
||||||
{ text: 'Add WireGuard Configuration', link: '/guides/add-wireguard-configuration' },
|
{ text: 'Beranda', link: '/' },
|
||||||
{ text: 'Peers', link: '/guides/peers' },
|
{ text: 'Panduan', link: '/guides/' },
|
||||||
{ text: 'Email Service', link: '/guides/email-service' },
|
{ text: 'API', link: '/api/' },
|
||||||
{ text: 'WebHooks', link: '/guides/webhooks' },
|
{ text: 'GitHub', link: 'https://git.datadunia.com/nexusguard/Nexus-Guard-Suite' },
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
},
|
||||||
}
|
en: {
|
||||||
|
label: 'English',
|
||||||
|
lang: 'en',
|
||||||
|
themeConfig: {
|
||||||
|
sidebar: [
|
||||||
|
serverCoreSidebar,
|
||||||
|
dashboardSidebar,
|
||||||
|
agentSidebar,
|
||||||
|
],
|
||||||
|
nav: [
|
||||||
|
{ text: 'Home', link: '/en/' },
|
||||||
|
{ text: 'Guides', link: '/en/guides/' },
|
||||||
|
{ text: 'API', link: '/en/api/' },
|
||||||
|
{ text: 'GitHub', link: 'https://git.datadunia.com/nexusguard/Nexus-Guard-Suite' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# NexusGuard API Reference
|
||||||
|
|
||||||
|
This page provides interactive documentation for the NexusGuard Server Core API.
|
||||||
|
|
||||||
|
<div id="swagger-ui"></div>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted } from 'vue'
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// Load Swagger UI from CDN
|
||||||
|
const script = document.createElement('script')
|
||||||
|
script.src = 'https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js'
|
||||||
|
script.onload = () => {
|
||||||
|
window.SwaggerUIBundle({
|
||||||
|
url: '/server-core/docs/swagger.json',
|
||||||
|
dom_id: '#swagger-ui',
|
||||||
|
presets: [
|
||||||
|
window.SwaggerUIBundle.presets.apis,
|
||||||
|
window.SwaggerUIBundle.SwaggerUIStandalonePreset
|
||||||
|
],
|
||||||
|
layout: 'BaseLayout'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
document.head.appendChild(script)
|
||||||
|
|
||||||
|
const link = document.createElement('link')
|
||||||
|
link.rel = 'stylesheet'
|
||||||
|
link.href = 'https://unpkg.com/swagger-ui-dist@5/swagger-ui.css'
|
||||||
|
document.head.appendChild(link)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# Referensi API NexusGuard
|
||||||
|
|
||||||
|
Halaman ini menyediakan dokumentasi interaktif untuk API Server Core NexusGuard.
|
||||||
|
|
||||||
|
<div id="swagger-ui"></div>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted } from 'vue'
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const script = document.createElement('script')
|
||||||
|
script.src = 'https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js'
|
||||||
|
script.onload = () => {
|
||||||
|
window.SwaggerUIBundle({
|
||||||
|
url: '/server-core/docs/swagger.json',
|
||||||
|
dom_id: '#swagger-ui',
|
||||||
|
presets: [
|
||||||
|
window.SwaggerUIBundle.presets.apis,
|
||||||
|
window.SwaggerUIBundle.SwaggerUIStandalonePreset
|
||||||
|
],
|
||||||
|
layout: 'BaseLayout'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
document.head.appendChild(script)
|
||||||
|
|
||||||
|
const link = document.createElement('link')
|
||||||
|
link.rel = 'stylesheet'
|
||||||
|
link.href = 'https://unpkg.com/swagger-ui-dist@5/swagger-ui.css'
|
||||||
|
document.head.appendChild(link)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { readFileSync } from 'node:fs';
|
||||||
|
import { join, dirname } from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
const submodules = [
|
||||||
|
{ name: 'server-core', path: '../server-core/docs/sidebar.json' },
|
||||||
|
{ name: 'dashboard-ui', path: '../dashboard-ui/docs/sidebar.json' },
|
||||||
|
{ name: 'device-agent', path: '../device-agent/docs/sidebar.json' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const sidebar = [];
|
||||||
|
|
||||||
|
for (const mod of submodules) {
|
||||||
|
const filePath = join(__dirname, mod.path);
|
||||||
|
try {
|
||||||
|
const content = JSON.parse(readFileSync(filePath, 'utf-8'));
|
||||||
|
sidebar.push(content);
|
||||||
|
console.error(`\u2713 Loaded ${mod.name}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`\u26A0 Skipping ${mod.name}: ${e.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(JSON.stringify(sidebar, null, 2));
|
||||||
Generated
+2552
File diff suppressed because it is too large
Load Diff
+1
-1
Submodule apps/server-core updated: e861996717...19e804ca45
@@ -61,6 +61,8 @@ services:
|
|||||||
VITE_API_BASE_URL: ${VITE_API_BASE_URL}
|
VITE_API_BASE_URL: ${VITE_API_BASE_URL}
|
||||||
ports:
|
ports:
|
||||||
- "${WEB_PORT:-80}:80"
|
- "${WEB_PORT:-80}:80"
|
||||||
|
volumes:
|
||||||
|
- ./apps/docs/.vitepress/dist:/usr/share/nginx/html/docs:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
- server-core
|
- server-core
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|||||||
@@ -47,6 +47,15 @@ echo "[+] Syncing and updating submodules..."
|
|||||||
SUBMODULE_FAILED=false
|
SUBMODULE_FAILED=false
|
||||||
git submodule update --init --recursive --remote || { SUBMODULE_FAILED=true; echo "[!] Git submodule update skipped or failed."; }
|
git submodule update --init --recursive --remote || { SUBMODULE_FAILED=true; echo "[!] Git submodule update skipped or failed."; }
|
||||||
|
|
||||||
|
# 2b. Build VitePress docs (non-blocking)
|
||||||
|
echo "[+] Building VitePress documentation..."
|
||||||
|
DOCS_BUILD_FAILED=false
|
||||||
|
if [ -d "apps/docs" ]; then
|
||||||
|
(cd apps/docs && npm install && npm run docs:build) || { DOCS_BUILD_FAILED=true; echo "[!] Docs build failed. Documentation may be stale. Continuing deployment..."; }
|
||||||
|
else
|
||||||
|
echo "[!] apps/docs directory not found. Skipping docs build."
|
||||||
|
fi
|
||||||
|
|
||||||
# 3. Hitung state hash (git + .env) untuk deteksi perubahan
|
# 3. Hitung state hash (git + .env) untuk deteksi perubahan
|
||||||
CURRENT_HASH=$(echo "$(git rev-parse HEAD 2>/dev/null)$(git submodule status 2>/dev/null)$(sha256sum .env 2>/dev/null)" | sha256sum | cut -d" " -f1)
|
CURRENT_HASH=$(echo "$(git rev-parse HEAD 2>/dev/null)$(git submodule status 2>/dev/null)$(sha256sum .env 2>/dev/null)" | sha256sum | cut -d" " -f1)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user