Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
159 commits
Select commit Hold shift + click to select a range
3312e52
Add iPhone-visible Portal runtime diagnostics
matthewcodergamer Sep 8, 2026
37e7d39
Capture Portal worker and game-data failures
matthewcodergamer Sep 8, 2026
a77aed5
Add Pages isolation and local chunk service worker
matthewcodergamer Sep 8, 2026
3857b89
Add iPhone GitHub Pages baseline test harness
matthewcodergamer Sep 8, 2026
67b21bc
Build and deploy Portal iPhone baseline to Pages
matthewcodergamer Sep 8, 2026
9f6f2a9
Fix Pages permissions for iPhone baseline staging
matthewcodergamer Sep 8, 2026
4888f71
Separate Portal ownership verification from runtime chunks
matthewcodergamer Sep 8, 2026
4dd2e99
Use dedicated Pages environment for iPhone staging
matthewcodergamer Sep 8, 2026
39d0169
Support direct Portal folder verification on iPhone
matthewcodergamer Sep 8, 2026
198527e
Harden Portal chunk loader diagnostics
matthewcodergamer Sep 8, 2026
341f49a
Export fullscreen runtime method for staging shell
matthewcodergamer Sep 8, 2026
deac14c
Fix staging fullscreen control
matthewcodergamer Sep 8, 2026
80d4474
Abort cleanly when Portal runtime data is unavailable
matthewcodergamer Sep 8, 2026
fb51b08
Block launch when Portal runtime chunk is missing
matthewcodergamer Sep 8, 2026
2ce45ea
Restore upstream Portal loader and use original chunk host
matthewcodergamer Sep 8, 2026
564eed9
Allow original upstream Portal chunk requests
matthewcodergamer Sep 8, 2026
d7b70de
Use original yikes.pw Portal chunk source after ownership check
matthewcodergamer Sep 8, 2026
7edb310
Add browser VPK fallback chunk builder
matthewcodergamer Sep 8, 2026
ac110db
Restore original chunks path behind dual-source service worker
matthewcodergamer Sep 8, 2026
4368552
Add original-host to local-VPK chunk fallback
matthewcodergamer Sep 8, 2026
ca01b95
Add automatic VPK fallback when original chunks fail
matthewcodergamer Sep 8, 2026
0a28a3d
Publish local VPK fallback helper in staging build
matthewcodergamer Sep 8, 2026
99ed1a8
Smoke-test dual-source staging JavaScript in CI
matthewcodergamer Sep 8, 2026
3b08463
Fast-fail blocked upstream chunk host before VPK fallback
matthewcodergamer Sep 8, 2026
5f51ec9
Skip runtime artifact upload on pull request validation
matthewcodergamer Sep 8, 2026
51b99f6
Harden Portal data loading and skip desktop startup paths
matthewcodergamer Sep 9, 2026
24e649c
Use Safari native fullscreen path for Portal canvas
matthewcodergamer Sep 9, 2026
624b067
Keep Portal Wasm runtime assets network-fresh on Safari
matthewcodergamer Sep 9, 2026
a34ef24
Validate Wasm side modules and emit useful iPhone abort stacks
matthewcodergamer Sep 9, 2026
15c68df
Skip optional desktop modules in Portal Wasm runtime
matthewcodergamer Sep 9, 2026
cf0c83b
Invalidate stale Portal chunk cache after module fix
matthewcodergamer Sep 9, 2026
b946f2d
Assert required Portal WebAssembly modules before Pages deploy
matthewcodergamer Sep 9, 2026
59d915e
Keep iPhone launch disabled while local chunks are still packing
matthewcodergamer Sep 9, 2026
5f59eeb
Exclude native binaries from locally packed Portal chunks
matthewcodergamer Sep 9, 2026
bb1fada
Fix optional module patch escaping in Portal build
matthewcodergamer Sep 9, 2026
1702f43
Validate optional Portal browser module patch before full build
matthewcodergamer Sep 9, 2026
a1f5073
Document iPhone module loading hardening
matthewcodergamer Sep 9, 2026
d44767f
Restore upstream README on iPhone baseline
matthewcodergamer Sep 9, 2026
387fba4
Preserve upstream README exactly
matthewcodergamer Sep 9, 2026
3f3bd38
Keep baseline documentation upstream-clean
matthewcodergamer Sep 9, 2026
62b0960
Keep iPhone staging runtime network-fresh
matthewcodergamer Sep 9, 2026
7e92d96
Stop preloading the first chamber on iPhone
matthewcodergamer Sep 9, 2026
d047bae
Avoid hard pthread pool aborts on iPhone
matthewcodergamer Sep 9, 2026
33c0938
Validate iPhone memory and pthread fixes
matthewcodergamer Sep 9, 2026
8d43384
Fix iPhone dylink and shared-memory pressure
matthewcodergamer Sep 9, 2026
b60f82b
Keep preloaded dylib package network-fresh
matthewcodergamer Sep 9, 2026
db40546
Validate runtime-dlopen and growable iPhone heap
matthewcodergamer Sep 9, 2026
639289d
Add tiny VPK boot asset overlay
matthewcodergamer Sep 9, 2026
ff12358
Stream local boot assets onto background chunk
matthewcodergamer Sep 9, 2026
81da570
Wire VPK boot overlay into iPhone staging
matthewcodergamer Sep 9, 2026
a60bb76
Fix Emscripten stdlib link for Portal runtime
matthewcodergamer Sep 9, 2026
04b1476
Fix Emscripten C++ forced library names
matthewcodergamer Sep 9, 2026
8708780
Fix staging HTML patch validation
matthewcodergamer Sep 9, 2026
dda0af0
Keep Wasm SIDE_MODULEs raw until Source dlopen
matthewcodergamer Sep 9, 2026
86565d6
Preload launcher and separate Portal boot overlay
matthewcodergamer Sep 9, 2026
2c6d94b
Serve Portal boot overlay separately from map stream
matthewcodergamer Sep 9, 2026
041df3c
Prefer original Portal chunks and preserve local fallback cache
matthewcodergamer Sep 9, 2026
df13a40
Keep Portal boot overlay outside local map cache
matthewcodergamer Sep 9, 2026
65c9d38
Keep boot overlay independent from map cache rebuilds
matthewcodergamer Sep 9, 2026
a061421
Include Source shader cache in Portal boot overlay
matthewcodergamer Sep 9, 2026
d9c5405
Serve Portal shader overlay v2
matthewcodergamer Sep 9, 2026
09c9c09
Reduce Portal map preload memory on iPhone
matthewcodergamer Sep 9, 2026
e7c30af
Bypass service worker wrapper for launcher data
matthewcodergamer Sep 9, 2026
ae175c8
Cap Portal console memory on Safari
matthewcodergamer Sep 9, 2026
89e637f
Lower Portal startup memory pressure on iPhone
matthewcodergamer Sep 9, 2026
209ec2a
Validate iPhone memory-pressure fixes
matthewcodergamer Sep 9, 2026
28b150b
Stream Portal data to reduce Safari jetsam pressure
matthewcodergamer Sep 9, 2026
cb191d0
Shrink threaded Portal runtime for iPhone Safari
matthewcodergamer Sep 9, 2026
f7d8e89
Validate iPhone low-memory Portal release
matthewcodergamer Sep 9, 2026
ad5ec38
Fix Emscripten 4.0.9 low-memory link
matthewcodergamer Sep 10, 2026
e2e3849
Reduce iPhone Portal runtime memory pressure
matthewcodergamer Sep 12, 2026
469ca56
Add iOS crash-loop guard and memory telemetry
matthewcodergamer Sep 12, 2026
d558d3d
Optimize Emscripten side modules for iPhone size
matthewcodergamer Sep 12, 2026
5727959
Validate iPhone Portal low-memory crash fixes
matthewcodergamer Sep 12, 2026
92ea229
Reduce Safari diagnostic DOM memory
matthewcodergamer Sep 12, 2026
5d9aec5
Fix Safari pthread window crash and compact diagnostics
matthewcodergamer Sep 12, 2026
2887f87
Keep Pages deploy transform compatible with compact diagnostics
matthewcodergamer Sep 12, 2026
757bddb
Keep compact diagnostics compatible with CI check
matthewcodergamer Sep 12, 2026
2b08fc3
Retain only latest runtime diagnostic event
matthewcodergamer Sep 12, 2026
59836a7
Keep only latest staging diagnostic event
matthewcodergamer Sep 12, 2026
53763b8
Flatten crash telemetry to latest checkpoint only
matthewcodergamer Sep 12, 2026
1d59cb0
Phase 2: shrink Portal bootstrap shader overlay
matthewcodergamer Sep 12, 2026
5d3299c
Phase 2: invalidate full shader bootstrap cache
matthewcodergamer Sep 12, 2026
4ee2e9f
Phase 2: move first-frame overlay to v3 cache
matthewcodergamer Sep 12, 2026
aa95b9a
Phase 2: report the latest missing shader family
matthewcodergamer Sep 12, 2026
620d71d
Phase 2: build map-scoped shader delta packs
matthewcodergamer Sep 12, 2026
d73db03
Phase 2: stream map shader delta packs with chunks
matthewcodergamer Sep 12, 2026
8e6b45a
Phase 3: link WORKERFS for direct retail VPK access
matthewcodergamer Sep 12, 2026
5cabb2f
Phase 3: keep Portal retail files zero-copy in Source workers
matthewcodergamer Sep 12, 2026
2d7dc5c
Phase 3: retain Portal File objects in staging document
matthewcodergamer Sep 12, 2026
b574706
Phase 3: embed WORKERFS handoff runtime
matthewcodergamer Sep 12, 2026
4a9b57a
Phase 3: validate and deploy direct VPK staging
matthewcodergamer Sep 12, 2026
8ac8edd
Phase 3: start WORKERFS handoff from preRun
matthewcodergamer Sep 12, 2026
ab1249a
Phase 3: suppress compatibility chunk preparation for direct launches
matthewcodergamer Sep 12, 2026
230bd41
Phase 3: skip Phase 2 cache builds for direct VPK launches
matthewcodergamer Sep 12, 2026
d5fa540
Phase 3: enforce current-map-only direct VPK residency
matthewcodergamer Sep 12, 2026
347ac2c
Phase 3: expose current-map-only residency policy
matthewcodergamer Sep 12, 2026
4ee5833
Keep Phase 3 CI marker for disabled background preload
matthewcodergamer Sep 12, 2026
d01a677
Fix cross-thread HTML5 input callback leak and stale-thread abort
matthewcodergamer Sep 13, 2026
f51a850
Fix Phase 3 startup base path and mobile fullscreen fallback
matthewcodergamer Sep 13, 2026
acc4142
Wire Phase 3 mobile startup and fullscreen hardening
matthewcodergamer Sep 13, 2026
9627140
Allow native iframe fullscreen for Phase 3 on iPhone
matthewcodergamer Sep 13, 2026
06cd0c5
Harden WebAssembly Source startup path and checkpoints
matthewcodergamer Sep 13, 2026
65a2975
Trace nested Source startup failures
matthewcodergamer Sep 13, 2026
717a85e
Add nested Source startup instrumentation patcher
matthewcodergamer Sep 13, 2026
1a20efa
Add structured startup failure tracker
matthewcodergamer Sep 13, 2026
4c7c88a
Remove duplicate startup diagnostics patcher
matthewcodergamer Sep 13, 2026
933a843
Remove duplicate startup diagnostics tracker
matthewcodergamer Sep 13, 2026
29f4145
Fix WebAssembly basedir argument parsing
matthewcodergamer Sep 13, 2026
cfdc4fc
Stage Phase 3 startup metadata in shared MEMFS
matthewcodergamer Sep 13, 2026
556b354
Fix Phase 3 startup metadata run dependency
matthewcodergamer Sep 13, 2026
01af043
Add zero-copy browser File bridge for Portal VPK reads
matthewcodergamer Sep 13, 2026
4dd8a90
Link browser-backed retail bridge into Portal main module
matthewcodergamer Sep 13, 2026
a207ced
Patch Source stdio for browser-backed Portal retail reads
matthewcodergamer Sep 13, 2026
6430d06
Apply browser-backed stdio patch in Wasm filesystem build
matthewcodergamer Sep 13, 2026
96f063a
Resolve direct files from the local WORKERFS mount
matthewcodergamer Sep 13, 2026
7888200
Expose zero-byte VPK namespace while keeping retail bytes browser-backed
matthewcodergamer Sep 13, 2026
2c2d6a2
Keep browser retail bridge in the linked Wasm launcher object
matthewcodergamer Sep 13, 2026
87ae3b9
Guarantee retail bridge is linked into Wasm MAIN_MODULE
matthewcodergamer Sep 13, 2026
ee06bf6
Fix browser file bridge EM_JS preprocessing
matthewcodergamer Sep 14, 2026
7b917f0
Expose zero-copy retail File handles to Source bridge
matthewcodergamer Sep 14, 2026
578351e
Fix Phase 3 gameinfo bootstrap before Source preinit
matthewcodergamer Sep 14, 2026
5947a22
fix(wasm): avoid EM_JS optimizer failure in retail bridge
matthewcodergamer Sep 14, 2026
2003340
fix(wasm): retain loose Portal BSP maps for direct streaming
matthewcodergamer Sep 14, 2026
cfa1be6
fix(wasm): expose loose Portal maps through WORKERFS
matthewcodergamer Sep 14, 2026
30ad6b1
fix(ci): preserve Phase 3 no-preload architecture guard
matthewcodergamer Sep 14, 2026
b9818d3
ios-native: add native iOS bootstrap overview
matthewcodergamer Sep 15, 2026
05896a4
ios-native: add CMake Xcode bootstrap target
matthewcodergamer Sep 15, 2026
c640610
ios-native: add application Info.plist
matthewcodergamer Sep 15, 2026
7158da3
ios-native: add native UIKit bootstrap and Portal folder verifier
matthewcodergamer Sep 15, 2026
9fdeb40
ci: add unsigned native iOS IPA build
matthewcodergamer Sep 15, 2026
633f6cc
ci: add signed native iOS IPA workflow
matthewcodergamer Sep 15, 2026
12a8d5e
docs: add native iOS zero-to-complete roadmap
matthewcodergamer Sep 15, 2026
6fee9d2
docs: add zero-to-complete native iOS AI build prompts
matthewcodergamer Sep 15, 2026
9732688
docs: add iOS native build, IPA, and signing guide
matthewcodergamer Sep 15, 2026
d2b28bf
docs: define native iOS architecture boundaries
matthewcodergamer Sep 15, 2026
2d19a96
docs: add zero-to-complete native iOS IPA prompt pack
matthewcodergamer Sep 15, 2026
dd1833b
docs: make zero-to-IPA prompt pack the native implementation entry point
matthewcodergamer Sep 15, 2026
e227ef1
docs: add native iOS phase 00 porting audit
matthewcodergamer Sep 16, 2026
3a0dcfc
ci: fix native iOS IPA product discovery
matthewcodergamer Sep 16, 2026
38ba0e2
ci: fix signed iOS app product discovery
matthewcodergamer Sep 16, 2026
7257767
docs: mark native iOS phase 00 CI baseline complete
matthewcodergamer Sep 16, 2026
aa06639
ios: harden N0 bootstrap diagnostics and IPA validation
matthewcodergamer Sep 16, 2026
aedfb68
ios: disable Mac and vision compatibility for N0
matthewcodergamer Sep 16, 2026
7ec9b1c
ci: pin N0 build-setting inspection to iOS
matthewcodergamer Sep 16, 2026
db05a29
docs: record native iOS phase 01 N0 result
matthewcodergamer Sep 16, 2026
976bc3d
ios: implement N1 SDL2 GLES input audio host
matthewcodergamer Sep 16, 2026
c0dcdd8
ios: fix N1 CMake control-flow syntax
matthewcodergamer Sep 16, 2026
621d83d
ios: declare SDL frame callback target
matthewcodergamer Sep 16, 2026
6384c78
ios: harden N1 lifecycle shutdown and input diagnostics
matthewcodergamer Sep 16, 2026
358747c
ios: add focused N2 Source platform boundary
matthewcodergamer Sep 16, 2026
dc9333b
ios: add explicit N2 Source foundation graph
matthewcodergamer Sep 16, 2026
ff954f6
ios: wire N2 Source foundation targets
matthewcodergamer Sep 16, 2026
81ed58a
ci: prove N2 Source foundation libraries
matthewcodergamer Sep 16, 2026
37a4426
ios: expose legacy GNUC switch for Source foundations
matthewcodergamer Sep 16, 2026
fb441ac
ios: select legacy Darwin allocator headers in Source
matthewcodergamer Sep 16, 2026
cb447af
ios: build full Source mathlib foundation inventory
matthewcodergamer Sep 16, 2026
28d3b48
ios: make tier1 MD5 C++17 compatible
matthewcodergamer Sep 16, 2026
9d44f07
ci: watch N2 Source foundation inputs
matthewcodergamer Sep 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
365 changes: 349 additions & 16 deletions .github/workflows/build.yml

