Skip to content

Commit f2446bf

Browse files
committed
feat: embed wireguard-go as a library and manage tunnels directly
Replace external wireguard-go/wg binaries and the Windows WireGuard MSI with wireguard-go embedded as a Go library. The helper now creates TUN devices, configures peers via wgctrl, and manages routes through native OS APIs (BSD routing sockets, netlink, winipcfg) instead of shelling out. Migrate key handling from custom crypto wrappers to wgtypes.Key with automatic legacy key migration. Add WireGuard public key validation at enrollment time, an iputil package for CIDR parsing, and cross- platform post-install smoke tests. Remove wireguard-go/wireguard-tools from all package dependencies (Homebrew, nix, deb).
1 parent 6f35fc7 commit f2446bf

76 files changed

Lines changed: 2780 additions & 817 deletions

Some content is hidden

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

.github/workflows/controlplane.yaml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
runs-on: ubuntu-latest
3333
steps:
3434
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6
35-
- uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # ratchet:jdx/mise-action@v3
35+
- uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # ratchet:jdx/mise-action@v4
3636
with:
3737
cache: false
3838
- run: mise run ${{ matrix.mise_task }}
@@ -44,7 +44,7 @@ jobs:
4444
runs-on: ubuntu-22.04
4545
steps:
4646
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6
47-
- uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # ratchet:jdx/mise-action@v3
47+
- uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # ratchet:jdx/mise-action@v4
4848

4949
- name: "Build controlplane"
5050
run: |
@@ -75,7 +75,6 @@ jobs:
7575
runs-on: ubuntu-22.04
7676
steps:
7777
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6
78-
7978
- name: Get Go version from go.mod
8079
id: go-version
8180
run: echo "version=$(awk '/^go /{print $2}' go.mod)" >> "$GITHUB_OUTPUT"

.github/workflows/naisdevice.yaml

Lines changed: 81 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: Naisdevice
22

33
on:
44
pull_request:
5-
types: [opened, reopened, synchronize]
5+
types: [opened, reopened, synchronize, labeled]
66
push:
77
branches: [main]
88
paths:
@@ -30,8 +30,9 @@ on:
3030
- "pkg/pb/**"
3131

3232
env:
33+
PRE_RELEASE: ${{ github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'pre-release') && 'true' || 'false' }}
3334
# some mise tasks use this to determine how they package/sign stuff.
34-
RELEASE: ${{ (github.ref == 'refs/heads/main' && github.actor != 'dependabot[bot]') && 'true' || 'false' }}
35+
RELEASE: ${{ ((github.ref == 'refs/heads/main' && github.actor != 'dependabot[bot]') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'pre-release'))) && 'true' || 'false' }}
3536

3637
concurrency:
3738
group: ${{ github.ref }}
@@ -50,14 +51,18 @@ jobs:
5051
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6
5152
with:
5253
fetch-depth: 0
53-
- uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # ratchet:jdx/mise-action@v3
54+
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
55+
- uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # ratchet:jdx/mise-action@v4
5456
- id: generate
5557
run: mise run ci:release-info
5658
env:
5759
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
60+
PRE_RELEASE: ${{ env.PRE_RELEASE }}
61+
PR_NUMBER: ${{ github.event.pull_request.number }}
5862
outputs:
5963
version: ${{ steps.generate.outputs.version }}
6064
changelog: ${{ steps.generate.outputs.changelog }}
65+
pre_release: ${{ env.PRE_RELEASE }}
6166

6267
checks:
6368
strategy:
@@ -76,7 +81,7 @@ jobs:
7681
contents: read
7782
steps:
7883
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6
79-
- uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # ratchet:jdx/mise-action@v3
84+
- uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # ratchet:jdx/mise-action@v4
8085
- run: mise run ${{ matrix.mise_task }}
8186

