Merge remote-tracking branch 'origin/main' into embedded-vnc

# Conflicts:
#	client/cmd/up.go
#	client/internal/engine.go
#	client/internal/profilemanager/config.go
#	client/proto/daemon.pb.go
#	client/server/mdm.go
#	client/server/server.go
#	client/status/status.go
#	client/ui/main.go
#	client/ui/services/windowmanager.go
#	management/internals/shared/grpc/conversion.go
#	management/server/store/sql_store.go
#	management/server/store/sql_store_test.go
#	shared/management/networkmap/envelope.go
#	shared/management/proto/management.pb.go
This commit is contained in:
Viktor Liu
2026-10-19 19:49:54 +09:00
804 changed files with 72029 additions and 25943 deletions
+1 -1
View File
@@ -52,7 +52,7 @@ jobs:
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-anet-e2e-buildx-${{ hashFiles('go.sum', 'combined/Dockerfile.multistage', 'proxy/Dockerfile.multistage', 'e2e/harness/Dockerfile.client') }}
key: ${{ runner.os }}-anet-e2e-buildx-${{ hashFiles('go.sum', 'combined/Dockerfile.multistage', 'proxy/Dockerfile.multistage', 'e2e/harness/Dockerfile.client', 'e2e/harness/Dockerfile.nblink') }}
restore-keys: |
${{ runner.os }}-anet-e2e-buildx-
@@ -34,7 +34,7 @@ jobs:
while IFS= read -r dir; do
echo "=== Checking $dir ==="
# Search for problematic imports, excluding test files
RESULTS=$(grep -r "github.com/netbirdio/netbird/\(management\|signal\|relay\|proxy\)" "$dir" --include="*.go" 2>/dev/null | grep -v "_test.go" | grep -v "test_" | grep -v "/test/" | grep -v "tools/idp-migrate/" || true)
RESULTS=$(grep -r "github.com/netbirdio/netbird/\(management\|signal\|relay\|proxy\)" "$dir" --include="*.go" 2>/dev/null | grep -v "_test.go" | grep -v "test_" | grep -v "/test/" | grep -v "tools/idp-migrate/" | grep -v "tools/mysql-migrate/" || true)
if [ -n "$RESULTS" ]; then
echo "❌ Found problematic dependencies:"
echo "$RESULTS"
@@ -93,7 +93,7 @@ jobs:
IMPORTERS=$(go list -json -deps ./... 2>/dev/null | jq -r "select(.Imports[]? == \"$package\") | .ImportPath")
# Check if any importer is NOT in management/signal/relay
BSD_IMPORTER=$(echo "$IMPORTERS" | grep -v "github.com/netbirdio/netbird/\(management\|signal\|relay\|proxy\|combined\|tools/idp-migrate\)" | head -1)
BSD_IMPORTER=$(echo "$IMPORTERS" | grep -v "github.com/netbirdio/netbird/\(management\|signal\|relay\|proxy\|combined\|tools/idp-migrate\|tools/mysql-migrate\)" | head -1)
if [ -n "$BSD_IMPORTER" ]; then
echo "❌ $package ($license) is imported by BSD-licensed code: $BSD_IMPORTER"
+2
View File
@@ -12,6 +12,8 @@ jobs:
docs-ack:
name: Require docs PR URL or explicit "not needed"
runs-on: ubuntu-latest
# Crowdin's translation-sync service PRs are auto-generated without the PR template.
if: github.event.pull_request.user.login != 'netbirddev'
steps:
- name: Read PR body
+3 -3
View File
@@ -38,12 +38,12 @@ jobs:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v7
with:
node-version: "22"
- name: Set up pnpm
uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
with:
version: 11
@@ -79,7 +79,7 @@ jobs:
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@v6
with:
path: ${{ steps.pnpm-store.outputs.path }}
key: ${{ runner.os }}-pnpm-${{ hashFiles('client/ui/frontend/pnpm-lock.yaml') }}
+1 -1
View File
@@ -33,7 +33,7 @@ jobs:
with:
usesh: true
copyback: false
release: "15.0"
release: "15.1"
envs: "GO_VERSION"
prepare: |
pkg install -y curl pkgconf xorg
+38 -1
View File
@@ -207,6 +207,43 @@ jobs:
# regression test, and need no frontend bundle.
run: CGO_ENABLED=1 go test -timeout 5m ./client/ui/authsession/... ./client/ui/i18n/... ./client/ui/preferences/... ./client/ui/services/...
test_client_pkcs11:
name: "Client PKCS#11 / Unit"
# The deb and rpm packages ship the client built with the pkcs11 tag, which loads
# PKCS#11 modules through purego. The other jobs build without the tag, so this one
# compiles that driver and signs with a real SoftHSM token, the build release ships.
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Install Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: "go.mod"
cache: false
- name: Install SoftHSM
run: sudo apt update && sudo apt install -y -q softhsm2
- name: Initialise token
run: |
mkdir -p "$RUNNER_TEMP/softhsm/tokens"
printf 'directories.tokendir = %s\nobjectstore.backend = file\n' "$RUNNER_TEMP/softhsm/tokens" > "$RUNNER_TEMP/softhsm/softhsm2.conf"
echo "SOFTHSM2_CONF=$RUNNER_TEMP/softhsm/softhsm2.conf" >> "$GITHUB_ENV"
SOFTHSM2_CONF="$RUNNER_TEMP/softhsm/softhsm2.conf" softhsm2-util --init-token --free --label netbird --pin 1234 --so-pin 1234
- name: Vet
run: CGO_ENABLED=0 go vet -tags pkcs11 ./client/internal/pkcs11/... ./client/internal/certproof/...
- name: Test
env:
NB_TEST_PKCS11_URI: "pkcs11:token=netbird?module-path=/usr/lib/softhsm/libsofthsm2.so&pin-value=1234"
NB_TEST_PKCS11_DISPOSABLE: "1"
run: CGO_ENABLED=0 go test -tags pkcs11 -timeout 5m ./client/internal/pkcs11/... ./client/internal/certproof/...
test_client_on_docker:
name: "Client (Docker) / Unit"
needs: [build-cache]
@@ -270,7 +307,7 @@ jobs:
sh -c ' \
apk update; apk add --no-cache \
ca-certificates iptables ip6tables dbus dbus-dev libpcap-dev build-base; \
go test -buildvcs=false -tags "devcert privileged" -v -timeout 10m -p 1 $(go list -e -buildvcs=false ./... | grep -v -e /management -e /signal -e /relay -e /proxy -e /combined -e /client/ui -e /upload-server -e /client/testutil/privileged)
go test -buildvcs=false -tags "devcert privileged" -v -timeout 10m -p 1 $(go list -e -buildvcs=false ./... | grep -v -e /management -e /signal -e /relay -e /proxy -e /combined -e /client/ui -e /upload-server -e /client/testutil/privileged -e tools/mysql-migrate)
'
test_relay:
+1 -1
View File
@@ -76,7 +76,7 @@ jobs:
# resolve; the Where-Object pipeline then drops the broken package by
# path. Without -e, go list aborts with empty stdout.
run: |
$packages = go list -e ./... | Where-Object { $_ -notmatch '/management' } | Where-Object { $_ -notmatch '/relay' } | Where-Object { $_ -notmatch '/signal' } | Where-Object { $_ -notmatch '/proxy' } | Where-Object { $_ -notmatch '/combined' } | Where-Object { $_ -notmatch '/client/ui$' }
$packages = go list -e ./... | Where-Object { $_ -notmatch '/management' } | Where-Object { $_ -notmatch '/relay' } | Where-Object { $_ -notmatch '/signal' } | Where-Object { $_ -notmatch '/proxy' } | Where-Object { $_ -notmatch '/combined' } | Where-Object { $_ -notmatch '/client/ui$' } | Where-Object { $_ -notmatch '/tools/mysql-migrate' }
$goExe = "C:\hostedtoolcache\windows\go\${{ steps.go.outputs.go-version }}\x64\bin\go.exe"
$cmd = "$goExe test -tags `"devcert privileged`" -timeout 10m -p 1 $($packages -join ' ') > test-out.txt 2>&1"
Set-Content -Path "${{ github.workspace }}\run-tests.cmd" -Value $cmd
+47 -1
View File
@@ -30,7 +30,7 @@ jobs:
# segment by codespell and behave the same across versions; the
# recursive "**" form did not take effect with the codespell shipped
# by this action.
skip: go.mod,go.sum,*/proxy/web/*,*pnpm-lock.yaml,*package-lock.json,*/locales/de/*,*/locales/es/*,*/locales/fr/*,*/locales/hu/*,*/locales/it/*,*/locales/pt/*,*/locales/ru/*,*/locales/zh-CN/*,*/i18n/TRANSLATING.md
skip: go.mod,go.sum,*/proxy/web/*,*pnpm-lock.yaml,*package-lock.json,*/locales/de/*,*/locales/es/*,*/locales/fr/*,*/locales/gl/*,*/locales/hu/*,*/locales/it/*,*/locales/pt/*,*/locales/ru/*,*/locales/zh-CN/*,*/i18n/TRANSLATING.md
golangci:
strategy:
fail-fast: false
@@ -80,3 +80,49 @@ jobs:
skip-save-cache: true
cache-invalidation-interval: 0
args: --timeout=20m
# Separate job rather than extra rows in the matrix above: those rows pick a
# GOOS by picking a runner OS, while android/ios are cross-compiled from
# ubuntu — an `include` entry with os: ubuntu-latest would merge into the
# Linux row instead of adding one. The package path is restricted because a
# whole-repo run under GOOS=android pulls *_linux.go files into packages that
# have no android counterpart.
golangci-mobile:
strategy:
fail-fast: false
matrix:
include:
- goos: android
goarch: arm64
packages: ./client/android/...
display_name: Android
- goos: ios
goarch: arm64
packages: ./client/ios/...
display_name: iOS
name: ${{ matrix.display_name }}
runs-on: ubuntu-latest
timeout-minutes: 25
env:
CGO_ENABLED: 0
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
steps:
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Install Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: "go.mod"
cache: false
- name: golangci-lint
uses: golangci/golangci-lint-action@82606bf257cbaff209d206a39f5134f0cfbfd2ee #v9.2.1
with:
version: latest
install-mode: binary
skip-cache: true
skip-save-cache: true
cache-invalidation-interval: 0
args: --timeout=20m ${{ matrix.packages }}
@@ -0,0 +1,64 @@
name: Mobile
on:
push:
branches:
- main
- "release-*"
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.head_ref || github.actor_id }}
cancel-in-progress: true
jobs:
android_build:
name: "Android / Build"
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
goarch: [arm64, arm, amd64, "386"]
env:
CGO_ENABLED: 0
GOOS: android
GOARCH: ${{ matrix.goarch }}
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Install Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: "go.mod"
- name: Build Android bridge
run: go build ./client/android/...
- name: Vet Android bridge
if: matrix.goarch == 'arm64'
run: go vet ./client/android/...
ios_build:
name: "iOS / Build"
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
goarch: [arm64, amd64]
env:
CGO_ENABLED: 0
GOOS: ios
GOARCH: ${{ matrix.goarch }}
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Install Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: "go.mod"
# No `go vet` counterpart: every ios target requires external (cgo)
# linking, which needs an Xcode toolchain the runner does not have.
- name: Build iOS SDK
run: go build ./client/ios/...
+2
View File
@@ -7,6 +7,8 @@ on:
jobs:
check-title:
runs-on: ubuntu-latest
# Crowdin's translation-sync service PRs are auto-generated with a fixed title.
if: github.event.pull_request.user.login != 'netbirddev'
steps:
- name: Validate PR title prefix
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+207
View File
@@ -0,0 +1,207 @@
name: Red Hat Certification
# Certify published UBI images in the Red Hat Ecosystem Catalog. Called by
# release.yml on stable tags, or run by hand to (re)certify any released
# version. preflight submits every architecture of an image's manifest list
# to Pyxis; auto-publish on the component makes it public once certified.
#
# Each component's Partner Connect ID comes from the REDHAT_CERT_ID_<NAME>
# repository variable, e.g. REDHAT_CERT_ID_CLIENT_ROOTLESS. The run fails
# before certifying anything if a selected component's variable is not set.
on:
workflow_call:
inputs:
component:
type: string
required: true
version:
type: string
required: true
secrets:
PYXIS_API_TOKEN:
required: true
workflow_dispatch:
inputs:
component:
description: "Component to certify"
type: choice
required: true
default: all
options:
- all
- client-rootless
- reverse-proxy
- netbird-server
- management
- signal
- relay
version:
description: "Released version, e.g. v0.80.0"
type: string
required: true
permissions:
contents: read
jobs:
resolve:
name: Resolve components
runs-on: ubuntu-24.04
outputs:
version: ${{ steps.resolve.outputs.version }}
matrix: ${{ steps.resolve.outputs.matrix }}
steps:
- name: Resolve components and images
id: resolve
env:
COMPONENT: ${{ inputs.component }}
INPUT_VERSION: ${{ inputs.version }}
REPO_VARS: ${{ toJSON(vars) }}
run: |
set -euo pipefail
version="${INPUT_VERSION#v}"
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::Only stable x.y.z versions are certified, got '${INPUT_VERSION}'"
exit 1
fi
# name, image repository, tag suffix (must match .goreleaser.yaml).
# Keep the names in sync with the workflow_dispatch options above.
components=(
"client-rootless ghcr.io/netbirdio/netbird -rootless-ubi"
"reverse-proxy ghcr.io/netbirdio/reverse-proxy -ubi"
"netbird-server ghcr.io/netbirdio/netbird-server -ubi"
"management ghcr.io/netbirdio/management -ubi"
"signal ghcr.io/netbirdio/signal -ubi"
"relay ghcr.io/netbirdio/relay -ubi"
)
matrix="[]"
missing=()
for c in "${components[@]}"; do
read -r name repo suffix <<< "$c"
[[ "$COMPONENT" == all || "$COMPONENT" == "$name" ]] || continue
var="REDHAT_CERT_ID_${name^^}"; var="${var//-/_}"
id="$(jq -r --arg v "$var" '.[$v] // empty' <<< "$REPO_VARS")"
if [[ -z "$id" ]]; then
missing+=("$var")
continue
fi
matrix="$(jq -c --arg n "$name" --arg t "${version}${suffix}" --arg r "${repo}:${version}${suffix}" --arg i "$id" \
'. + [{component: $n, tag: $t, ref: $r, component_id: $i}]' <<< "$matrix")"
done
if (( ${#missing[@]} )); then
echo "::error::Set these repository variables to the Partner Connect component IDs: ${missing[*]}"
exit 1
fi
if [[ "$matrix" == "[]" ]]; then
echo "::error::No component to certify for '${COMPONENT}'"
exit 1
fi
echo "Components to certify: ${matrix}"
echo "version=${version}" >> "$GITHUB_OUTPUT"
echo "matrix=${matrix}" >> "$GITHUB_OUTPUT"
certify:
name: "Certify ${{ matrix.component }} UBI image"
needs: resolve
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
include: ${{ fromJSON(needs.resolve.outputs.matrix) }}
env:
PREFLIGHT_VERSION: "1.21.0"
# sha256 of preflight-linux-amd64 from the 1.21.0 GitHub release.
# Red Hat publishes no checksum file, so the value is pinned here.
PREFLIGHT_SHA256: "5e653135503c72f8702bbe31d7643197d12937c68086879133dd6b9650a9a449"
steps:
- name: Verify the multi-arch image is on ghcr.io
env:
IMAGE_REF: ${{ matrix.ref }}
run: |
set -euo pipefail
docker buildx imagetools inspect "$IMAGE_REF" --raw > manifest.json
for arch in amd64 arm64; do
if ! jq -e --arg a "$arch" '.manifests[] | select(.platform.architecture == $a)' manifest.json > /dev/null; then
echo "::error::${IMAGE_REF} has no ${arch} manifest"
exit 1
fi
done
echo "Manifest list for ${IMAGE_REF}:"
jq -r '.manifests[] | "\(.platform.os)/\(.platform.architecture) \(.digest)"' manifest.json
- name: Install preflight
run: |
set -euo pipefail
curl -fsSL --proto '=https' --proto-redir '=https' -o preflight \
"https://github.com/redhat-openshift-ecosystem/openshift-preflight/releases/download/${PREFLIGHT_VERSION}/preflight-linux-amd64"
echo "${PREFLIGHT_SHA256} preflight" | sha256sum -c -
chmod +x preflight
./preflight --version
- name: Run preflight checks and submit to Red Hat
env:
IMAGE_REF: ${{ matrix.ref }}
PFLT_PYXIS_API_TOKEN: ${{ secrets.PYXIS_API_TOKEN }}
PFLT_CERTIFICATION_COMPONENT_ID: ${{ matrix.component_id }}
PFLT_ARTIFACTS: artifacts
PFLT_LOGFILE: artifacts/preflight.log
PFLT_LOGLEVEL: info
PFLT_JUNIT: "true"
run: |
set -euo pipefail
# No --platform: preflight walks the manifest list and submits every
# architecture in one run, grouped under one manifest-list digest.
# preflight does not create the PFLT_LOGFILE directory, and --submit
# fails if the log file is missing.
mkdir -p artifacts
./preflight check container "$IMAGE_REF" --submit
- name: Fail if any check did not pass
run: |
set -euo pipefail
shopt -s nullglob globstar
results=(artifacts/**/results.json)
if [[ ${#results[@]} -eq 0 ]]; then
echo "::error::preflight produced no results.json"
exit 1
fi
status=0
for f in "${results[@]}"; do
arch="$(basename "$(dirname "$f")")"
passed="$(jq -r '.passed' "$f")"
failed="$(jq -r '[.results.failed[]?.name] | join(", ")' "$f")"
echo "${arch}: passed=${passed} ${failed:+failed checks: ${failed}}"
[[ "$passed" == "true" ]] || status=1
done
exit $status
- name: Upload preflight artifacts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: redhat-preflight-${{ matrix.component }}-${{ needs.resolve.outputs.version }}
path: artifacts/
retention-days: 30
- name: Wait for Pyxis to mark both architectures certified
env:
TAG: ${{ matrix.tag }}
COMPONENT_ID: ${{ matrix.component_id }}
PFLT_PYXIS_API_TOKEN: ${{ secrets.PYXIS_API_TOKEN }}
run: |
set -euo pipefail
# Filter on the tag server-side so older versions are found past the first page.
url="https://catalog.redhat.com/api/containers/v1/projects/certification/id/${COMPONENT_ID}/images?filter=repositories.tags.name==${TAG}&page_size=100"
for attempt in $(seq 1 20); do
certified="$(curl -fsS --proto '=https' --proto-redir '=https' -H "X-API-KEY: ${PFLT_PYXIS_API_TOKEN}" "$url" \
| jq -r --arg t "$TAG" '[.data[] | select(.repositories[]?.tags[]?.name == $t) | select(.certified == true) | .architecture] | unique | join(",")')"
echo "attempt ${attempt}: certified architectures for ${TAG}: ${certified:-none}"
if [[ "$certified" == "amd64,arm64" ]]; then
echo "Both architectures certified. Auto-publish is enabled on the component, so the catalog updates on its own."
exit 0
fi
sleep 30
done
echo "::error::Pyxis has not marked both architectures certified after 10 minutes. Check https://connect.redhat.com/component/view/${COMPONENT_ID}/images"
exit 1
+112 -22
View File
@@ -23,8 +23,50 @@ concurrency:
cancel-in-progress: true
jobs:
freebsd_port_trigger:
name: "FreeBSD Port / Trigger"
runs-on: ubuntu-22.04
outputs:
run: ${{ steps.decide.outputs.run }}
version: ${{ steps.decide.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Decide whether the port job runs
id: decide
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: |
set -euo pipefail
run=false
case "$GITHUB_EVENT_NAME" in
push)
if [[ "$GITHUB_REF" == "refs/heads/main" ]]; then
run=true
elif [[ "$GITHUB_REF" == refs/tags/* && "$GITHUB_REF_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
# The port tracks stable releases only, so a canary or rc tag has nothing to submit.
run=true
echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
fi
;;
pull_request)
git fetch --depth=1 origin "$BASE_SHA"
if git diff --name-only "$BASE_SHA" HEAD | \
grep -qE '^(release_files/freebsd-port-.*\.sh|\.github/workflows/release\.yml)$'; then
run=true
fi
;;
esac
echo "run=$run" >> "$GITHUB_OUTPUT"
echo "FreeBSD port job runs: $run"
release_freebsd_port:
name: "FreeBSD Port / Build & Test"
needs: freebsd_port_trigger
if: needs.freebsd_port_trigger.outputs.run == 'true'
runs-on: ubuntu-22.04
steps:
- name: Checkout
@@ -33,18 +75,19 @@ jobs:
persist-credentials: false
- name: Generate FreeBSD port diff
run: bash -x release_files/freebsd-port-diff.sh
- name: Generate FreeBSD port issue body
run: bash -x release_files/freebsd-port-issue-body.sh
env:
TARGET_VERSION: ${{ needs.freebsd_port_trigger.outputs.version }}
run: bash -x release_files/freebsd-port-diff.sh "$TARGET_VERSION"
- name: Check if diff was generated
id: check_diff
run: |
if ls netbird-*.diff 1> /dev/null 2>&1; then
echo "diff_exists=true" >> $GITHUB_OUTPUT
shopt -s nullglob
diffs=(netbird-*.diff)
if [[ ${#diffs[@]} -gt 0 ]]; then
echo "diff_exists=true" >> "$GITHUB_OUTPUT"
else
echo "diff_exists=false" >> $GITHUB_OUTPUT
echo "diff_exists=false" >> "$GITHUB_OUTPUT"
echo "No diff file generated (port may already be up to date)"
fi
@@ -52,10 +95,18 @@ jobs:
if: steps.check_diff.outputs.diff_exists == 'true'
id: version
run: |
VERSION=$(ls netbird-*.diff | sed 's/netbird-\(.*\)\.diff/\1/')
echo "version=$VERSION" >> $GITHUB_OUTPUT
diffs=(netbird-*.diff)
VERSION="${diffs[0]#netbird-}"
VERSION="${VERSION%.diff}"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Generated files for version: $VERSION"
cat netbird-*.diff
cat "${diffs[0]}"
- name: Generate FreeBSD port issue body
if: steps.check_diff.outputs.diff_exists == 'true'
env:
TARGET_VERSION: ${{ steps.version.outputs.version }}
run: bash -x release_files/freebsd-port-issue-body.sh "" "$TARGET_VERSION"
- name: Read Go version from go.mod
id: goversion
@@ -69,7 +120,7 @@ jobs:
with:
usesh: true
copyback: false
release: "15.0"
release: "15.1"
envs: "GO_VERSION"
prepare: |
# Install required packages
@@ -191,6 +242,17 @@ jobs:
# requires a changelog. Generated, not committed (see .gitignore).
# chglog is a go.mod tool directive, so go.sum pins it and its deps.
run: bash release_files/rpm-changelog.sh
- name: Fill the RPM ISA provide version
# nfpm cannot emit rpmbuild's ISA provide and GoReleaser cannot template it.
run: bash release_files/rpm-provides.sh
- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '22'
- name: Install proxy web dependencies for license collection
# release_files/collect-licenses.sh -w reads the proxy UI's license terms from node_modules.
working-directory: proxy/web
run: npm ci --ignore-scripts
- name: Set up QEMU
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 #v4.1.0
- name: Set up Docker Buildx
@@ -230,14 +292,18 @@ jobs:
uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2
with:
version: ${{ env.GORELEASER_VER }}
args: release --clean ${{ env.flags }}
args: release --config .goreleaser.generated.yaml --clean ${{ env.flags }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
UPLOAD_DEBIAN_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }}
UPLOAD_YUM_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }}
GPG_RPM_KEY_FILE: ${{ env.GPG_RPM_KEY_FILE }}
NFPM_NETBIRD_RPM_PASSPHRASE: ${{ secrets.GPG_RPM_PASSPHRASE }}
# One per nfpm id: GoReleaser looks the passphrase up as NFPM_<ID>_PASSPHRASE.
NFPM_NETBIRD_RPM_AMD64_PASSPHRASE: ${{ secrets.GPG_RPM_PASSPHRASE }}
NFPM_NETBIRD_RPM_ARM64_PASSPHRASE: ${{ secrets.GPG_RPM_PASSPHRASE }}
NFPM_NETBIRD_RPM_ARM_PASSPHRASE: ${{ secrets.GPG_RPM_PASSPHRASE }}
NFPM_NETBIRD_RPM_386_PASSPHRASE: ${{ secrets.GPG_RPM_PASSPHRASE }}
SKIP_PUBLISH: ${{ env.SKIP_PUBLISH }}
SKIP_DOCKER_PUSH: ${{ env.SKIP_DOCKER_PUSH }}
- name: Verify RPM signatures
@@ -294,10 +360,12 @@ jobs:
tag_and_push() {
local src="$1" img_name tag dst variant=""
img_name="${src%%:*}"
# Client variants share a repository, so keep their tag suffixes.
# Variants share a repository with their default image, so keep
# their tag suffixes. Order matters: the first matching pattern wins.
case "$src" in
*-rootless-ubi-amd64) variant="-rootless-ubi" ;;
*-rootless-amd64) variant="-rootless" ;;
*-ubi-amd64) variant="-ubi" ;;
esac
for tag in $(resolve_tags); do
dst="${img_name}:${tag}${variant}"
@@ -346,7 +414,11 @@ jobs:
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1
with:
name: linux-packages
path: dist/netbird_linux**
path: |
dist/netbird_linux**
dist/netbird-pkcs11_linux**
dist/netbird-deb-32bit_linux**
dist/netbird-rpm-*_linux**
retention-days: 7
- name: upload windows packages
id: upload_windows_packages
@@ -363,6 +435,24 @@ jobs:
path: dist/netbird_darwin**
retention-days: 7
# Certify the UBI images in the Red Hat Ecosystem Catalog on stable tags.
# See redhat-certify.yml, which can also be run by hand for any released version.
redhat_certification:
name: "Red Hat"
needs: release
if: |
github.repository == 'netbirdio/netbird' &&
startsWith(github.ref, 'refs/tags/v') &&
!contains(github.ref_name, '-')
permissions:
contents: read
uses: ./.github/workflows/redhat-certify.yml
with:
component: all
version: ${{ github.ref_name }}
secrets:
PYXIS_API_TOKEN: ${{ secrets.PYXIS_API_TOKEN }}
release_ui:
runs-on: ubuntu-latest
outputs:
@@ -417,12 +507,12 @@ jobs:
run: git --no-pager diff --exit-code
- name: Set up Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v7
with:
node-version: '22'
- name: Set up pnpm
uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
with:
version: 11
@@ -554,12 +644,12 @@ jobs:
run: git --no-pager diff --exit-code
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '22'
- name: Set up pnpm
uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
with:
version: 11
@@ -651,11 +741,11 @@ jobs:
- name: check git status
run: git --no-pager diff --exit-code
- name: Set up Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v7
with:
node-version: '22'
- name: Set up pnpm
uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
with:
version: 11
- name: Install wails3 CLI
@@ -774,7 +864,7 @@ jobs:
run: 7z x -o"${{ github.workspace }}/NSIS_Plugins" "${{ github.workspace }}/ShellExecAsUser_amd64-Unicode.7z"
- name: Set up Go for wails3 CLI
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version-file: "go.mod"
cache: false
+53
View File
@@ -0,0 +1,53 @@
name: Reverse Proxy E2E
on:
pull_request:
paths:
- '.github/workflows/reverse-proxy-e2e.yml'
- '**/*.go'
- 'e2e/**'
- 'shared/management/**'
- 'combined/Dockerfile*'
- 'proxy/Dockerfile*'
- '.dockerignore'
- 'go.mod'
- 'go.sum'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
reverse-proxy:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Install Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
- name: Set up Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
- name: Cache Docker layers
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: /tmp/.reverse-proxy-buildx-cache
key: ${{ runner.os }}-reverse-proxy-e2e-${{ hashFiles('go.sum', 'combined/Dockerfile.multistage', 'proxy/Dockerfile.multistage') }}
restore-keys: |
${{ runner.os }}-reverse-proxy-e2e-
- name: Run reverse-proxy E2E
env:
NB_E2E_BUILDX_CACHE: /tmp/.reverse-proxy-buildx-cache
run: go test -tags e2e -timeout 25m -v ./e2e/reverseproxy/...
+46
View File
@@ -0,0 +1,46 @@
name: Test Homebrew cask
on:
pull_request:
paths:
- "client/ui/netbird-ui.rb.tmpl"
- ".github/scripts/test-homebrew-cask.sh"
- ".github/workflows/test-homebrew-cask.yml"
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.head_ref || github.actor_id }}
cancel-in-progress: true
jobs:
install-uninstall:
runs-on: macos-latest
timeout-minutes: 20
steps:
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Clone the Homebrew tap
run: git clone https://github.com/netbirdio/homebrew-tap.git .homebrew-cask-tap
- name: Update Homebrew and install gomplate
# The runner image disables auto-update; the cask steps DSL needs Homebrew 6.0.20 or newer.
run: |
brew update
brew install gomplate
- name: Install and uninstall the cask
run: .github/scripts/test-homebrew-cask.sh
- name: Upload logs
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1
with:
name: homebrew-cask-results
path: ${{ runner.temp }}/homebrew-cask/results
if-no-files-found: ignore
@@ -258,6 +258,18 @@ jobs:
with:
persist-credentials: false
- name: Verify enterprise Traefik tag validation
run: bash infrastructure_files/tests/test-getting-started-enterprise.sh
- name: Verify community Traefik image validation
run: bash infrastructure_files/tests/test-getting-started.sh
- name: Verify community Compose network scoping
run: bash infrastructure_files/tests/test-getting-started-networks.sh
- name: Verify migration Compose network scoping
run: bash infrastructure_files/tests/test-getting-started-networks.sh --migration
- name: Verify fresh-install session cookie key hardening
run: |
grep -Fxq ' SESSION_COOKIE_ENCRYPTION_KEY=$(openssl rand -base64 32)' infrastructure_files/getting-started.sh
+4 -3
View File
@@ -32,11 +32,12 @@ jobs:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v7
with:
node-version: "22"
# English (en) is the source of truth for translation keys; every other
# locale declared in _index.json must carry the exact same key set.
# English (en) is the source of truth for translation keys. Locales declared
# in _index.json fail on orphaned keys or placeholder mismatches; missing
# keys only warn, since they fall back to English at runtime.
- name: Check translation key parity
run: node client/ui/i18n/check-translations.mjs