Large diffs are not rendered by default.

201 changes: 201 additions & 0 deletions .github/workflows/ios-native-signed.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
name: iOS Native Signed IPA

on:
workflow_dispatch:

permissions:
contents: read

jobs:
build-signed-ios:
runs-on: macos-latest
timeout-minutes: 35

steps:
- name: Checkout source and submodules
uses: actions/checkout@v6
with:
submodules: recursive
fetch-depth: 1

- name: Verify no retail Portal data is committed under native project
shell: bash
run: |
set -euo pipefail
if find ios-native -type f \( \
-iname '*.vpk' -o -iname '*.bsp' -o -iname '*.vtf' -o -iname '*.vmt' -o \
-iname '*.vcs' -o -iname '*.wav' -o -iname '*.mp3' -o -iname '*.mdl' \
\) -print -quit | grep -q .; then
echo 'Retail/game asset file detected under ios-native/. Refusing signed package.' >&2
exit 1
fi

- name: Validate signing configuration
env:
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
IOS_TEAM_ID: ${{ vars.IOS_TEAM_ID }}
IOS_BUNDLE_ID: ${{ vars.IOS_BUNDLE_ID }}
run: |
set -euo pipefail
for value in BUILD_CERTIFICATE_BASE64 BUILD_PROVISION_PROFILE_BASE64 P12_PASSWORD KEYCHAIN_PASSWORD IOS_TEAM_ID IOS_BUNDLE_ID; do
if [ -z "${!value:-}" ]; then
echo "Missing required secret/variable: $value" >&2
exit 1
fi
done

