ci: build and test the apple app on every push - #333
Merged
Conversation
This repo had no .github directory at all, so nothing verified that the
iOS and macOS apps still compile or that the unit suite still passes.
The release pipeline (build/all/run.sh) archives and signs; it never runs
networkTests. This closes that gap.
What the job does, and why each step is there:
* Checks out apple into `apple/` and urnetwork/sdk into `sdk/`, then
clones connect, glog and goidenticons at the workspace root. Both
layouts are forced, not stylistic: app/URnetworkSdk/Package.swift is
a binaryTarget at ../../../sdk/build/apple/URnetworkSdk.xcframework,
and sdk/go.mod + sdk/build/go.mod resolve the three Go siblings
through `replace ../` directives. Same sibling convention, and the
same conditional goidenticons RenderPngV2 shim, as the existing
sdk, connect and windows workflows.
* Builds the SDK xcframeworks with `make init_tools build_apple`.
Nothing publishes them, so CI builds them or it cannot build the app.
init_tools rather than build.sh's `init`, because `init` ends with
`go clean -cache && go clean -modcache` and would discard the Go
cache it just populated; the Makefile documents init_tools as the
target for exactly this case.
* Pins Go via sdk/build/go.mod (1.26.5) instead of the `go-version:
stable` the sibling Go workflows use. stable is 1.27, and
sdk/build/Makefile's build_apple exports GODEBUG=gotypesalias=0,
which the 1.27 runtime fatals on -- its own comment says gomobile
must be built with go <= 1.26. GOTOOLCHAIN=local keeps a future
go.mod bump from silently undoing that.
* Asserts the built xcframeworks actually carry the ios-arm64,
ios-arm64-simulator and macos slices. build_apple only tests that
the directories exist and only size-checks ios-arm64, so a
part-way bind would otherwise surface 200 lines later as a
missing-module error in xcodebuild.
* Builds URnetwork for `generic/platform=iOS` and
`generic/platform=macOS`, Release, with CODE_SIGNING_ALLOWED=NO and
nothing else -- byte-for-byte what build.sh does. The targets use
automatic signing with a DEVELOPMENT_TEAM in the pbxproj, so also
blanking DEVELOPMENT_TEAM/CODE_SIGN_IDENTITY is what actually
provokes "requires a development team".
* Runs check_apple_size.sh --extension on the built appex, as build.sh
does. Beyond the size ceiling it re-reads the appex's Go build
metadata, so it also proves the extension was built GOOS=ios with
fips140 off.
* Runs `xcodebuild test -only-testing:networkTests` on the iOS
Simulator. networkTests is a host-app bundle, so the app really
launches; test-main.sh proves the simulator leg needs no signing,
while its macOS leg needs -allowProvisioningUpdates and a real team,
which is why macOS here stays build-only.
Deliberately out of scope: archive, signing, provisioning, notarization
and upload; and networkUITests/testMainAcceptance, which signs into a
live account from vault/main/test-acceptance.yml. No secret is used or
needed.
runs-on macos-15 because it must be Apple silicon: the SDK binds
iossimulator/arm64 with no x86_64 simulator slice, so the test host
cannot link on an intel runner.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MAXFxG1EK4jTxQ1iW73BUr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This repo has no
.githubdirectory today, so nothing verifies that the iOS and macOSapps still compile, and nothing runs
networkTests. The release pipeline(
build/all/run.sh) archives and signs — it never runs the unit suite. This adds a firstCI that closes both gaps.
What it runs
One job,
runs-on: macos-15, on push + PR againstmainplusworkflow_dispatch.apple/,urnetwork/sdkintosdk/, and cloneconnect,glog,goidenticonsat the workspace root. Both layouts are forced, not stylistic:app/URnetworkSdk/Package.swiftis abinaryTargetat../../../sdk/build/apple/URnetworkSdk.xcframework, andsdk/go.mod+sdk/build/go.modresolve the three Go siblings throughreplace ../directives. Samesibling convention — and the same conditional goidenticons
RenderPngV2shim — as theexisting
sdk,connectandwindowsworkflows. (The shim is a no-op today;goidenticons publishes
RenderPngV2atgoidenticons.go:373.)make init_tools build_appleinsdk/build— the xcframeworks are committednowhere and no release publishes them, so CI builds them or it cannot build the app.
ios-arm64,ios-arm64-simulatorandmacos-*slices, each with a plausibly-sized binary.
xcodebuild build, Release,generic/platform=iOS, unsigned.sdk/build/check_apple_size.sh --extension <URnetworkVPN.appex>— the same budgetgate
build.shruns after its iOS build.xcodebuild build, Release,generic/platform=macOS, unsigned.xcodebuild test -only-testing:networkTestson the iOS Simulator (iPhone 16).Steps 4, 6 and 7 are
build.shandtest-main.sh's own unsigned invocations, unchanged.What it deliberately does not do
none is needed. The two builds pass
CODE_SIGNING_ALLOWED=NOand nothing else —exactly what
build.shpasses. Every target isCODE_SIGN_STYLE = Automaticwith aDEVELOPMENT_TEAMbaked into the pbxproj, and also blankingDEVELOPMENT_TEAM/CODE_SIGN_IDENTITYis what provokes "Signing for X requires a development team", sothe workflow does not.
test-main.sh's macOS leg has to pass-allowProvisioningUpdates DEVELOPMENT_TEAM=6BGU69Q742because the app's sandbox andNetworkExtension entitlements need a real profile. The simulator leg needs no signing at
all, which is why the tests run there.
networkUITestsis excluded via-only-testing:networkTests. TheURnetworkscheme's test action lists both bundles, and
networkUITests/testMainAcceptancesignsinto a live account from
vault/main/test-acceptance.ymland asserts a changed publicegress IP. That is the product acceptance suite, out of scope under a no-secrets rule —
not a silent skip.
networkTestsis the repo's real unit suite: 10 files, XCTest plusswift-testing, covering GlobeGeometry, WorldTopology, TransportStats,
VPNReconciliationSupport, TunnelMemoryBounds, PresentationLifecycle,
PhysicalPageBenchmarkResult, ProviderLocationLabel and DeviceModelNames.
build.shregeneratesLocalizable.xcstringsvianpm run gen:applein the sibling store, but that file is committed (the pipelinecommits the refresh — see 995cd52), so CI needs four siblings, not five.
Two pins that differ from the sibling workflows, on purpose
runs-on: macos-15must be Apple silicon.sdk/build/Makefilebindsiossimulator/arm64with no x86_64 simulator slice, so the simulator test host cannotlink on an intel runner. Do not move this to an intel image.
go-version-file: sdk/build/go.mod(1.26.5), notgo-version: stablethe waysdk/test.ymlandconnect/test.ymldo.stableis now1.27, and
build_appleexportsGODEBUG=gotypesalias=0, which the 1.27 runtime fatalson — the Makefile's own comment says gomobile must be built with go <= 1.26.
GOTOOLCHAIN: localkeeps a future siblinggo.modbump from silently undoing that byturning it into a loud "requires go >= 1.27" instead.
make init_tools, notbuild.sh'smake init:initends withgo clean -cache && go clean -modcache, which would throw away the cachesetup-gojustrestored. The Makefile documents
init_toolsas the target for exactly this case("so acceptance builds do not install tools or clean shared Go caches"), and the
go get golang.org/x/mobile/bindthatinitadds is a no-op —sdk/build/go.modalreadypins x/mobile at the same
GOMOBILE_VERSION.For a maintainer to decide
gomobile bindsacross four slices each (URnetworkSdk, then URnetworkExtensionSdk with
-tags ios_extension) before anyxcodebuildruns, then two Release builds and asimulator test run.
timeout-minutes: 180. If that is too expensive per push,the cheapest lever is dropping the macOS build; the next is caching the xcframeworks
keyed on the four sibling SHAs (they cannot go through
upload-artifactas-is —it dereferences the macOS framework symlinks).
check_apple_size.shenforces hardceilings (56 MiB SDK, 53 MiB extension SDK, 39 MiB extension). A legitimate size
increase will turn CI red until the ceiling is raised deliberately. That is the
intended behaviour, but it is worth knowing before the first red build.
unrelated push to
connectcan turn every open PR here red at once — the sametradeoff
server/test.ymldocuments. Pinref:per sibling if that proves noisy.app/URnetworkSdk/Package.swiftdeclares.testTarget(name: "URnetworkSdkTests", dependencies: ["URnetworkSdkBinary"]), butapp/URnetworkSdk/contains onlyPackage.swift— there is noTests/URnetworkSdkTestsdirectory, and.gitignoredoes not exclude one. SwiftPM'susual response is "Source files for target URnetworkSdkTests should be located under
'Tests/URnetworkSdkTests'". This predates the PR and would hit a local
build.shidentically, so Xcode may well tolerate it for a binary-only local package — but if
the first run dies during package resolution rather than during the Go bind, this is
the cause.
Verification
python3 -c "import yaml; yaml.safe_load(...)"parses;actionlint(with shellcheck) isclean; the xcframework-slice assertion was dry-run against a synthetic layout and both
passes and fails correctly. Every referenced name was checked against the repo: the
URnetworkshared scheme, thenetworkTestsblueprint name, theapp.xcodeproj/project.xcworkspacepath,sdk/build'sinit_toolsandbuild_appletargets,
check_apple_size.sh --extension, andsdk/build/go.mod+go.sum.Not verified without dispatching: that
Xcode_16.4.appand aniPhone 16simulatorare present on the current
macos-15image; the real wall-clock time; and whether theunsigned
generic/platform=iOSRelease build clears signing on a runner with no keychainidentity —
build.shdoes exactly this locally, so it should, but if it demands a teamanyway, drop that step and the
--extensionsize gate with it (the gate needs theRelease-iphoneosappex) and keep the macOS build plus the simulator test.Left as a draft for that first dispatch.