Private
Public Access
1
0

13 Commits

Author SHA1 Message Date
526dedd653 fix(ci): derive tag from git when CM_TAG is unset
Codemagic doesn't set CM_TAG for Gitea webhook integrations.
Fall back to git tag --points-at HEAD.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 22:20:30 +01:00
9b3ac8c31c chore(altstore): update source for 2026-04-06 21:09:49 +00:00
cd2ba37db6 fix(ci): import SLABS variable group for GITEA_TOKEN
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 21:59:06 +01:00
7be2ef27b9 fix(ci): add xcodegen project.yml and generate xcodeproj before archive
SPM executableTarget is treated as a CLI tool by xcodebuild, producing
Products/usr/local/bin instead of a .app bundle. xcodegen generates a
proper application target with PRODUCT_TYPE=com.apple.product-type.application.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 12:47:12 +01:00
b7e4931e64 fix(ci): use xcodebuild archive to produce .app for IPA packaging
xcodebuild build on an SPM executableTarget only outputs the module/bundle,
not a .app. archive produces a .xcarchive with the .app under Products/.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 12:38:48 +01:00
a3bfd42759 fix(ci): restore -destination flag for SwiftPM xcodebuild
-sdk alone is rejected; SwiftPM packages require -destination.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 23:24:31 +01:00
1587db4edf fix(ci): switch from archive to build -sdk iphoneos
SwiftPM executableTarget archived to usr/local/bin (no .app bundle).
xcodebuild build -sdk iphoneos puts .app in DerivedData/Release-iphoneos/.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 23:21:26 +01:00
a516f0570d fix(ci): fix .app path lookup and add GITEA_TOKEN guard
- Package IPA: use find to locate .app regardless of archive subpath
- Publish: fail fast with clear message if GITEA_TOKEN is not set

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 23:16:54 +01:00
7cbdc3cdb7 fix(ci): add set -x tracing to Publish step for diagnosis
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 22:05:45 +01:00
7f27ee1b4e fix(ci): use base64 -i flag for macOS input file syntax
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 13:15:58 +01:00
4f9c73e90f fix(ci): replace git push with Gitea API file update
git push over HTTPS was failing auth despite correct credentials.
Use PUT /contents API instead — same token already works for releases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 13:05:06 +01:00
e3359320fc fix(ci): correct Gitea HTTP auth username in codemagic push step
Was using 'sysadmin' (Linux system user) instead of 'SilverLABS' (Gitea account).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:50:25 +01:00
9073a51787 fix(build): resolve Xcode 26 compilation errors
- Add ServerConfigView stub (referenced in SilverAppleApp.swift)
- Add HardeningListView stub (referenced in DashboardView.swift)
- Fix .accentColor → Color.accentColor (ShapeStyle removed member)
- Fix withCheckedThrowingContinuation explicit type annotation
- Make AppEnvironment.serverUrl internal for ServerConfigView access

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 12:13:04 +01:00
9 changed files with 155 additions and 21 deletions

3
.gitignore vendored
View File

@@ -32,6 +32,9 @@ playground.xcworkspace
.build/
# Generated by xcodegen in CI — do not commit
*.xcodeproj/
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However

View File