- name: Install Apple certificate and provisioning profile
env:
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
shell: bash
run: |
set -euxo pipefail
CERTIFICATE_PATH="$RUNNER_TEMP/build_certificate.p12"
PP_PATH="$RUNNER_TEMP/build_pp.mobileprovision"
KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db"

echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o "$CERTIFICATE_PATH"
echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o "$PP_PATH"

security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security import "$CERTIFICATE_PATH" -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH"
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security list-keychain -d user -s "$KEYCHAIN_PATH"

security cms -D -i "$PP_PATH" > "$RUNNER_TEMP/profile.plist"
PROFILE_UUID="$(/usr/libexec/PlistBuddy -c 'Print :UUID' "$RUNNER_TEMP/profile.plist")"
PROFILE_NAME="$(/usr/libexec/PlistBuddy -c 'Print :Name' "$RUNNER_TEMP/profile.plist")"
mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles"
cp "$PP_PATH" "$HOME/Library/MobileDevice/Provisioning Profiles/$PROFILE_UUID.mobileprovision"

echo "PROFILE_UUID=$PROFILE_UUID" >> "$GITHUB_ENV"
echo "PROFILE_NAME=$PROFILE_NAME" >> "$GITHUB_ENV"
echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV"

- name: Configure signed Xcode project
env:
IOS_BUNDLE_ID: ${{ vars.IOS_BUNDLE_ID }}
run: |
set -euxo pipefail
cmake -S ios-native -B build/ios -G Xcode \
-DCMAKE_SYSTEM_NAME=iOS \
-DCMAKE_OSX_SYSROOT=iphoneos \
-DCMAKE_OSX_ARCHITECTURES=arm64 \
-DCMAKE_OSX_DEPLOYMENT_TARGET=15.0 \
-DRENDER360_DEPLOYMENT_TARGET=15.0 \
-DRENDER360_BUNDLE_ID="$IOS_BUNDLE_ID" \
-DRENDER360_BUILD_IDENTIFIER="${GITHUB_SHA}" \
-DRENDER360_BUILD_NUMBER="${GITHUB_RUN_NUMBER}"