8287
builds:
@@ -109,7 +114,7 @@ jobs:
109114
OUTFILE: ./release_artifacts/naisdevice${{ matrix.gotags == 'tenant' && '-tenant' || '' }}_${{ matrix.platform.os }}_${{ matrix.arch }}.${{ matrix.platform.ext }}
110115
steps:
111116
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6
112-
- uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # ratchet:jdx/mise-action@v3
117+
- uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # ratchet:jdx/mise-action@v4
113118
- if: matrix.platform.os == 'windows'
114119
run: sudo apt-get update && sudo apt-get install --yes nsis osslsigncode
115120
- if: matrix.platform.os == 'macos'
@@ -129,34 +134,83 @@ jobs:
129134
run: |
130135
mkdir -p "$(dirname $OUTFILE)"
131136
mise run "package:${{ matrix.platform.os }}"
132-
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # ratchet:actions/upload-artifact@v5
137+
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # ratchet:actions/upload-artifact@v7
133138
with:
134139
name: installer-${{ matrix.platform.os }}-${{ matrix.arch }}-${{ matrix.gotags || 'nav' }}
135140
path: ${{ env.OUTFILE }}
136141

142+
smoke-tests:
143+
name: smoke test ${{ matrix.artifact }}
144+
needs: [builds]
145+
strategy:
146+
fail-fast: false
147+
matrix:
148+
include:
149+
- os: macos
150+
runner: macos-latest
151+
artifact: installer-macos-arm64-nav
152+
installer_glob: "*.pkg"
153+
- os: macos
154+
runner: macos-latest
155+
artifact: installer-macos-arm64-tenant
156+
installer_glob: "*.pkg"
157+
- os: linux
158+
runner: ubuntu-latest
159+
artifact: installer-linux-amd64-nav
160+
installer_glob: "*.deb"
161+
- os: linux
162+
runner: ubuntu-latest
163+
artifact: installer-linux-amd64-tenant
164+
installer_glob: "*.deb"
165+
- os: windows
166+
runner: windows-latest
167+
artifact: installer-windows-amd64-nav
168+
installer_glob: "*.exe"
169+
- os: windows
170+
runner: windows-latest
171+
artifact: installer-windows-amd64-tenant
172+
installer_glob: "*.exe"
173+
runs-on: ${{ matrix.runner }}
174+
steps:
175+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6
176+
- uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # ratchet:jdx/mise-action@v4
177+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # ratchet:actions/download-artifact@v8
178+
with:
179+
name: ${{ matrix.artifact }}
180+
path: ./downloaded-artifact/
181+
- name: run smoke test
182+
shell: bash
183+
run: mise run smoke-test:${{ matrix.os }} ./downloaded-artifact/${{ matrix.installer_glob }}
184+
137185
# Used by GitHub to determine if all checks/builds have passed
138186
branch-protection-checkpoint:
139-
needs: [checks, builds]
187+
needs: [checks, builds, smoke-tests]
140188
if: ${{ always() }}
141189
runs-on: ubuntu-latest
142190
steps:
143-
- if: ${{ needs.checks.result != 'success' || needs.builds.result != 'success' }}
191+
- if: ${{ needs.checks.result != 'success' || needs.builds.result != 'success' || needs.smoke-tests.result != 'success' }}
144192
run: exit 1
145-
- run: echo "All checks and builds passed."
193+
- run: echo "All checks, builds, and smoke tests passed."
146194

