mirror of
https://github.com/netbirdio/dashboard.git
synced 2026-09-23 00:30:43 -07:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0f4a3564a |
No files matched your search
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"extends": ["next/core-web-vitals","prettier"],
|
||||||
|
"plugins": ["simple-import-sort"],
|
||||||
|
"rules": {
|
||||||
|
"simple-import-sort/imports": [
|
||||||
|
"warn",
|
||||||
|
{
|
||||||
|
"groups": [["^\\u0000", "^@?\\w", "^[^.]", "^\\."]]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"simple-import-sort/exports": "warn"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -98,33 +98,13 @@ jobs:
|
|||||||
type=ref,event=pr
|
type=ref,event=pr
|
||||||
type=sha
|
type=sha
|
||||||
|
|
||||||
- name: Docker meta (rootless)
|
|
||||||
id: meta_rootless
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: |
|
|
||||||
${{ env.DOCKERHUB_IMAGE }}
|
|
||||||
${{ env.GHCR_IMAGE }}
|
|
||||||
flavor: |
|
|
||||||
latest=false
|
|
||||||
suffix=-rootless,onlatest=true
|
|
||||||
tags: |
|
|
||||||
type=schedule
|
|
||||||
type=ref,event=branch
|
|
||||||
type=ref,event=tag
|
|
||||||
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/') }}
|
|
||||||
type=ref,event=pr
|
|
||||||
type=sha
|
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
- name: Log in to Docker Hub
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.NB_DOCKER_USER }}
|
username: ${{ secrets.NB_DOCKER_USER }}
|
||||||
password: ${{ secrets.NB_DOCKER_TOKEN }}
|
password: ${{ secrets.NB_DOCKER_TOKEN }}
|
||||||
|
|
||||||
- name: Log in to the GitHub Container registry
|
- name: Log in to the GitHub Container registry
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
@@ -136,23 +116,11 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/Dockerfile
|
file: docker/Dockerfile
|
||||||
push: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
|
push: true
|
||||||
platforms: linux/amd64,linux/arm64,linux/arm
|
platforms: linux/amd64,linux/arm64,linux/arm
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
|
||||||
- name: Build and push rootless Docker image
|
- run: |
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: docker/Dockerfile.rootless
|
|
||||||
push: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
|
|
||||||
platforms: linux/amd64,linux/arm64,linux/arm
|
|
||||||
tags: ${{ steps.meta_rootless.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta_rootless.outputs.labels }}
|
|
||||||
|
|
||||||
- if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
|
||||||
run: |
|
|
||||||
echo '### Pushed tags' >> $GITHUB_STEP_SUMMARY
|
echo '### Pushed tags' >> $GITHUB_STEP_SUMMARY
|
||||||
echo '${{ steps.meta.outputs.tags }}' >> $GITHUB_STEP_SUMMARY
|
echo '${{ steps.meta.outputs.tags }}' >> $GITHUB_STEP_SUMMARY
|
||||||
echo '${{ steps.meta_rootless.outputs.tags }}' >> $GITHUB_STEP_SUMMARY
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
name: Bump netbird wasm client
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
tag:
|
|
||||||
description: 'NetBird release tag (e.g. v0.78.0)'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ inputs.tag }}
|
|
||||||
cancel-in-progress: false
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
bump:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: main
|
|
||||||
token: ${{ secrets.NETBIRD_DEV_BOT_GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Configure git
|
|
||||||
run: |
|
|
||||||
git config --global user.email "dev@netbird.io"
|
|
||||||
git config --global user.name "netbirddev"
|
|
||||||
|
|
||||||
# The tag rides in env and is validated before use, so a crafted dispatch
|
|
||||||
# input cannot expand into shell source or reach the sed expression.
|
|
||||||
- name: Update the default wasm path
|
|
||||||
id: bump
|
|
||||||
env:
|
|
||||||
TAG: ${{ inputs.tag }}
|
|
||||||
run: |
|
|
||||||
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
||||||
echo "Refusing tag '$TAG': expected vMAJOR.MINOR.PATCH"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
sed -i "s|https://pkgs.netbird.io/wasm/client/v[0-9.]*|https://pkgs.netbird.io/wasm/client/${TAG}|" src/utils/config.ts
|
|
||||||
|
|
||||||
branch="bump-netbird-wasm-${TAG#v}"
|
|
||||||
echo "branch=${branch}" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
# The branch name is derived from the tag, so a re-dispatch of the
|
|
||||||
# same release would collide with the branch and pull request an
|
|
||||||
# earlier run left behind.
|
|
||||||
if git ls-remote --exit-code --heads origin "${branch}" >/dev/null 2>&1; then
|
|
||||||
echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "Branch ${branch} already exists, ${TAG} was handled by an earlier run"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
git checkout -b "${branch}"
|
|
||||||
git add src/utils/config.ts
|
|
||||||
if git diff --cached --quiet; then
|
|
||||||
echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "Default wasm path already at ${TAG}, nothing to do"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
echo "skip=false" >> "$GITHUB_OUTPUT"
|
|
||||||
git commit -m "Bump the WASM client to ${TAG}"
|
|
||||||
git push --set-upstream origin "${branch}"
|
|
||||||
|
|
||||||
- name: Create pull request
|
|
||||||
if: steps.bump.outputs.skip != 'true'
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.NETBIRD_DEV_BOT_GITHUB_TOKEN }}
|
|
||||||
TAG: ${{ inputs.tag }}
|
|
||||||
BRANCH: ${{ steps.bump.outputs.branch }}
|
|
||||||
run: |
|
|
||||||
gh pr create \
|
|
||||||
--base main \
|
|
||||||
--head "$BRANCH" \
|
|
||||||
--title "Bump the WASM client to ${TAG}" \
|
|
||||||
--body "Automated wasm path bump triggered by netbird release ${TAG}."
|
|
||||||
@@ -101,61 +101,17 @@ jobs:
|
|||||||
echo "Using reverse-proxy tag: $TAG"
|
echo "Using reverse-proxy tag: $TAG"
|
||||||
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Restore geolocation database cache
|
- name: Setup test environment
|
||||||
id: geo-cache
|
|
||||||
uses: actions/cache/restore@v4
|
|
||||||
with:
|
|
||||||
path: e2e/environment/geo-cache
|
|
||||||
key: geolite-dbs-v1
|
|
||||||
|
|
||||||
- name: Build dashboard and set up test environment
|
|
||||||
env:
|
env:
|
||||||
MANAGEMENT_IMAGE_TAG: ${{ steps.management_tag.outputs.tag }}
|
MANAGEMENT_IMAGE_TAG: ${{ steps.management_tag.outputs.tag }}
|
||||||
REVERSE_PROXY_IMAGE_TAG: ${{ steps.reverse_proxy_tag.outputs.tag }}
|
REVERSE_PROXY_IMAGE_TAG: ${{ steps.reverse_proxy_tag.outputs.tag }}
|
||||||
# The docker environment (image pulls, Zitadel bootstrap) is
|
run: cd ./e2e/environment && bash create-test-env.sh
|
||||||
# network-bound and the Next build is CPU-bound, so they overlap.
|
|
||||||
# The build reads .test-config.json via the @/config/test alias,
|
|
||||||
# and create-test-env.sh renders that file only after the Zitadel
|
|
||||||
# bootstrap — so the build waits for it before starting.
|
|
||||||
run: |
|
|
||||||
(cd ./e2e/environment && bash create-test-env.sh) > env-setup.log 2>&1 &
|
|
||||||
ENV_PID=$!
|
|
||||||
until [ -s .test-config.json ] && jq empty .test-config.json 2>/dev/null; do
|
|
||||||
if ! kill -0 "$ENV_PID" 2>/dev/null; then break; fi
|
|
||||||
sleep 2
|
|
||||||
done
|
|
||||||
if ! [ -s .test-config.json ]; then
|
|
||||||
echo "::error::create-test-env.sh exited before rendering .test-config.json"
|
|
||||||
cat env-setup.log
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
# Lowest CPU priority: the containers must win the scheduler, or
|
|
||||||
# the build can starve management past the proxy-registration wait.
|
|
||||||
if ! nice -n 19 env APP_ENV=test npx next build; then
|
|
||||||
kill "$ENV_PID" 2>/dev/null || true
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if ! wait "$ENV_PID"; then
|
|
||||||
echo "::error::Test environment setup failed"
|
|
||||||
cat env-setup.log
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
cat env-setup.log
|
|
||||||
|
|
||||||
# Saved right after env setup rather than in a post step, so a later
|
|
||||||
# test failure doesn't lose the cache.
|
|
||||||
- name: Save geolocation database cache
|
|
||||||
if: always() && steps.geo-cache.outputs.cache-hit != 'true' && hashFiles('e2e/environment/geo-cache/**') != ''
|
|
||||||
uses: actions/cache/save@v4
|
|
||||||
with:
|
|
||||||
path: e2e/environment/geo-cache
|
|
||||||
key: geolite-dbs-v1
|
|
||||||
|
|
||||||
- name: Run Playwright tests
|
- name: Run Playwright tests
|
||||||
id: playwright
|
id: playwright
|
||||||
run: |
|
run: |
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
npx playwright test --config=e2e/playwright.config.ts 2>&1 | tee playwright-output.log
|
npm run test:ci 2>&1 | tee playwright-output.log
|
||||||
|
|
||||||
- name: Append Playwright summary to job summary
|
- name: Append Playwright summary to job summary
|
||||||
if: always() && hashFiles('e2e/test-results/results.json') != ''
|
if: always() && hashFiles('e2e/test-results/results.json') != ''
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
name: Unit Tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
# Cancel superseded runs on the same ref so a new push doesn't queue behind an
|
|
||||||
# outdated one (mirrors build_and_push.yml).
|
|
||||||
concurrency:
|
|
||||||
group: unit-tests-${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
vitest:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: setup-node
|
|
||||||
uses: actions/setup-node@v5
|
|
||||||
with:
|
|
||||||
node-version: '20'
|
|
||||||
cache: 'npm'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm ci
|
|
||||||
|
|
||||||
- name: Run unit tests
|
|
||||||
run: npm run test:unit
|
|
||||||
@@ -44,7 +44,6 @@ e2e/test-results/
|
|||||||
e2e/playwright-report/
|
e2e/playwright-report/
|
||||||
/test-results/
|
/test-results/
|
||||||
/playwright-report/
|
/playwright-report/
|
||||||
playwright-report*.zip
|
|
||||||
.configs/.local-config.zitadel.json
|
.configs/.local-config.zitadel.json
|
||||||
.configs/.staging-config.json
|
.configs/.staging-config.json
|
||||||
.configs/.temp-config.json
|
.configs/.temp-config.json
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
# ./build.sh # build + export netbird-dashboard.tar.gz
|
# ./build.sh # build + export netbird-dashboard.tar.gz
|
||||||
# IMAGE_TAG=v1 ./build.sh # override the image tag
|
# IMAGE_TAG=v1 ./build.sh # override the image tag
|
||||||
# SKIP_BUILD=1 ./build.sh # reuse an existing out/ (skip npm build)
|
# SKIP_BUILD=1 ./build.sh # reuse an existing out/ (skip npm build)
|
||||||
# ROOTLESS=1 ./build.sh # build the amd64-rootless image variant
|
|
||||||
#
|
#
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -20,26 +19,8 @@ cd "$(dirname "$0")"
|
|||||||
|
|
||||||
IMAGE_NAME="${IMAGE_NAME:-netbird-dashboard}"
|
IMAGE_NAME="${IMAGE_NAME:-netbird-dashboard}"
|
||||||
IMAGE_TAG="${IMAGE_TAG:-amd64}"
|
IMAGE_TAG="${IMAGE_TAG:-amd64}"
|
||||||
DOCKERFILE="docker/Dockerfile"
|
|
||||||
CONTAINER_PORT=80
|
|
||||||
OUTPUT_SUFFIX=""
|
|
||||||
|
|
||||||
case "${ROOTLESS:-0}" in
|
|
||||||
0) ;;
|
|
||||||
1)
|
|
||||||
DOCKERFILE="docker/Dockerfile.rootless"
|
|
||||||
CONTAINER_PORT=8080
|
|
||||||
OUTPUT_SUFFIX="-rootless"
|
|
||||||
[[ "${IMAGE_TAG}" == *-rootless ]] || IMAGE_TAG="${IMAGE_TAG}-rootless"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "ERROR: ROOTLESS must be 0 or 1." >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
IMAGE="${IMAGE_NAME}:${IMAGE_TAG}"
|
IMAGE="${IMAGE_NAME}:${IMAGE_TAG}"
|
||||||
OUTPUT="${OUTPUT:-${IMAGE_NAME}${OUTPUT_SUFFIX}.tar.gz}"
|
OUTPUT="${OUTPUT:-${IMAGE_NAME}.tar.gz}"
|
||||||
|
|
||||||
# Build the static export (out/) unless told to reuse an existing one. Next 16
|
# Build the static export (out/) unless told to reuse an existing one. Next 16
|
||||||
# no longer runs ESLint during `next build`; types are checked by the build via
|
# no longer runs ESLint during `next build`; types are checked by the build via
|
||||||
@@ -58,10 +39,17 @@ if [[ ! -d out ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# The .dockerignore lives under docker/, but Docker reads it from the build
|
||||||
|
# context root. Stage it for the duration of the build so node_modules/.next
|
||||||
|
# don't get shipped into the build context.
|
||||||
|
cleanup() { rm -f .dockerignore; }
|
||||||
|
trap cleanup EXIT
|
||||||
|
cp docker/.dockerignore .dockerignore
|
||||||
|
|
||||||
echo "==> Building ${IMAGE} for linux/amd64"
|
echo "==> Building ${IMAGE} for linux/amd64"
|
||||||
docker build \
|
docker build \
|
||||||
--platform linux/amd64 \
|
--platform linux/amd64 \
|
||||||
-f "${DOCKERFILE}" \
|
-f docker/Dockerfile \
|
||||||
-t "${IMAGE}" \
|
-t "${IMAGE}" \
|
||||||
.
|
.
|
||||||
|
|
||||||
@@ -72,13 +60,13 @@ echo "==> Done: ${OUTPUT} ($(du -h "${OUTPUT}" | cut -f1))"
|
|||||||
echo
|
echo
|
||||||
echo "Copy and run on the server:"
|
echo "Copy and run on the server:"
|
||||||
echo " scp ${OUTPUT} user@your-server:/tmp/"
|
echo " scp ${OUTPUT} user@your-server:/tmp/"
|
||||||
echo " docker load < /tmp/${OUTPUT##*/}"
|
echo " docker load < /tmp/${OUTPUT}"
|
||||||
echo
|
echo
|
||||||
echo "Run (nginx serves on container port ${CONTAINER_PORT}). Set the runtime env vars the"
|
echo "Run (nginx serves on container port 80). Set the runtime env vars the"
|
||||||
echo "dashboard templates at startup — for the Agent Network onboarding test,"
|
echo "dashboard templates at startup — for the Agent Network onboarding test,"
|
||||||
echo "flip NETBIRD_AGENT_NETWORK_ONLY=true:"
|
echo "flip NETBIRD_AGENT_NETWORK_ONLY=true:"
|
||||||
echo " docker run -d --name ${IMAGE_NAME} --restart unless-stopped \\"
|
echo " docker run -d --name ${IMAGE_NAME} --restart unless-stopped \\"
|
||||||
echo " -p 8080:${CONTAINER_PORT} \\"
|
echo " -p 8080:80 \\"
|
||||||
echo " -e NETBIRD_MGMT_API_ENDPOINT=https://your-mgmt:443 \\"
|
echo " -e NETBIRD_MGMT_API_ENDPOINT=https://your-mgmt:443 \\"
|
||||||
echo " -e AUTH_AUTHORITY=https://your-idp/realms/netbird \\"
|
echo " -e AUTH_AUTHORITY=https://your-idp/realms/netbird \\"
|
||||||
echo " -e AUTH_CLIENT_ID=netbird-dashboard \\"
|
echo " -e AUTH_CLIENT_ID=netbird-dashboard \\"
|
||||||
|
|||||||
+1
-2
@@ -24,6 +24,5 @@
|
|||||||
"hubspotSignupFormId": "$NETBIRD_HUBSPOT_SIGNUP_FORM_ID",
|
"hubspotSignupFormId": "$NETBIRD_HUBSPOT_SIGNUP_FORM_ID",
|
||||||
"hubspotOnboardingFormId": "$NETBIRD_HUBSPOT_ONBOARDING_FORM_ID",
|
"hubspotOnboardingFormId": "$NETBIRD_HUBSPOT_ONBOARDING_FORM_ID",
|
||||||
"hubspotSurveyFormId": "$NETBIRD_HUBSPOT_SURVEY_FORM_ID",
|
"hubspotSurveyFormId": "$NETBIRD_HUBSPOT_SURVEY_FORM_ID",
|
||||||
"analyticsExcludedEmails": "$NETBIRD_ANALYTICS_EXCLUDED_EMAILS",
|
"analyticsExcludedEmails": "$NETBIRD_ANALYTICS_EXCLUDED_EMAILS"
|
||||||
"announcement": "$NETBIRD_ANNOUNCEMENT"
|
|
||||||
}
|
}
|
||||||
File renamed without changes.
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
FROM alpine:3.24
|
FROM alpine:3.14
|
||||||
|
|
||||||
RUN apk add --no-cache bash curl less ca-certificates git tzdata zip gettext \
|
RUN apk add --no-cache bash curl less ca-certificates git tzdata zip gettext \
|
||||||
nginx curl supervisor certbot-nginx && \
|
nginx curl supervisor certbot-nginx && \
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
FROM alpine:3.24
|
|
||||||
|
|
||||||
RUN apk add --no-cache bash ca-certificates gettext nginx tzdata && \
|
|
||||||
rm -rf /var/cache/apk/* && \
|
|
||||||
mkdir -p /tmp/nginx
|
|
||||||
|
|
||||||
STOPSIGNAL SIGINT
|
|
||||||
EXPOSE 8080
|
|
||||||
|
|
||||||
WORKDIR /usr/share/nginx/html
|
|
||||||
|
|
||||||
COPY docker/default.conf /etc/nginx/http.d/default.conf
|
|
||||||
COPY docker/nginx.conf /etc/nginx/nginx.conf
|
|
||||||
COPY docker/rootless.conf /etc/nginx/http.d/rootless.conf
|
|
||||||
COPY docker/init_react_envs.sh /usr/local/init_react_envs.sh
|
|
||||||
COPY out/ /usr/share/nginx/html/
|
|
||||||
|
|
||||||
RUN sed -i \
|
|
||||||
-e 's/listen 80 default_server;/listen 8080 default_server;/' \
|
|
||||||
-e 's/listen \[::\]:80 default_server;/listen [::]:8080 default_server;/' \
|
|
||||||
/etc/nginx/http.d/default.conf && \
|
|
||||||
sed -i '/^user nginx;$/d' /etc/nginx/nginx.conf && \
|
|
||||||
chmod +x /usr/local/init_react_envs.sh && \
|
|
||||||
chgrp -R 0 /etc/nginx/http.d /usr/share/nginx/html /tmp/nginx && \
|
|
||||||
chmod -R g=u /etc/nginx/http.d /usr/share/nginx/html /tmp/nginx
|
|
||||||
|
|
||||||
USER 10001:0
|
|
||||||
ENTRYPOINT ["/usr/local/init_react_envs.sh"]
|
|
||||||
CMD ["/usr/sbin/nginx", "-e", "/dev/stderr", "-g", "pid /tmp/nginx.pid;"]
|
|
||||||
+10
-46
@@ -1,59 +1,23 @@
|
|||||||
# NetBird Dashboard
|
# NetBird Dashboard
|
||||||
|
NetBird Dashboard is NetBirds Management server UI. It allows users to signin, view setup keys and manage peers. This image is **not ready** for production use.
|
||||||
NetBird Dashboard is NetBird's management server UI.
|
|
||||||
|
|
||||||
## Tags
|
## Tags
|
||||||
|
```latest``` ```vX.X.X``` not available yet.
|
||||||
|
|
||||||
Each published image tag also has a rootless variant with the `-rootless`
|
```main``` built on every PR being merged to the repository
|
||||||
suffix. For example, `main` is also published as `main-rootless`.
|
|
||||||
|
|
||||||
## How to use this image
|
## How to use this image
|
||||||
|
HTTP run:
|
||||||
HTTP:
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
docker run -d --rm -p 80:80 netbirdio/dashboard:main
|
docker run -d --rm -p 80:80 wiretrustee/dashboard:main
|
||||||
```
|
```
|
||||||
|
Using SSL certificate from Let's Encrypt®:
|
||||||
Using an SSL certificate from Let's Encrypt:
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
docker run -d --rm -p 80:80 -p 443:443 \
|
docker run -d --rm -p 80:80 -p 443:443 \
|
||||||
-e LETSENCRYPT_DOMAIN=app.mydomain.com \
|
-e LETSENCRYPT_DOMAIN=app.mydomain.com \
|
||||||
-e LETSENCRYPT_EMAIL=hello@mydomain.com \
|
-e LETSENCRYPT_EMAIL=hello@mydomain.com \
|
||||||
netbirdio/dashboard:main
|
netbirdio/dashboard:main
|
||||||
```
|
```
|
||||||
|
> For SSL generation, you need to run this image in a server with proper public IP and a domain name pointing to it.
|
||||||
For certificate generation, the server needs a public IP and a domain name
|
|
||||||
pointing to it.
|
|
||||||
|
|
||||||
### Rootless and OpenShift
|
|
||||||
|
|
||||||
The rootless image listens on port `8080`, runs as UID `10001` by default, and
|
|
||||||
supports OpenShift's arbitrary UID when the container retains GID `0`:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker run -d --rm \
|
|
||||||
--user 12345:0 \
|
|
||||||
-p 8080:8080 \
|
|
||||||
-e AUTH_AUTHORITY=https://idp.example.com \
|
|
||||||
-e AUTH_CLIENT_ID=netbird-dashboard \
|
|
||||||
-e AUTH_AUDIENCE=netbird-dashboard \
|
|
||||||
-e AUTH_SUPPORTED_SCOPES='openid profile email' \
|
|
||||||
-e USE_AUTH0=false \
|
|
||||||
-e NETBIRD_MGMT_API_ENDPOINT=https://api.example.com \
|
|
||||||
netbirdio/dashboard:main-rootless
|
|
||||||
```
|
|
||||||
|
|
||||||
The rootless image does not include Certbot or expose HTTPS. Terminate TLS at
|
|
||||||
the OpenShift Route, Ingress, or another reverse proxy.
|
|
||||||
|
|
||||||
## Environment variables
|
## Environment variables
|
||||||
|
* ```NGINX_SSL_PORT``` Changes the port that Nginx listens to. Defaults to ```443```
|
||||||
- `NGINX_SSL_PORT` changes the port that Nginx listens to. Defaults to `443`.
|
* ```LETSENCRYPT_DOMAIN``` Enables Certbot`s client execution for the specified domain. Defaults to ```none```
|
||||||
- `LETSENCRYPT_DOMAIN` enables Certbot for the specified domain. Defaults to
|
* ```LETSENCRYPT_EMAIL``` Email used in Certbot`s client execution to register the certificate request. Defaults to ```example@local```
|
||||||
`none`.
|
|
||||||
- `LETSENCRYPT_EMAIL` is used to register the certificate request. Defaults to
|
|
||||||
`example@local`.
|
|
||||||
|
|
||||||
These certificate variables apply only to the standard image.
|
|
||||||
@@ -73,8 +73,6 @@ export NETBIRD_HUBSPOT_SIGNUP_FORM_ID=${NETBIRD_HUBSPOT_SIGNUP_FORM_ID}
|
|||||||
export NETBIRD_HUBSPOT_ONBOARDING_FORM_ID=${NETBIRD_HUBSPOT_ONBOARDING_FORM_ID}
|
export NETBIRD_HUBSPOT_ONBOARDING_FORM_ID=${NETBIRD_HUBSPOT_ONBOARDING_FORM_ID}
|
||||||
export NETBIRD_HUBSPOT_SURVEY_FORM_ID=${NETBIRD_HUBSPOT_SURVEY_FORM_ID}
|
export NETBIRD_HUBSPOT_SURVEY_FORM_ID=${NETBIRD_HUBSPOT_SURVEY_FORM_ID}
|
||||||
export NETBIRD_ANALYTICS_EXCLUDED_EMAILS=${NETBIRD_ANALYTICS_EXCLUDED_EMAILS}
|
export NETBIRD_ANALYTICS_EXCLUDED_EMAILS=${NETBIRD_ANALYTICS_EXCLUDED_EMAILS}
|
||||||
# A permanent banner for this deployment, shown to every user; empty for none.
|
|
||||||
export NETBIRD_ANNOUNCEMENT=${NETBIRD_ANNOUNCEMENT}
|
|
||||||
|
|
||||||
echo "NetBird latest version: ${NETBIRD_LATEST_VERSION}"
|
echo "NetBird latest version: ${NETBIRD_LATEST_VERSION}"
|
||||||
|
|
||||||
@@ -165,7 +163,7 @@ sed -i "s|add_header Content-Security-Policy \"[^\"]*\" always;|$CSP_HEADER|g" /
|
|||||||
}
|
}
|
||||||
|
|
||||||
# replace ENVs in the config
|
# replace ENVs in the config
|
||||||
ENV_STR="\$\$USE_AUTH0 \$\$AUTH_AUDIENCE \$\$AUTH_AUTHORITY \$\$AUTH_CLIENT_ID \$\$AUTH_CLIENT_SECRET \$\$AUTH_SUPPORTED_SCOPES \$\$NETBIRD_MGMT_API_ENDPOINT \$\$NETBIRD_MGMT_GRPC_API_ENDPOINT \$\$NETBIRD_HOTJAR_TRACK_ID \$\$NETBIRD_GOOGLE_ANALYTICS_ID \$\$NETBIRD_GOOGLE_TAG_MANAGER_ID \$\$AUTH_REDIRECT_URI \$\$AUTH_SILENT_REDIRECT_URI \$\$NETBIRD_TOKEN_SOURCE \$\$NETBIRD_DRAG_QUERY_PARAMS \$\$NETBIRD_AUTH_SERVICE_URL \$\$NETBIRD_WASM_PATH \$\$NETBIRD_LICENSED \$\$NETBIRD_CLOUD \$\$NETBIRD_AGENT_NETWORK_ONLY \$\$NETBIRD_AGENT_NETWORK_ENABLED \$\$NETBIRD_HUBSPOT_PORTAL_ID \$\$NETBIRD_HUBSPOT_SIGNUP_FORM_ID \$\$NETBIRD_HUBSPOT_ONBOARDING_FORM_ID \$\$NETBIRD_HUBSPOT_SURVEY_FORM_ID \$\$NETBIRD_ANALYTICS_EXCLUDED_EMAILS \$\$NETBIRD_ANNOUNCEMENT"
|
ENV_STR="\$\$USE_AUTH0 \$\$AUTH_AUDIENCE \$\$AUTH_AUTHORITY \$\$AUTH_CLIENT_ID \$\$AUTH_CLIENT_SECRET \$\$AUTH_SUPPORTED_SCOPES \$\$NETBIRD_MGMT_API_ENDPOINT \$\$NETBIRD_MGMT_GRPC_API_ENDPOINT \$\$NETBIRD_HOTJAR_TRACK_ID \$\$NETBIRD_GOOGLE_ANALYTICS_ID \$\$NETBIRD_GOOGLE_TAG_MANAGER_ID \$\$AUTH_REDIRECT_URI \$\$AUTH_SILENT_REDIRECT_URI \$\$NETBIRD_TOKEN_SOURCE \$\$NETBIRD_DRAG_QUERY_PARAMS \$\$NETBIRD_AUTH_SERVICE_URL \$\$NETBIRD_WASM_PATH \$\$NETBIRD_LICENSED \$\$NETBIRD_CLOUD \$\$NETBIRD_AGENT_NETWORK_ONLY \$\$NETBIRD_AGENT_NETWORK_ENABLED \$\$NETBIRD_HUBSPOT_PORTAL_ID \$\$NETBIRD_HUBSPOT_SIGNUP_FORM_ID \$\$NETBIRD_HUBSPOT_ONBOARDING_FORM_ID \$\$NETBIRD_HUBSPOT_SURVEY_FORM_ID \$\$NETBIRD_ANALYTICS_EXCLUDED_EMAILS"
|
||||||
|
|
||||||
OIDC_TRUSTED_DOMAINS="/usr/share/nginx/html/OidcTrustedDomains.js"
|
OIDC_TRUSTED_DOMAINS="/usr/share/nginx/html/OidcTrustedDomains.js"
|
||||||
envsubst "$ENV_STR" < "$OIDC_TRUSTED_DOMAINS".tmpl > "$OIDC_TRUSTED_DOMAINS"
|
envsubst "$ENV_STR" < "$OIDC_TRUSTED_DOMAINS".tmpl > "$OIDC_TRUSTED_DOMAINS"
|
||||||
@@ -175,12 +173,6 @@ for f in $(grep -R -l AUTH_SUPPORTED_SCOPES /usr/share/nginx/html); do
|
|||||||
rm "$f".copy
|
rm "$f".copy
|
||||||
done
|
done
|
||||||
|
|
||||||
# When a command is provided, initialization happens before the server starts.
|
|
||||||
# The rootless image uses this path so nginx never needs to be reloaded.
|
|
||||||
if (( $# > 0 )); then
|
|
||||||
exec "$@"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Reload nginx so the patched CSP header takes effect.
|
# Reload nginx so the patched CSP header takes effect.
|
||||||
# supervisord starts nginx (priority 100) before this script (priority 201) and
|
# supervisord starts nginx (priority 100) before this script (priority 201) and
|
||||||
# never reloads it, so without this nginx keeps serving the static default.conf
|
# never reloads it, so without this nginx keeps serving the static default.conf
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
# nginx includes this file inside the http context.
|
|
||||||
# All runtime state stays in a directory writable by the arbitrary UID used by OpenShift.
|
|
||||||
client_body_temp_path /tmp/nginx/client_temp;
|
|
||||||
proxy_temp_path /tmp/nginx/proxy_temp;
|
|
||||||
fastcgi_temp_path /tmp/nginx/fastcgi_temp;
|
|
||||||
uwsgi_temp_path /tmp/nginx/uwsgi_temp;
|
|
||||||
scgi_temp_path /tmp/nginx/scgi_temp;
|
|
||||||
@@ -218,7 +218,6 @@ await visitByNavigation(page, "Policies"); // Click child
|
|||||||
| Notifications | `settings-notifications-email.spec.ts`, `settings-notifications-slack.spec.ts`, `settings-notifications-webhook.spec.ts` | `@notifications` |
|
| Notifications | `settings-notifications-email.spec.ts`, `settings-notifications-slack.spec.ts`, `settings-notifications-webhook.spec.ts` | `@notifications` |
|
||||||
| Team | `team-users.spec.ts`, `team-service-users.spec.ts`, `team-users-approval-and-billing.spec.ts` | `@team` |
|
| Team | `team-users.spec.ts`, `team-service-users.spec.ts`, `team-users-approval-and-billing.spec.ts` | `@team` |
|
||||||
| Setup Keys | `setup-keys.spec.ts` | `@setup-keys` |
|
| Setup Keys | `setup-keys.spec.ts` | `@setup-keys` |
|
||||||
| Control Center | `control-center-*.spec.ts` (`-draft`, `-draft-connections`, `-draft-matrix`, `-draft-extras`, `-draft-install`, `-draft-remove`, `-draft-shortcuts`, `-deploy`, `-drilldown`, `-live`, `-peers`) | `@control-center` |
|
|
||||||
|
|
||||||
## Debugging
|
## Debugging
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
# Ignore zitadel environment
|
# Ignore zitadel environment
|
||||||
.env
|
.env
|
||||||
Caddyfile
|
Caddyfile
|
||||||
agentgateway-stub.Caddyfile
|
|
||||||
management.json
|
management.json
|
||||||
turnserver.conf
|
turnserver.conf
|
||||||
zitadel.env
|
zitadel.env
|
||||||
@@ -10,6 +9,4 @@ proxy-no-ports.env
|
|||||||
proxy-certs/
|
proxy-certs/
|
||||||
proxy-certs-no-ports/
|
proxy-certs-no-ports/
|
||||||
docker-compose.yml
|
docker-compose.yml
|
||||||
/machinekey
|
/machinekey
|
||||||
geo-cache/
|
|
||||||
geo-dump/
|
|
||||||
@@ -19,7 +19,7 @@ check_docker_compose() {
|
|||||||
DOCKER_COMPOSE_COMMAND=$(check_docker_compose)
|
DOCKER_COMPOSE_COMMAND=$(check_docker_compose)
|
||||||
|
|
||||||
$DOCKER_COMPOSE_COMMAND down --volumes
|
$DOCKER_COMPOSE_COMMAND down --volumes
|
||||||
rm -f docker-compose.yml Caddyfile agentgateway-stub.Caddyfile zitadel.env .env dashboard.env machinekey/zitadel-admin-sa.token turnserver.conf management.json proxy.env proxy-no-ports.env
|
rm -f docker-compose.yml Caddyfile zitadel.env .env dashboard.env machinekey/zitadel-admin-sa.token turnserver.conf management.json proxy.env proxy-no-ports.env
|
||||||
rm -rf proxy-certs proxy-certs-no-ports
|
rm -rf proxy-certs proxy-certs-no-ports
|
||||||
rm -f ../../.test-config.json ../playwright.env.json
|
rm -f ../../.test-config.json ../playwright.env.json
|
||||||
rm -f ../fixtures/auth/owner.json ../fixtures/auth/user.json
|
rm -f ../fixtures/auth/owner.json ../fixtures/auth/user.json
|
||||||
@@ -61,13 +61,7 @@ wait_proxy_cluster() {
|
|||||||
SERVICE_NAME=${1:-reverse-proxy}
|
SERVICE_NAME=${1:-reverse-proxy}
|
||||||
echo -n "Waiting for $SERVICE_NAME to register with management "
|
echo -n "Waiting for $SERVICE_NAME to register with management "
|
||||||
set +e
|
set +e
|
||||||
# 480s: management downloads its geolocation databases on first boot
|
local attempts=60
|
||||||
# (the proxy specs need /locations/countries, so it cannot be disabled
|
|
||||||
# there), and a slow pkgs.netbird.io can stall that well past the old
|
|
||||||
# 120s budget. The proxies skip their download entirely via
|
|
||||||
# NB_PROXY_DISABLE_GEOLOCATION. The loop exits as soon as the sync
|
|
||||||
# lands, so healthy runs pay nothing.
|
|
||||||
local attempts=240
|
|
||||||
local i
|
local i
|
||||||
for ((i = 1; i <= attempts; i++)); do
|
for ((i = 1; i <= attempts; i++)); do
|
||||||
if $DOCKER_COMPOSE_COMMAND logs "$SERVICE_NAME" 2>&1 | grep -q "Initial mapping sync complete"; then
|
if $DOCKER_COMPOSE_COMMAND logs "$SERVICE_NAME" 2>&1 | grep -q "Initial mapping sync complete"; then
|
||||||
@@ -532,7 +526,7 @@ initEnvironment() {
|
|||||||
echo "Generated files already exist, if you want to reinitialize the environment, please remove them first."
|
echo "Generated files already exist, if you want to reinitialize the environment, please remove them first."
|
||||||
echo "You can use the following commands:"
|
echo "You can use the following commands:"
|
||||||
echo " $DOCKER_COMPOSE_COMMAND down --volumes # to remove all containers and volumes"
|
echo " $DOCKER_COMPOSE_COMMAND down --volumes # to remove all containers and volumes"
|
||||||
echo " rm -f docker-compose.yml Caddyfile agentgateway-stub.Caddyfile zitadel.env dashboard.env machinekey/zitadel-admin-sa.token turnserver.conf management.json proxy.env proxy-no-ports.env && rm -rf proxy-certs proxy-certs-no-ports"
|
echo " rm -f docker-compose.yml Caddyfile zitadel.env dashboard.env machinekey/zitadel-admin-sa.token turnserver.conf management.json proxy.env proxy-no-ports.env && rm -rf proxy-certs proxy-certs-no-ports"
|
||||||
echo "Be aware that this will remove all data from the database, and you will have to reconfigure the dashboard."
|
echo "Be aware that this will remove all data from the database, and you will have to reconfigure the dashboard."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -540,7 +534,6 @@ initEnvironment() {
|
|||||||
echo Rendering initial files...
|
echo Rendering initial files...
|
||||||
renderDockerCompose > docker-compose.yml
|
renderDockerCompose > docker-compose.yml
|
||||||
renderCaddyfile > Caddyfile
|
renderCaddyfile > Caddyfile
|
||||||
renderAgentGatewayStub > agentgateway-stub.Caddyfile
|
|
||||||
renderZitadelEnv > zitadel.env
|
renderZitadelEnv > zitadel.env
|
||||||
echo "" > turnserver.conf
|
echo "" > turnserver.conf
|
||||||
echo "" > management.json
|
echo "" > management.json
|
||||||
@@ -596,8 +589,6 @@ initEnvironment() {
|
|||||||
echo -e "\nCreating proxy access tokens...\n"
|
echo -e "\nCreating proxy access tokens...\n"
|
||||||
init_proxy_tokens
|
init_proxy_tokens
|
||||||
|
|
||||||
exportGeoDatabases
|
|
||||||
|
|
||||||
echo -e "\nStarting reverse proxy services...\n"
|
echo -e "\nStarting reverse proxy services...\n"
|
||||||
$DOCKER_COMPOSE_COMMAND up -d reverse-proxy reverse-proxy-no-ports
|
$DOCKER_COMPOSE_COMMAND up -d reverse-proxy reverse-proxy-no-ports
|
||||||
|
|
||||||
@@ -613,30 +604,6 @@ initEnvironment() {
|
|||||||
echo "Password: $ZITADEL_ADMIN_PASSWORD" | tee -a .env
|
echo "Password: $ZITADEL_ADMIN_PASSWORD" | tee -a .env
|
||||||
}
|
}
|
||||||
|
|
||||||
# Saving an Agent Network provider makes management call the upstream and
|
|
||||||
# refuses the save unless it answers a model listing, so a provider spec needs
|
|
||||||
# a reachable OpenAI-compatible endpoint. agentgateway is self-hosted and has
|
|
||||||
# no public one; this stub stands in for it, inside the compose network where
|
|
||||||
# management can reach it and without depending on a vendor being up.
|
|
||||||
renderAgentGatewayStub() {
|
|
||||||
cat <<'EOF'
|
|
||||||
{
|
|
||||||
admin off
|
|
||||||
auto_https off
|
|
||||||
}
|
|
||||||
|
|
||||||
:8088 {
|
|
||||||
handle /v1/models {
|
|
||||||
header Content-Type application/json
|
|
||||||
respond `{"object":"list","data":[{"id":"agentgateway-e2e-model","object":"model","owned_by":"netbird-e2e"}]}` 200
|
|
||||||
}
|
|
||||||
handle {
|
|
||||||
respond 404
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
renderCaddyfile() {
|
renderCaddyfile() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
{
|
{
|
||||||
@@ -793,41 +760,7 @@ ZITADEL_FIRSTINSTANCE_ORG_MACHINE_PAT_EXPIRATIONDATE=$ZIDATE_TOKEN_EXPIRATION_DA
|
|||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
# Copies management's geolocation databases out of its data volume into
|
|
||||||
# ./geo-cache so CI can cache them across runs. Management has finished
|
|
||||||
# loading them by the time its API serves requests. A no-op when the
|
|
||||||
# cache already holds both files, and never fatal: a failed export just
|
|
||||||
# means the next run downloads again.
|
|
||||||
exportGeoDatabases() {
|
|
||||||
mkdir -p geo-cache
|
|
||||||
if compgen -G "geo-cache/GeoLite2-City_*.mmdb" > /dev/null \
|
|
||||||
&& compgen -G "geo-cache/geonames_*.db" > /dev/null; then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
echo -e "\nExporting geolocation databases for caching...\n"
|
|
||||||
rm -rf geo-dump
|
|
||||||
if $DOCKER_COMPOSE_COMMAND cp management:/var/lib/netbird ./geo-dump; then
|
|
||||||
cp geo-dump/GeoLite2-City_*.mmdb geo-dump/geonames_*.db geo-cache/ 2>/dev/null \
|
|
||||||
|| echo "WARN: no geolocation databases found in management data dir"
|
|
||||||
rm -rf geo-dump
|
|
||||||
else
|
|
||||||
echo "WARN: could not copy management data dir; geolocation databases not cached"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
renderDockerCompose() {
|
renderDockerCompose() {
|
||||||
# Cached geolocation databases (restored by CI into ./geo-cache) are
|
|
||||||
# mounted into management's data dir so it skips the slow first-boot
|
|
||||||
# download from pkgs.netbird.io. With no cache the mounts are omitted
|
|
||||||
# and management downloads as before.
|
|
||||||
local geo_mounts=""
|
|
||||||
local f
|
|
||||||
for f in geo-cache/GeoLite2-City_*.mmdb geo-cache/geonames_*.db; do
|
|
||||||
[ -f "$f" ] || continue
|
|
||||||
geo_mounts+="
|
|
||||||
- ./${f}:/var/lib/netbird/$(basename "$f")"
|
|
||||||
done
|
|
||||||
|
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
version: "3.4"
|
version: "3.4"
|
||||||
services:
|
services:
|
||||||
@@ -843,15 +776,6 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- netbird_caddy_data:/data
|
- netbird_caddy_data:/data
|
||||||
- ./Caddyfile:/etc/caddy/Caddyfile
|
- ./Caddyfile:/etc/caddy/Caddyfile
|
||||||
# Stand-in upstream for the Agent Network provider specs: answers the model
|
|
||||||
# listing management probes before it accepts a provider save. Reachable
|
|
||||||
# only from inside the compose network, at http://agentgateway-stub:8088.
|
|
||||||
agentgateway-stub:
|
|
||||||
image: caddy
|
|
||||||
restart: unless-stopped
|
|
||||||
networks: [ netbird ]
|
|
||||||
volumes:
|
|
||||||
- ./agentgateway-stub.Caddyfile:/etc/caddy/Caddyfile
|
|
||||||
# Management
|
# Management
|
||||||
management:
|
management:
|
||||||
image: ghcr.io/netbirdio/management-cloud:${MANAGEMENT_IMAGE_TAG}
|
image: ghcr.io/netbirdio/management-cloud:${MANAGEMENT_IMAGE_TAG}
|
||||||
@@ -870,7 +794,7 @@ services:
|
|||||||
- NB_TRAFFIC_FLOW_INTERVAL=20s
|
- NB_TRAFFIC_FLOW_INTERVAL=20s
|
||||||
- NB_SINGLE_INSTANCE_MODE=true
|
- NB_SINGLE_INSTANCE_MODE=true
|
||||||
volumes:
|
volumes:
|
||||||
- netbird_management:/var/lib/netbird${geo_mounts}
|
- netbird_management:/var/lib/netbird
|
||||||
- ./management.json:/etc/netbird/management.json
|
- ./management.json:/etc/netbird/management.json
|
||||||
command: [
|
command: [
|
||||||
"--port", "80",
|
"--port", "80",
|
||||||
@@ -921,21 +845,6 @@ services:
|
|||||||
networks: [netbird]
|
networks: [netbird]
|
||||||
env_file:
|
env_file:
|
||||||
- ./proxy.env
|
- ./proxy.env
|
||||||
environment:
|
|
||||||
# No spec exercises country-based enforcement, and skipping the
|
|
||||||
# GeoLite2 download removes a startup stall of up to 2 minutes
|
|
||||||
# when pkgs.netbird.io is slow.
|
|
||||||
- NB_PROXY_DISABLE_GEOLOCATION=true
|
|
||||||
# Declare the private capability so this cluster can host the agent
|
|
||||||
# network endpoint. That endpoint is a private service — reachable only
|
|
||||||
# from connected peers — and management refuses to bootstrap it onto a
|
|
||||||
# cluster without a private-capable proxy; the connect-provider wizard
|
|
||||||
# reads the same flag (supports_private) to pick its cluster. Without
|
|
||||||
# it no cluster qualifies and the wizard stops at the provider tab,
|
|
||||||
# which strands every spec that walks through it. The no-ports proxy
|
|
||||||
# below stays centralised, so the pick has to skip past a cluster that
|
|
||||||
# does not qualify.
|
|
||||||
- NB_PROXY_PRIVATE=true
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./proxy-certs:/certs:ro
|
- ./proxy-certs:/certs:ro
|
||||||
command: [
|
command: [
|
||||||
@@ -957,9 +866,6 @@ services:
|
|||||||
networks: [netbird]
|
networks: [netbird]
|
||||||
env_file:
|
env_file:
|
||||||
- ./proxy-no-ports.env
|
- ./proxy-no-ports.env
|
||||||
environment:
|
|
||||||
# See the primary proxy: no spec needs geo enforcement.
|
|
||||||
- NB_PROXY_DISABLE_GEOLOCATION=true
|
|
||||||
volumes:
|
volumes:
|
||||||
# Distinct cert dir so this proxy has a distinct identity from the
|
# Distinct cert dir so this proxy has a distinct identity from the
|
||||||
# primary proxy; a shared cert makes both register under the same
|
# primary proxy; a shared cert makes both register under the same
|
||||||
|
|||||||
+82
-269
File diff suppressed because it is too large.
Load diff
+2
-10
@@ -33,7 +33,7 @@ export async function loginToApp(
|
|||||||
// Use locators that match either outcome — Playwright auto-waits.
|
// Use locators that match either outcome — Playwright auto-waits.
|
||||||
const appReady = page.getByTestId("left-navigation-item").first();
|
const appReady = page.getByTestId("left-navigation-item").first();
|
||||||
const setupModal = page.getByTestId("setup-netbird-modal");
|
const setupModal = page.getByTestId("setup-netbird-modal");
|
||||||
const approvalPending = page.getByTestId("pending-approval");
|
const approvalPending = page.getByText("User Approval Pending");
|
||||||
const onboarding = page.getByText("Add new device to your network");
|
const onboarding = page.getByText("Add new device to your network");
|
||||||
const selectAccount = page.getByText("Select account");
|
const selectAccount = page.getByText("Select account");
|
||||||
const loginInput = page.locator("input[id=loginName]");
|
const loginInput = page.locator("input[id=loginName]");
|
||||||
@@ -117,15 +117,7 @@ export async function loginToApp(
|
|||||||
* Use this instead of page.goto() for in-app navigation after loginToApp().
|
* Use this instead of page.goto() for in-app navigation after loginToApp().
|
||||||
*/
|
*/
|
||||||
export async function navigateTo(page: Page, path: string) {
|
export async function navigateTo(page: Page, path: string) {
|
||||||
// A client-side route update still in flight from the previous test (the
|
await page.goto(path, { waitUntil: "domcontentloaded" });
|
||||||
// dashboard page is shared per worker) aborts the navigation. Retry once —
|
|
||||||
// by then the app-driven navigation has landed.
|
|
||||||
try {
|
|
||||||
await page.goto(path, { waitUntil: "domcontentloaded" });
|
|
||||||
} catch (e) {
|
|
||||||
if (!String(e).includes("ERR_ABORTED")) throw e;
|
|
||||||
await page.goto(path, { waitUntil: "domcontentloaded" });
|
|
||||||
}
|
|
||||||
const modal = page.getByTestId("setup-netbird-modal");
|
const modal = page.getByTestId("setup-netbird-modal");
|
||||||
try {
|
try {
|
||||||
await modal.waitFor({ state: "visible", timeout: 3_000 });
|
await modal.waitFor({ state: "visible", timeout: 3_000 });
|
||||||
|
|||||||
Loaded 20 of 385 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user