- name: Build signed arm64 app
env:
IOS_TEAM_ID: ${{ vars.IOS_TEAM_ID }}
IOS_SIGNING_IDENTITY: ${{ vars.IOS_SIGNING_IDENTITY }}
shell: bash
run: |
set -euxo pipefail
SIGNING_IDENTITY="${IOS_SIGNING_IDENTITY:-Apple Development}"
xcodebuild \
-project build/ios/Render360PortalIOS.xcodeproj \
-scheme Render360Portal \
-configuration Release \
-sdk iphoneos \
-destination 'generic/platform=iOS' \
-derivedDataPath build/DerivedData \
CODE_SIGN_STYLE=Manual \
DEVELOPMENT_TEAM="$IOS_TEAM_ID" \
CODE_SIGN_IDENTITY="$SIGNING_IDENTITY" \
PROVISIONING_PROFILE="$PROFILE_UUID" \
ONLY_ACTIVE_ARCH=NO \
ARCHS=arm64 \
build

- name: Verify signature and package IPA
shell: bash
run: |
set -euxo pipefail

resolve_app_path() {
local candidate
for candidate in \
build/ios/Release-iphoneos/Render360Portal.app \
build/DerivedData/Build/Products/Release-iphoneos/Render360Portal.app; do
if [ -d "$candidate" ]; then
printf '%s\n' "$candidate"
return 0
fi
done
find build -type d -path '*/Release-iphoneos/Render360Portal.app' -print -quit 2>/dev/null || true
}