147195
release-github:
148-
if: github.ref == 'refs/heads/main' && github.actor != 'dependabot[bot]' && needs.release-info.outputs.changelog != '' && needs.release-info.outputs.version != ''
196+
if: >-
197+
needs.release-info.outputs.changelog != '' && needs.release-info.outputs.version != '' &&
198+
(
199+
(github.ref == 'refs/heads/main' && github.actor != 'dependabot[bot]') ||
200+
needs.release-info.outputs.pre_release == 'true'
201+
)
149202
needs: [release-info, branch-protection-checkpoint]
150203
runs-on: ubuntu-latest
151204
permissions:
152205
contents: write
206+
env:
207+
RELEASE_TARGET_COMMIT: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
153208
steps:
154209
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6
155210
with:
156-
fetch-depth: 0
157-
- uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # ratchet:jdx/mise-action@v3
158-
- run: git tag ${{ needs.release-info.outputs.version }}
159-
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # ratchet:actions/download-artifact@v6
211+
ref: ${{ env.RELEASE_TARGET_COMMIT }}
212+
- uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # ratchet:jdx/mise-action@v4
213+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # ratchet:actions/download-artifact@v8
160214
with:
161215
merge-multiple: true
162216
path: release_artifacts
@@ -165,15 +219,18 @@ jobs:
165219
id: release
166220
with:
167221
tag_name: ${{ needs.release-info.outputs.version }}
222+
target_commitish: ${{ env.RELEASE_TARGET_COMMIT }}
168223
body: ${{ needs.release-info.outputs.changelog }}
169-
prerelease: false
224+
prerelease: ${{ needs.release-info.outputs.pre_release == 'true' }}
170225
files: ./release_artifacts/*
171226
env:
172227
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
173-
- env:
228+
- if: needs.release-info.outputs.pre_release != 'true'
229+
env:
174230
VERSION: ${{ needs.release-info.outputs.version }}
175231
run: mise run ci:prepare-template-vars ./release_artifacts/checksums.txt -v > template.vars
176-
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # ratchet:actions/upload-artifact@v5
232+
- if: needs.release-info.outputs.pre_release != 'true'
233+
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # ratchet:actions/upload-artifact@v7
177234
with:
178235
name: template-vars
179236
path: ./template.vars
@@ -182,12 +239,13 @@ jobs:
182239
echo "A new release is available over at https://github.com/${{ github.repository }}/releases/tag/${{ needs.release-info.outputs.version }}." >> $GITHUB_STEP_SUMMARY
183240
184241
release-gar:
242+
if: needs.release-info.outputs.pre_release != 'true'
185243
strategy:
186244
fail-fast: false
187245
matrix:
188246
arch: [arm64, amd64]
189247
suffix: [nav, tenant]
190-
needs: [release-github]
248+
needs: [release-info, release-github]
191249
runs-on: ubuntu-latest
192250
permissions:
193251
contents: read
@@ -201,15 +259,16 @@ jobs:
201259
service_account: gh-naisdevice@nais-io.iam.gserviceaccount.com
202260
token_format: access_token
203261
- uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # ratchet:google-github-actions/setup-gcloud@v3
204-
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # ratchet:actions/download-artifact@v6
262+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # ratchet:actions/download-artifact@v8
205263
with:
206264
name: installer-linux-${{ matrix.arch }}-${{ matrix.suffix }}
207265
path: ./downloaded-artifact/
208266
- run: |
209267
gcloud artifacts apt upload nais-ppa --project nais-io --quiet --location europe-north1 --source ./downloaded-artifact/*
210268
211269
release-external-repos:
212-
needs: [release-github]
270+
if: needs.release-info.outputs.pre_release != 'true'
271+
needs: [release-info, release-github]
213272
strategy:
214273
fail-fast: false
215274
matrix:
@@ -234,8 +293,8 @@ jobs:
234293
private-key: ${{ secrets.NAIS_APP_PRIVATE_KEY }}
235294
app-id: ${{ secrets.NAIS_APP_ID }}
236295
repo: ${{ matrix.target.repo }}
237-
- uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # ratchet:jdx/mise-action@v3
238-
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # ratchet:actions/download-artifact@v6
296+
- uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # ratchet:jdx/mise-action@v4
297+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # ratchet:actions/download-artifact@v8
239298
with:
240299
name: template-vars
241300
- name: update ${{ matrix.target.repo }}

.github/workflows/templates/naisdevice-tenant.rb

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,6 @@
55
desc "naisdevice is a mechanism enabling developers to connect to internal resources in a secure and friendly manner."
66
homepage "https://docs.nais.io/operate/naisdevice/how-to/install/"
77

8-
depends_on formula: [
9-
"wireguard-go",
10-
"wireguard-tools",
11-
]
12-
138
if Hardware::CPU.intel?
149
url "https://github.com/nais/device/releases/download/#{version}/$NAISDEVICE_TENANT_MACOS_AMD64_FILENAME", verified: "github.com/nais/device/"
1510
sha256 "$NAISDEVICE_TENANT_MACOS_AMD64_HASH_BASE16"

.github/workflows/templates/naisdevice.rb

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,6 @@
55
desc "naisdevice is a mechanism enabling developers to connect to internal resources in a secure and friendly manner."
66
homepage "https://docs.nais.io/operate/naisdevice/how-to/install/"
77

8-
depends_on formula: [
9-
"wireguard-go",
10-
"wireguard-tools",
11-
]
12-
138
if Hardware::CPU.intel?
149
url "https://github.com/nais/device/releases/download/#{version}/$NAISDEVICE_MACOS_AMD64_FILENAME", verified: "github.com/nais/device/"
1510
sha256 "$NAISDEVICE_MACOS_AMD64_HASH_BASE16"

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ bin
55
.DS_Store
66
*.pkg
77
*.app
8-
wireguard-go-*
9-
wireguard-tools-*
108
cmd/device-agent/main_windows.syso
119
cmd/helper/main_windows.syso
1210
packaging/windows/obj

AGENTS.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Project instructions for AI coding agents
2+
3+
## Commands
4+
5+
### After all changes are made, run
6+
7+
- `mise run test`
8+
- `mise run check`
9+
- `go fix [changed_files]...`
10+
11+
## Tech stack
12+
13+
- go (look at go.mod for version)
14+
- gRPC
15+
- protobuf
16+
- wireguard
17+
- sqlite
18+
19+
## Code style
20+
21+
- Write obvious code instead of clever code.
22+
- Favor self-explanatory code over code comments.
23+
- If you really have to add a comment, make sure it's short and concise.
24+
- Wrap errors with context: `fmt.Errorf("short description: %w", err)`.
25+
- Use `testify/require` and `testify/assert` for tests. Prefer table-driven tests.
26+
- Platform-specific code goes in files with build-tag suffixes (`_darwin.go`, `_linux.go`, `_windows.go`).
27+
28+
## Git
29+
30+
- Use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) for all commit messages.
31+
- Never commit unless explicitly told to.
32+
- Never push unless explicitly told to.

assets/linux/nfpm.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ license: "MIT"
1313
depends:
1414
- "jq"
1515
- "sed"
16-
- "wireguard"
16+
- "wireguard | wireguard-tools"
1717
scripts:
1818
postinstall: "./assets/linux/postinstall"
1919
postremove: "./assets/linux/postrm"

assets/linux/postinstall

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,14 @@ make_user_dirs() {
2828
user_accounts=$(loginctl list-users --output json | jq '[.[] | select(.uid >= 1000)]')
2929
fi
3030

31-
if echo "$user_accounts" | jq -e 'length != 1' >/dev/null; then
31+
num_accounts=$(echo "$user_accounts" | jq 'length')
32+
33+
if [ "$num_accounts" -eq 0 ]; then
34+
echo "No logged-in user accounts found, skipping user directory setup"
35+
return 0
36+
fi
37+
38+
if [ "$num_accounts" -gt 1 ]; then
3239
printf "\nMore than 1 user account logged in! naisdevice only permits _one_ user account!\n"
3340
exit 1
3441
fi
@@ -44,7 +51,9 @@ make_user_dirs() {
4451
chmod 700 "$directory"
4552
done
4653

47-
cp /sys/devices/virtual/dmi/id/product_serial "${config_dir}"
54+
if [ -f /sys/devices/virtual/dmi/id/product_serial ]; then
55+
cp /sys/devices/virtual/dmi/id/product_serial "${config_dir}"
56+
fi
4857

4958
chown -R "${user}:" "${config_dir}"
5059
}

assets/macos/postinstall

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@ daemon_name="io.nais.device.helper"
55
destination="/Library/LaunchDaemons/${daemon_name}.plist"
66
launchctl list | grep -q "$daemon_name" && launchctl unload "$destination"
77

8-
config_dir="/Users/${user}/Library/Application Support/naisdevice"
9-
log_dir="${config_dir}/logs"
8+
if [ -n "$user" ]; then
9+
config_dir="/Users/${user}/Library/Application Support/naisdevice"
10+
log_dir="${config_dir}/logs"
1011

11-
mkdir -p -m 0700 "${config_dir}"
12-
mkdir -p -m 0700 "${log_dir}"
13-
14-
chown -R "${user}:staff" "${config_dir}"
12+
mkdir -p -m 0700 "${config_dir}"
13+
mkdir -p -m 0700 "${log_dir}"
1514

15+
chown -R "${user}:staff" "${config_dir}"
16+
else
17+
echo "No console user detected, skipping user config directory setup"
18+
fi
1619

1720
cat << EOF > "$destination"
1821
<?xml version="1.0" encoding="UTF-8"?>
@@ -49,4 +52,3 @@ launchctl load "$destination"
4952
echo "Installed service $daemon_name"
5053

5154
killall -9 -m "naisdevice.*" || true
52-
killall -9 "wireguard-go" || true

0 commit comments

Comments
 (0)