[misc, android] Build and lint the mobile Go code in CI (#7641)

Nothing in CI compiles the files behind //go:build android or //go:build ios.
The android bridge builds 7 of its 23 files on linux and skips client.go; the
iOS SDK is not built at all. The linter matrix picks a GOOS by picking a runner
OS, so it loads the same file set as the host build and never sees them either.
A type error in client/android/client.go therefore passes every check on its
PR, merges, and is discovered by netbirdio/android-client after sync-tag.yml
fires trigger_android_bump on the release tag.

The new Mobile workflow cross-compiles ./client/android/... for the GOARCH
values gomobile ships and ./client/ios/..., and vets the android bridge. The
new Android and iOS lint jobs run golangci-lint with GOOS/GOARCH in the job
env. No NDK, Xcode or gomobile is needed: these are library packages, so the
compiler type-checks them without a link step, and the dependency graph drags
in the android/ios-tagged files across client/iface, client/internal/dns and
client/internal/routemanager with them.

Linting those files for the first time surfaces one gosec G101 on the SSH
password-required marker. It is a sentinel string the Java side matches on,
not a credential, so it is suppressed at the declaration.
This commit is contained in:
Riccardo Manfrin
2026-09-25 10:21:20 +02:00
committed by GitHub
parent ad7598a7d7
commit c7f610e6cd
3 changed files with 112 additions and 0 deletions
+46
View File
@@ -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
@@ -31,6 +31,8 @@ const (
// PasswordRequiredMarker tells Java to prompt for a password and retry. It is
// a string because gomobile flattens errors to their message, so a sentinel
// value would not survive the binding.
//
//nolint:gosec // G101 false positive: a sentinel marker, not a credential
const PasswordRequiredMarker = "netbird-ssh-password-required"
// HostKeyUnknownMarker tells Java to show the fingerprint and, on confirmation,