APP_PATH="$(resolve_app_path)"
if [ -z "$APP_PATH" ] || [ ! -d "$APP_PATH" ]; then
echo 'Render360 Portal: could not locate the signed iPhoneOS .app bundle.' >&2
find build -maxdepth 6 -type d -name '*.app' -print 2>/dev/null || true
exit 1
fi

EXECUTABLE="$APP_PATH/Render360Portal"
test -f "$EXECUTABLE"
codesign --verify --deep --strict --verbose=2 "$APP_PATH"
codesign -d --entitlements :- "$APP_PATH" || true
test "$(lipo -archs "$EXECUTABLE")" = 'arm64'

python3 - "$APP_PATH/Info.plist" "${{ vars.IOS_BUNDLE_ID }}" <<'PY'
import plistlib
import sys

with open(sys.argv[1], 'rb') as handle:
info = plistlib.load(handle)
assert info.get('CFBundleIdentifier') == sys.argv[2]
assert info.get('CFBundleExecutable') == 'Render360Portal'
assert info.get('UIDeviceFamily') == [1]
assert info.get('CFBundleSupportedPlatforms') == ['iPhoneOS']
assert info.get('MinimumOSVersion') == '15.0'
assert info.get('UISupportedInterfaceOrientations') == [
'UIInterfaceOrientationLandscapeLeft',
'UIInterfaceOrientationLandscapeRight',
]
print('Validated signed N0 bundle metadata')
PY

