Skip to content

Commit b569a04

Browse files
Merge branch 'main' into feat/auto-upgrade
2 parents 5ba5b40 + 86a00ab commit b569a04

File tree

120 files changed

+2003
-1178
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

120 files changed

+2003
-1178
lines changed

.github/pull_request_template.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@
1212
- [ ] Is a feature enhancement
1313
- [ ] It is a refactor
1414
- [ ] Created tests that fail without the change (if possible)
15-
- [ ] Extended the README / documentation, if necessary
1615

1716
> By submitting this pull request, you confirm that you have read and agree to the terms of the [Contributor License Agreement](https://github.com/netbirdio/netbird/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT.md).
17+
18+
## Documentation
19+
Select exactly one:
20+
21+
- [ ] I added/updated documentation for this change
22+
- [ ] Documentation is **not needed** for this change (explain why)
23+
24+
### Docs PR URL (required if "docs added" is checked)
25+
Paste the PR link from https://github.com/netbirdio/docs here:
26+
27+
https://github.com/netbirdio/docs/pull/__

.github/workflows/docs-ack.yml

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
name: Docs Acknowledgement
2+
3+
on:
4+
pull_request:
5+
types: [opened, edited, synchronize]
6+
7+
permissions:
8+
contents: read
9+
pull-requests: read
10+
11+
jobs:
12+
docs-ack:
13+
name: Require docs PR URL or explicit "not needed"
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- name: Read PR body
18+
id: body
19+
run: |
20+
BODY=$(jq -r '.pull_request.body // ""' "$GITHUB_EVENT_PATH")
21+
echo "body<<EOF" >> $GITHUB_OUTPUT
22+
echo "$BODY" >> $GITHUB_OUTPUT
23+
echo "EOF" >> $GITHUB_OUTPUT
24+
25+
- name: Validate checkbox selection
26+
id: validate
27+
run: |
28+
body='${{ steps.body.outputs.body }}'
29+
30+
added_checked=$(printf "%s" "$body" | grep -E '^- \[x\] I added/updated documentation' -i | wc -l | tr -d ' ')
31+
noneed_checked=$(printf "%s" "$body" | grep -E '^- \[x\] Documentation is \*\*not needed\*\*' -i | wc -l | tr -d ' ')
32+
33+
if [ "$added_checked" -eq 1 ] && [ "$noneed_checked" -eq 1 ]; then
34+
echo "::error::Choose exactly one: either 'docs added' OR 'not needed'."
35+
exit 1
36+
fi
37+
38+
if [ "$added_checked" -eq 0 ] && [ "$noneed_checked" -eq 0 ]; then
39+
echo "::error::You must check exactly one docs option in the PR template."
40+
exit 1
41+
fi
42+
43+
if [ "$added_checked" -eq 1 ]; then
44+
echo "mode=added" >> $GITHUB_OUTPUT
45+
else
46+
echo "mode=noneed" >> $GITHUB_OUTPUT
47+
fi
48+
49+
- name: Extract docs PR URL (when 'docs added')
50+
if: steps.validate.outputs.mode == 'added'
51+
id: extract
52+
run: |
53+
body='${{ steps.body.outputs.body }}'
54+
55+
# Strictly require HTTPS and that it's a PR in netbirdio/docs
56+
# Examples accepted:
57+
# https://github.com/netbirdio/docs/pull/1234
58+
url=$(printf "%s" "$body" | grep -Eo 'https://github\.com/netbirdio/docs/pull/[0-9]+' | head -n1 || true)
59+
60+
if [ -z "$url" ]; then
61+
echo "::error::You checked 'docs added' but didn't include a valid HTTPS PR link to netbirdio/docs (e.g., https://github.com/netbirdio/docs/pull/1234)."
62+
exit 1
63+
fi
64+
65+
pr_number=$(echo "$url" | sed -E 's#.*/pull/([0-9]+)$#\1#')
66+
echo "url=$url" >> $GITHUB_OUTPUT
67+
echo "pr_number=$pr_number" >> $GITHUB_OUTPUT
68+
69+
- name: Verify docs PR exists (and is open or merged)
70+
if: steps.validate.outputs.mode == 'added'
71+
uses: actions/github-script@v7
72+
id: verify
73+
with:
74+
pr_number: ${{ steps.extract.outputs.pr_number }}
75+
script: |
76+
const prNumber = parseInt(core.getInput('pr_number'), 10);
77+
const { data } = await github.rest.pulls.get({
78+
owner: 'netbirdio',
79+
repo: 'docs',
80+
pull_number: prNumber
81+
});
82+
83+
// Allow open or merged PRs
84+
const ok = data.state === 'open' || data.merged === true;
85+
core.setOutput('state', data.state);
86+
core.setOutput('merged', String(!!data.merged));
87+
if (!ok) {
88+
core.setFailed(`Docs PR #${prNumber} exists but is neither open nor merged (state=${data.state}, merged=${data.merged}).`);
89+
}
90+
result-encoding: string
91+
github-token: ${{ secrets.GITHUB_TOKEN }}
92+
93+
- name: All good
94+
run: echo "Documentation requirement satisfied ✅"

.github/workflows/forum.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name: Post release topic on Discourse
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
jobs:
8+
post:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: roots/discourse-topic-github-release-action@main
12+
with:
13+
discourse-api-key: ${{ secrets.DISCOURSE_RELEASES_API_KEY }}
14+
discourse-base-url: https://forum.netbird.io
15+
discourse-author-username: NetBird
16+
discourse-category: 17
17+
discourse-tags:
18+
releases

.github/workflows/golang-test-freebsd.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ jobs:
2525
release: "14.2"
2626
prepare: |
2727
pkg install -y curl pkgconf xorg
28-
LATEST_VERSION=$(curl -s https://go.dev/VERSION?m=text|head -n 1)
29-
GO_TARBALL="$LATEST_VERSION.freebsd-amd64.tar.gz"
28+
GO_TARBALL="go1.23.12.freebsd-amd64.tar.gz"
3029
GO_URL="https://go.dev/dl/$GO_TARBALL"
3130
curl -vLO "$GO_URL"
3231
tar -C /usr/local -vxzf "$GO_TARBALL"

.github/workflows/release.yml

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
pull_request:
1010

1111
env:
12-
SIGN_PIPE_VER: "v0.0.21"
12+
SIGN_PIPE_VER: "v0.0.22"
1313
GORELEASER_VER: "v2.3.2"
1414
PRODUCT_NAME: "NetBird"
1515
COPYRIGHT: "NetBird GmbH"
@@ -79,6 +79,8 @@ jobs:
7979
run: go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@233067e
8080
- name: Generate windows syso amd64
8181
run: goversioninfo -icon client/ui/assets/netbird.ico -manifest client/manifest.xml -product-name ${{ env.PRODUCT_NAME }} -copyright "${{ env.COPYRIGHT }}" -ver-major ${{ steps.semver_parser.outputs.major }} -ver-minor ${{ steps.semver_parser.outputs.minor }} -ver-patch ${{ steps.semver_parser.outputs.patch }} -ver-build 0 -file-version ${{ steps.semver_parser.outputs.fullversion }}.0 -product-version ${{ steps.semver_parser.outputs.fullversion }}.0 -o client/resources_windows_amd64.syso
82+
- name: Generate windows syso arm64
83+
run: goversioninfo -arm -64 -icon client/ui/assets/netbird.ico -manifest client/manifest.xml -product-name ${{ env.PRODUCT_NAME }} -copyright "${{ env.COPYRIGHT }}" -ver-major ${{ steps.semver_parser.outputs.major }} -ver-minor ${{ steps.semver_parser.outputs.minor }} -ver-patch ${{ steps.semver_parser.outputs.patch }} -ver-build 0 -file-version ${{ steps.semver_parser.outputs.fullversion }}.0 -product-version ${{ steps.semver_parser.outputs.fullversion }}.0 -o client/resources_windows_arm64.syso
8284
- name: Run GoReleaser
8385
uses: goreleaser/goreleaser-action@v4
8486
with:
@@ -154,10 +156,20 @@ jobs:
154156

155157
- name: Install dependencies
156158
run: sudo apt update && sudo apt install -y -q libappindicator3-dev gir1.2-appindicator3-0.1 libxxf86vm-dev gcc-mingw-w64-x86-64
159+
160+
- name: Install LLVM-MinGW for ARM64 cross-compilation
161+
run: |
162+
cd /tmp
163+
wget -q https://github.com/mstorsjo/llvm-mingw/releases/download/20250709/llvm-mingw-20250709-ucrt-ubuntu-22.04-x86_64.tar.xz
164+
echo "60cafae6474c7411174cff1d4ba21a8e46cadbaeb05a1bace306add301628337 llvm-mingw-20250709-ucrt-ubuntu-22.04-x86_64.tar.xz" | sha256sum -c
165+
tar -xf llvm-mingw-20250709-ucrt-ubuntu-22.04-x86_64.tar.xz
166+
echo "/tmp/llvm-mingw-20250709-ucrt-ubuntu-22.04-x86_64/bin" >> $GITHUB_PATH
157167
- name: Install goversioninfo
158168
run: go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@233067e
159169
- name: Generate windows syso amd64
160170
run: goversioninfo -64 -icon client/ui/assets/netbird.ico -manifest client/ui/manifest.xml -product-name ${{ env.PRODUCT_NAME }}-"UI" -copyright "${{ env.COPYRIGHT }}" -ver-major ${{ steps.semver_parser.outputs.major }} -ver-minor ${{ steps.semver_parser.outputs.minor }} -ver-patch ${{ steps.semver_parser.outputs.patch }} -ver-build 0 -file-version ${{ steps.semver_parser.outputs.fullversion }}.0 -product-version ${{ steps.semver_parser.outputs.fullversion }}.0 -o client/ui/resources_windows_amd64.syso
171+
- name: Generate windows syso arm64
172+
run: goversioninfo -arm -64 -icon client/ui/assets/netbird.ico -manifest client/ui/manifest.xml -product-name ${{ env.PRODUCT_NAME }}-"UI" -copyright "${{ env.COPYRIGHT }}" -ver-major ${{ steps.semver_parser.outputs.major }} -ver-minor ${{ steps.semver_parser.outputs.minor }} -ver-patch ${{ steps.semver_parser.outputs.patch }} -ver-build 0 -file-version ${{ steps.semver_parser.outputs.fullversion }}.0 -product-version ${{ steps.semver_parser.outputs.fullversion }}.0 -o client/ui/resources_windows_arm64.syso
161173

162174
- name: Run GoReleaser
163175
uses: goreleaser/goreleaser-action@v4
@@ -231,17 +243,3 @@ jobs:
231243
ref: ${{ env.SIGN_PIPE_VER }}
232244
token: ${{ secrets.SIGN_GITHUB_TOKEN }}
233245
inputs: '{ "tag": "${{ github.ref }}", "skipRelease": false }'
234-
235-
post_on_forum:
236-
runs-on: ubuntu-latest
237-
continue-on-error: true
238-
needs: [trigger_signer]
239-
steps:
240-
- uses: Codixer/[email protected]
241-
with:
242-
discourse-api-key: ${{ secrets.DISCOURSE_RELEASES_API_KEY }}
243-
discourse-base-url: https://forum.netbird.io
244-
discourse-author-username: NetBird
245-
discourse-category: 17
246-
discourse-tags:
247-
releases

.goreleaser.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ builds:
1616
- arm64
1717
- 386
1818
ignore:
19-
- goos: windows
20-
goarch: arm64
2119
- goos: windows
2220
goarch: arm
2321
- goos: windows

.goreleaser_ui.yaml

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ builds:
1515
- -s -w -X github.com/netbirdio/netbird/version.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser
1616
mod_timestamp: "{{ .CommitTimestamp }}"
1717

18-
- id: netbird-ui-windows
18+
- id: netbird-ui-windows-amd64
1919
dir: client/ui
2020
binary: netbird-ui
2121
env:
@@ -30,6 +30,22 @@ builds:
3030
- -H windowsgui
3131
mod_timestamp: "{{ .CommitTimestamp }}"
3232

33+
- id: netbird-ui-windows-arm64
34+
dir: client/ui
35+
binary: netbird-ui
36+
env:
37+
- CGO_ENABLED=1
38+
- CC=aarch64-w64-mingw32-clang
39+
- CXX=aarch64-w64-mingw32-clang++
40+
goos:
41+
- windows
42+
goarch:
43+
- arm64
44+
ldflags:
45+
- -s -w -X github.com/netbirdio/netbird/version.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser
46+
- -H windowsgui
47+
mod_timestamp: "{{ .CommitTimestamp }}"
48+
3349
archives:
3450
- id: linux-arch
3551
name_template: "{{ .ProjectName }}-linux_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
@@ -38,7 +54,8 @@ archives:
3854
- id: windows-arch
3955
name_template: "{{ .ProjectName }}-windows_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
4056
builds:
41-
- netbird-ui-windows
57+
- netbird-ui-windows-amd64
58+
- netbird-ui-windows-arm64
4259

4360
nfpms:
4461
- maintainer: Netbird <[email protected]>

client/android/client.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package android
44

55
import (
66
"context"
7+
"slices"
78
"sync"
89

910
log "github.com/sirupsen/logrus"
@@ -112,7 +113,7 @@ func (c *Client) Run(urlOpener URLOpener, dns *DNSList, dnsReadyListener DnsRead
112113
// todo do not throw error in case of cancelled context
113114
ctx = internal.CtxInitState(ctx)
114115
c.connectClient = internal.NewConnectClient(ctx, cfg, c.recorder)
115-
return c.connectClient.RunOnAndroid(c.tunAdapter, c.iFaceDiscover, c.networkChangeListener, dns.items, dnsReadyListener)
116+
return c.connectClient.RunOnAndroid(c.tunAdapter, c.iFaceDiscover, c.networkChangeListener, slices.Clone(dns.items), dnsReadyListener)
116117
}
117118

118119
// RunWithoutLogin we apply this type of run function when the backed has been started without UI (i.e. after reboot).
@@ -138,7 +139,7 @@ func (c *Client) RunWithoutLogin(dns *DNSList, dnsReadyListener DnsReadyListener
138139
// todo do not throw error in case of cancelled context
139140
ctx = internal.CtxInitState(ctx)
140141
c.connectClient = internal.NewConnectClient(ctx, cfg, c.recorder)
141-
return c.connectClient.RunOnAndroid(c.tunAdapter, c.iFaceDiscover, c.networkChangeListener, dns.items, dnsReadyListener)
142+
return c.connectClient.RunOnAndroid(c.tunAdapter, c.iFaceDiscover, c.networkChangeListener, slices.Clone(dns.items), dnsReadyListener)
142143
}
143144

144145
// Stop the internal client and free the resources
@@ -235,7 +236,7 @@ func (c *Client) OnUpdatedHostDNS(list *DNSList) error {
235236
return err
236237
}
237238

238-
dnsServer.OnUpdatedHostDNSServer(list.items)
239+
dnsServer.OnUpdatedHostDNSServer(slices.Clone(list.items))
239240
return nil
240241
}
241242

client/android/dns_list.go

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,34 @@
11
package android
22

3-
import "fmt"
3+
import (
4+
"fmt"
5+
"net/netip"
46

5-
// DNSList is a wrapper of []string
7+
"github.com/netbirdio/netbird/client/internal/dns"
8+
)
9+
10+
// DNSList is a wrapper of []netip.AddrPort with default DNS port
611
type DNSList struct {
7-
items []string
12+
items []netip.AddrPort
813
}
914

10-
// Add new DNS address to the collection
11-
func (array *DNSList) Add(s string) {
12-
array.items = append(array.items, s)
15+
// Add new DNS address to the collection, returns error if invalid
16+
func (array *DNSList) Add(s string) error {
17+
addr, err := netip.ParseAddr(s)
18+
if err != nil {
19+
return fmt.Errorf("invalid DNS address: %s", s)
20+
}
21+
addrPort := netip.AddrPortFrom(addr.Unmap(), dns.DefaultPort)
22+
array.items = append(array.items, addrPort)
23+
return nil
1324
}
1425

15-
// Get return an element of the collection
26+
// Get return an element of the collection as string
1627
func (array *DNSList) Get(i int) (string, error) {
1728
if i >= len(array.items) || i < 0 {
1829
return "", fmt.Errorf("out of range")
1930
}
20-
return array.items[i], nil
31+
return array.items[i].Addr().String(), nil
2132
}
2233

2334
// Size return with the size of the collection

client/android/dns_list_test.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,30 @@ package android
33
import "testing"
44

55
func TestDNSList_Get(t *testing.T) {
6-
l := DNSList{
7-
items: make([]string, 1),
6+
l := DNSList{}
7+
8+
// Add a valid DNS address
9+
err := l.Add("8.8.8.8")
10+
if err != nil {
11+
t.Errorf("unexpected error: %s", err)
812
}
913

10-
_, err := l.Get(0)
14+
// Test getting valid index
15+
addr, err := l.Get(0)
1116
if err != nil {
1217
t.Errorf("invalid error: %s", err)
1318
}
19+
if addr != "8.8.8.8" {
20+
t.Errorf("expected 8.8.8.8, got %s", addr)
21+
}
1422

23+
// Test negative index
1524
_, err = l.Get(-1)
1625
if err == nil {
1726
t.Errorf("expected error but got nil")
1827
}
1928

29+
// Test out of bounds index
2030
_, err = l.Get(1)
2131
if err == nil {
2232
t.Errorf("expected error but got nil")

0 commit comments

Comments
 (0)