@@ -12,7 +12,7 @@ final class AppEnvironment: ObservableObject {
let apiClient: SilverAPIClient
let mdmService: MDMEnrollmentService
private var serverUrl: String {
var serverUrl: String {
UserDefaults.standard.string(forKey: "silverapple.serverUrl") ?? ""
}

View File

@@ -28,7 +28,7 @@ final class PassportAuthService: NSObject, ObservableObject, ASWebAuthentication
let authUrl = buildAuthURL(challenge: challenge)
let callbackUrl = try await withCheckedThrowingContinuation { continuation in
let callbackUrl: URL = try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<URL, any Error>) in
let session = ASWebAuthenticationSession(url: authUrl, callbackURLScheme: "silverapple") { url, error in
if let error { continuation.resume(throwing: error); return }
guard let url else { continuation.resume(throwing: AuthError.noCallback); return }

View File

@@ -0,0 +1,16 @@
import SwiftUI
struct HardeningListView: View {
var body: some View {
NavigationStack {
List {
Section {
Label("Privacy hardening checks coming soon.", systemImage: "lock.shield")
.foregroundStyle(.secondary)
.font(.subheadline)
}
}
.navigationTitle("Hardening")
}
}
}

View File

@@ -15,7 +15,7 @@ struct MDMEnrollmentView: View {
VStack(spacing: 32) {
Image(systemName: "iphone.badge.play")
.font(.system(size: 56))
.foregroundStyle(.accentColor)
.foregroundStyle(Color.accentColor)
VStack(spacing: 12) {
Text("Device Management")

View File

@@ -0,0 +1,29 @@
import SwiftUI
struct ServerConfigView: View {
@EnvironmentObject var env: AppEnvironment
var body: some View {
NavigationStack {
List {
Section("Server") {
HStack {
Text("URL")
Spacer()
Text(env.serverUrl.isEmpty ? "Not configured" : env.serverUrl)
.foregroundStyle(.secondary)
.lineLimit(1)
.truncationMode(.middle)
}
}
Section {
Button("Sign Out", role: .destructive) {
env.authService.signOut()
}
}
}
.navigationTitle("Settings")
}
}
}

View File

@@ -11,13 +11,23 @@
"name": "SilverApple",
"bundleIdentifier": "uk.silverlabs.silverapple",
"developerName": "SilverLABS",
"downloadURL": "",
"downloadURL": "https://git.silverlabs.uk/SilverLABS/SilverApple/releases/download//SilverApple.ipa",
"subtitle": "Privacy companion for iOS",
"localizedDescription": "SilverApple integrates your device with the SilverLABS ecosystem — MDM enrollment, privacy hardening checks, and Passport authentication.",
"iconURL": "https://git.silverlabs.uk/SilverLABS/SilverApple/raw/branch/main/SilverApple/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png",
"tintColor": "00BBFF",
"category": "utilities",
"versions": []
"versions": [
{
"version": "",
"buildVersion": "",
"date": "2026-04-06T21:09:48Z",
"localizedDescription": "See release notes.",
"downloadURL": "https://git.silverlabs.uk/SilverLABS/SilverApple/releases/download//SilverApple.ipa",
"sha256": "30e7d3cdd5f5c6e88fbf16cfe20cf646f4ced79e84a8b321702861182744b83e",
"size": 91467
}
]
}
],
"news": []

View File

@@ -13,18 +13,26 @@ workflows:
environment:
xcode: latest
groups:
- SLABS
vars:
BUNDLE_ID: uk.silverlabs.silverapple
GITEA_REPO: SilverLABS/SilverApple
GITEA_API: https://git.silverlabs.uk/api/v1
# GITEA_TOKEN — set this in Codemagic App Settings → Environment variables (mark as secret)
scripts:
- name: Build archive (unsigned)
- name: Generate Xcode project
script: |
brew install xcodegen
xcodegen generate --spec project.yml
- name: Build (unsigned)
script: |
xcodebuild archive \
-project SilverApple.xcodeproj \
-scheme SilverApple \
-destination "generic/platform=iOS" \
-configuration Release \
-archivePath "$CM_BUILD_DIR/SilverApple.xcarchive" \
CODE_SIGNING_ALLOWED=NO \
CODE_SIGNING_REQUIRED=NO \
@@ -34,18 +42,34 @@ workflows:
- name: Package IPA
script: |
cd "$CM_BUILD_DIR"
APP=$(find SilverApple.xcarchive/Products -name "*.app" -type d | head -1)
if [ -z "$APP" ]; then
echo "ERROR: No .app found in xcarchive. Contents:"
find SilverApple.xcarchive -type d | head -30
exit 1
fi
echo "Packaging: $APP"
mkdir -p Payload
cp -r SilverApple.xcarchive/Products/Applications/SilverApple.app Payload/
cp -r "$APP" Payload/
zip -r SilverApple.ipa Payload/
rm -rf Payload
echo "IPA size: $(du -sh SilverApple.ipa | cut -f1)"
- name: Publish to Gitea
script: |
set -e
TAG="$CM_TAG"
set -exo pipefail
[ -n "$GITEA_TOKEN" ] || { echo "ERROR: GITEA_TOKEN is not set in Codemagic env vars"; exit 1; }
echo "TAG=$CM_TAG BUILD_DIR=$CM_BUILD_DIR"
echo "GITEA_API=$GITEA_API TOKEN_SET=yes"
TAG="${CM_TAG:-$(git tag --points-at HEAD | head -1)}"
[ -n "$TAG" ] || { echo "ERROR: could not determine tag"; exit 1; }
VERSION="${TAG#v}"
IPA="$CM_BUILD_DIR/SilverApple.ipa"
# Verify IPA exists
ls -lh "$IPA"
SHA256=$(shasum -a 256 "$IPA" | awk '{print $1}')
SIZE=$(wc -c < "$IPA" | tr -d ' ')
DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
@@ -64,27 +88,36 @@ workflows:
altstore-source.json > altstore-source.tmp.json
mv altstore-source.tmp.json altstore-source.json
# Commit and push updated source
git remote set-url origin "https://sysadmin:$GITEA_TOKEN@git.silverlabs.uk/$GITEA_REPO.git"
git config user.name "Codemagic"
git config user.email "ci@silverlabs.uk"
git add altstore-source.json
git commit -m "chore(altstore): update source for $TAG" || echo "No changes"
git push origin HEAD:main
# Get current file SHA from Gitea API
FILE_SHA=$(curl -s \
-H "Authorization: token $GITEA_TOKEN" \
"$GITEA_API/repos/$GITEA_REPO/contents/altstore-source.json" \
| jq -r '.sha')
echo "FILE_SHA=$FILE_SHA"
# Update altstore-source.json via Gitea contents API
CONTENT=$(base64 -i altstore-source.json | tr -d '\n')
curl -s -X PUT "$GITEA_API/repos/$GITEA_REPO/contents/altstore-source.json" \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"message\":\"chore(altstore): update source for $TAG\",\"content\":\"$CONTENT\",\"sha\":\"$FILE_SHA\",\"branch\":\"main\"}" \
| jq -r '.commit.sha // "FAILED"'
# Create Gitea release
RELEASE_ID=$(curl -sf -X POST "$GITEA_API/repos/$GITEA_REPO/releases" \
RELEASE_ID=$(curl -s -X POST "$GITEA_API/repos/$GITEA_REPO/releases" \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"tag_name\":\"$TAG\",\"name\":\"SilverApple $TAG\",\"body\":\"AltStore / SideStore release.\",\"draft\":false,\"prerelease\":false}" \
| jq -r '.id')
echo "RELEASE_ID=$RELEASE_ID"
# Upload IPA
curl -sf -X POST "$GITEA_API/repos/$GITEA_REPO/releases/$RELEASE_ID/assets" \
curl -s -X POST "$GITEA_API/repos/$GITEA_REPO/releases/$RELEASE_ID/assets" \
-H "Authorization: token $GITEA_TOKEN" \
-F "attachment=@$IPA;type=application/octet-stream"
-F "attachment=@$IPA;type=application/octet-stream" \
| jq -r '.name // "UPLOAD_FAILED"'
echo "Published release $TAG → $DOWNLOAD_URL"
echo "Done: $TAG → $DOWNLOAD_URL"
artifacts:
- $CM_BUILD_DIR/SilverApple.ipa

43
project.yml Normal file
View File

@@ -0,0 +1,43 @@
name: SilverApple
options:
bundleIdPrefix: uk.silverlabs
deploymentTarget:
iOS: "16.0"
xcodeVersion: "15"
generateEmptyDirectories: true
targets:
SilverApple:
type: application
platform: iOS
deploymentTarget: "16.0"
sources:
- path: SilverApple
excludes:
- Info.plist
- SilverApple.entitlements
resources:
- SilverApple/Assets.xcassets
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: uk.silverlabs.silverapple
INFOPLIST_FILE: SilverApple/Info.plist
CODE_SIGN_ENTITLEMENTS: SilverApple/SilverApple.entitlements
SWIFT_VERSION: "5.9"
TARGETED_DEVICE_FAMILY: "1,2"
OTHER_LDFLAGS:
- "-framework AuthenticationServices"
- "-framework SafariServices"
- "-framework Security"
SilverAppleTests:
type: bundle.unit-test
platform: iOS
deploymentTarget: "16.0"
sources:
- path: SilverAppleTests
dependencies:
- target: SilverApple
settings:
base:
SWIFT_VERSION: "5.9"