rm -rf build/ipa-signed
mkdir -p build/ipa-signed/Payload
ditto "$APP_PATH" build/ipa-signed/Payload/Render360Portal.app
(cd build/ipa-signed && /usr/bin/zip -qry ../Render360-Portal-iOS-signed.ipa Payload)
IPA=build/Render360-Portal-iOS-signed.ipa
test -s "$IPA"
/usr/bin/unzip -Z1 "$IPA" > build/signed-ipa-contents.txt
grep -qx 'Payload/Render360Portal.app/Render360Portal' build/signed-ipa-contents.txt
if grep -Eiq '\.(vpk|bsp|vtf|vmt|vcs|wav|mp3|mdl)$' build/signed-ipa-contents.txt; then
echo 'Retail/game asset extension detected inside signed IPA.' >&2
exit 1
fi
ls -lh "$IPA"

- name: Upload signed IPA
uses: actions/upload-artifact@v4
with:
name: Render360-Portal-iOS-signed-${{ github.run_number }}
path: build/Render360-Portal-iOS-signed.ipa
if-no-files-found: error
retention-days: 14

- name: Clean up signing material
if: ${{ always() }}
shell: bash
run: |
if [ -n "${KEYCHAIN_PATH:-}" ] && [ -f "$KEYCHAIN_PATH" ]; then
security delete-keychain "$KEYCHAIN_PATH" || true
fi
if [ -n "${PROFILE_UUID:-}" ]; then
rm -f "$HOME/Library/MobileDevice/Provisioning Profiles/$PROFILE_UUID.mobileprovision" || true
fi
135 changes: 135 additions & 0 deletions .github/workflows/ios-native.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
name: iOS Native Bootstrap IPA
on:
push:
branches: [render360/ios-native]
paths:
- 'ios-native/**'
- 'tier0/**'
- 'tier1/**'
- 'mathlib/**'
- 'common/**'
- 'public/**'
- '.github/workflows/ios-native.yml'
- 'docs/IOS_NATIVE_**'
workflow_dispatch:
permissions: { contents: read }
jobs:
build-ios-native:
runs-on: macos-latest
timeout-minutes: 30
steps:
- name: Checkout source and submodules
uses: actions/checkout@v6
with: { submodules: recursive, fetch-depth: 1 }
- name: Print toolchain
run: |
set -euxo pipefail
xcodebuild -version; cmake --version; clang --version
- name: Verify native source boundaries
shell: bash
run: |
set -euo pipefail
if find ios-native -type f \( -iname '*.vpk' -o -iname '*.bsp' -o -iname '*.vtf' -o -iname '*.vmt' -o -iname '*.vcs' -o -iname '*.wav' -o -iname '*.mp3' -o -iname '*.mdl' \) -print -quit | grep -q .; then echo 'Retail game asset detected.' >&2; exit 1; fi
if grep -RInE '__EMSCRIPTEN__|MEMFS|WORKERFS|SharedArrayBuffer|PROXY_TO_PTHREAD|OffscreenCanvas' ios-native/Sources ios-native/SourceCompat ios-native/CMakeLists.txt ios-native/cmake; then echo 'Browser runtime dependency entered native target.' >&2; exit 1; fi
grep -q 'add_library(r360_tier0 STATIC' ios-native/cmake/SourceFoundation.cmake
grep -q 'add_library(r360_tier1 STATIC' ios-native/cmake/SourceFoundation.cmake
grep -q 'add_library(r360_mathlib STATIC' ios-native/cmake/SourceFoundation.cmake
- name: Configure Xcode arm64 iPhone project
run: |
set -euxo pipefail
cmake -S ios-native -B build/ios -G Xcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos -DCMAKE_OSX_ARCHITECTURES=arm64 -DCMAKE_OSX_DEPLOYMENT_TARGET=15.0 -DRENDER360_DEPLOYMENT_TARGET=15.0 -DRENDER360_BUNDLE_ID=com.render360.portal -DRENDER360_BUILD_IDENTIFIER="${GITHUB_SHA}" -DRENDER360_BUILD_NUMBER="${GITHUB_RUN_NUMBER}"
- name: Verify pinned SDL2 and generated iPhoneOS settings
shell: bash
run: |
set -euo pipefail
grep -Fx 'version=2.32.10' build/ios/render360-sdl2-version.txt
grep -Fx 'commit=5d249570393f7a37e037abf22cd6012a4cc56a71' build/ios/render360-sdl2-version.txt
grep -Fx 'sha256=5f5993c530f084535c65a6879e9b26ad441169b3e25d789d83287040a9ca5165' build/ios/render360-sdl2-version.txt
xcodebuild -project build/ios/Render360PortalIOS.xcodeproj -scheme Render360Portal -configuration Release -sdk iphoneos -destination 'generic/platform=iOS' -showBuildSettings | tee build/xcode-build-settings.txt
grep -Eq '^[[:space:]]*ARCHS = arm64$' build/xcode-build-settings.txt
grep -Eq '^[[:space:]]*IPHONEOS_DEPLOYMENT_TARGET = 15\.0$' build/xcode-build-settings.txt
grep -Eq '^[[:space:]]*PRODUCT_BUNDLE_IDENTIFIER = com\.render360\.portal$' build/xcode-build-settings.txt
grep -Eq '^[[:space:]]*SUPPORTED_PLATFORMS = iphoneos$' build/xcode-build-settings.txt
grep -Eq '^[[:space:]]*TARGETED_DEVICE_FAMILY = 1$' build/xcode-build-settings.txt
grep -Eq '^[[:space:]]*SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO$' build/xcode-build-settings.txt
grep -Eq '^[[:space:]]*SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO$' build/xcode-build-settings.txt
- name: Build N2 Source foundation in dependency order
shell: bash
run: |
set -euxo pipefail
for target in r360_tier0 r360_tier1 r360_mathlib; do
echo "=== building ${target} ==="
xcodebuild -project build/ios/Render360PortalIOS.xcodeproj -target "${target}" -configuration Release -sdk iphoneos -destination 'generic/platform=iOS' CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=NO ARCHS=arm64 build
done
- name: Verify N2 static ARM64 products
shell: bash
run: |
set -euxo pipefail
: > build/foundation-libraries.txt
for stem in tier0_ios tier1_ios mathlib_ios; do
lib="$(find build/ios -type f -name "lib${stem}.a" -print -quit)"
test -n "$lib"
archs="$(lipo -archs "$lib")"
test "$archs" = arm64
echo "${stem}=${lib} arch=${archs}" | tee -a build/foundation-libraries.txt
done
if grep -Eq '(^|[[:space:]])(i386|x86_64)([[:space:]]|$)' build/foundation-libraries.txt; then exit 1; fi
- name: Build unsigned arm64 N2 app
run: |
set -euxo pipefail
xcodebuild -project build/ios/Render360PortalIOS.xcodeproj -scheme Render360Portal -configuration Release -sdk iphoneos -destination 'generic/platform=iOS' -derivedDataPath build/DerivedData CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=NO ARCHS=arm64 build
- name: Verify N2 bundle and package unsigned IPA
shell: bash
run: |
set -euxo pipefail
APP_PATH=build/ios/Release-iphoneos/Render360Portal.app
if [ ! -d "$APP_PATH" ]; then APP_PATH=build/DerivedData/Build/Products/Release-iphoneos/Render360Portal.app; fi
test -f "$APP_PATH/Render360Portal"
lipo -archs "$APP_PATH/Render360Portal" | tee build/architecture.txt
test "$(cat build/architecture.txt)" = arm64
nm "$APP_PATH/Render360Portal" | grep -q '_SDL_Init'
python3 - "$APP_PATH/Info.plist" <<'PY'
import plistlib,sys
with open(sys.argv[1],'rb') as f: info=plistlib.load(f)
assert info.get('CFBundleIdentifier')=='com.render360.portal'
assert info.get('CFBundleExecutable')=='Render360Portal'
assert info.get('UIRequiresFullScreen') is True
assert info.get('UIFileSharingEnabled') is True
assert info.get('LSSupportsOpeningDocumentsInPlace') is True
assert info.get('UISupportedInterfaceOrientations')==['UIInterfaceOrientationLandscapeLeft','UIInterfaceOrientationLandscapeRight']
assert info.get('UIRequiredDeviceCapabilities')==['arm64']
assert info.get('UIDeviceFamily')==[1]
assert info.get('CFBundleSupportedPlatforms')==['iPhoneOS']
assert info.get('MinimumOSVersion')=='15.0'
assert not any(k.startswith('NS') and k.endswith('UsageDescription') for k in info)
PY
rm -rf build/ipa; mkdir -p build/ipa/Payload; ditto "$APP_PATH" build/ipa/Payload/Render360Portal.app
cat > build/ipa/BUILD_INFO.txt <<INFO
Render360 Portal native iOS N2 Source foundation
commit=${GITHUB_SHA}
sdl=2.32.10
sdl_commit=5d249570393f7a37e037abf22cd6012a4cc56a71
source_foundation=tier0,tier1,mathlib
sdk=iphoneos
deployment=15.0
arch=arm64
signing=unsigned
retail_assets=bundled:no
INFO
(cd build/ipa && /usr/bin/zip -qry ../Render360-Portal-iOS-unsigned.ipa Payload BUILD_INFO.txt)
/usr/bin/unzip -Z1 build/Render360-Portal-iOS-unsigned.ipa | tee build/ipa-contents.txt
grep -qx 'Payload/Render360Portal.app/Render360Portal' build/ipa-contents.txt
if grep -Eiq '\.(vpk|bsp|vtf|vmt|vcs|wav|mp3|mdl)$' build/ipa-contents.txt; then exit 1; fi
- name: Upload unsigned IPA
uses: actions/upload-artifact@v4
with:
name: Render360-Portal-iOS-unsigned-${{ github.run_number }}
path: |
build/Render360-Portal-iOS-unsigned.ipa
build/architecture.txt
build/foundation-libraries.txt
build/xcode-build-settings.txt
build/ipa-contents.txt
build/ios/render360-sdl2-version.txt
if-no-files-found: error
retention-days: 30
Loading
Loading