Private
Public Access
1
0

17 Commits
v0.1.0 ... main

Author SHA1 Message Date
cdc40774c4 fix(ci): switch to signed IPA build via APPLE_SIGNING group
Replace unsigned CODE_SIGNING_ALLOWED=NO build with proper ad-hoc
signed archive using keychain, certificate, and provisioning profile.
Update xtool.yml schema to match current xtool v1 format.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:27:54 +01:00
5847294a80 feat(sidestore): add SilverLABS anisette server list 2026-04-07 20:21:51 +00:00
343481d053 chore(altstore): remove stale empty-version entry from failed build 2026-04-06 22:27:00 +01:00
13a3dc4890 chore(altstore): update source for v0.1.1 2026-04-06 21:22:42 +00:00
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
11 changed files with 201 additions and 42 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/v0.1.1/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": "0.1.1",
"buildVersion": "0.1.1",
"date": "2026-04-06T21:22:41Z",
"localizedDescription": "See release notes.",
"downloadURL": "https://git.silverlabs.uk/SilverLABS/SilverApple/releases/download/v0.1.1/SilverApple.ipa",
"sha256": "fa2004dee56567a11b134461bc3736417a2f84f015bf2944e6872fda020e0399",
"size": 91467
}
]
}
],
"news": []

View File

@@ -13,39 +13,85 @@ workflows:
environment:
xcode: latest
groups:
- SLABS
- APPLE_SIGNING
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: Initialize keychain
script: keychain initialize
- name: Install signing certificate
script: |
echo $CM_CERTIFICATE | base64 --decode > /tmp/cert.p12
keychain add-certificates \
--certificate /tmp/cert.p12 \
--certificate-password $CM_CERTIFICATE_PASSWORD
- name: Install provisioning profile
script: |
echo $CM_PROVISIONING_PROFILE | base64 --decode > /tmp/profile.mobileprovision
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
cp /tmp/profile.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/
- name: Configure Xcode signing
script: xcode-project use-profiles
- name: Build (signed)
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 \
CODE_SIGN_IDENTITY="" \
PROVISIONING_PROFILE=""
DEVELOPMENT_TEAM="$APPLE_TEAM_ID" \
CODE_SIGN_STYLE=Manual
- name: Package IPA
- name: Export signed IPA
script: |
cd "$CM_BUILD_DIR"
mkdir -p Payload
cp -r SilverApple.xcarchive/Products/Applications/SilverApple.app Payload/
zip -r SilverApple.ipa Payload/
rm -rf Payload
echo "IPA size: $(du -sh SilverApple.ipa | cut -f1)"
cat > /tmp/ExportOptions.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>ad-hoc</string>
<key>signingStyle</key>
<string>manual</string>
</dict>
</plist>
EOF
xcodebuild -exportArchive \
-archivePath "$CM_BUILD_DIR/SilverApple.xcarchive" \
-exportPath "$CM_BUILD_DIR/export" \
-exportOptionsPlist /tmp/ExportOptions.plist
cp "$CM_BUILD_DIR/export/SilverApple.ipa" "$CM_BUILD_DIR/SilverApple.ipa"
- 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 +110,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"

8
servers.json Normal file
View File

@@ -0,0 +1,8 @@
{
"servers": [
{
"name": "SilverLABS Anisette",
"address": "https://anisette.silverlabs.uk"
}
]
}

View File

@@ -1,13 +1,8 @@
# xTool configuration — https://xtool.sh
# Run `xtool configure` once to set up your Apple ID credentials and Darwin SDK.
# Then: `xtool run` to build and install directly to a connected device.
# Run `xtool setup` once to configure your Apple ID credentials and extract the Darwin SDK.
# Then: `xtool dev` to build and deploy directly to a connected USB device.
targets:
SilverApple:
bundleIdentifier: uk.silverlabs.silverapple
# Fill in your Apple Developer Team ID (10-char string from developer.apple.com)
teamID: ""
infoPlist: SilverApple/Info.plist
entitlements: SilverApple/SilverApple.entitlements
deploymentTarget: "16.0"
deviceFamily: [iphone]
version: 1
bundleID: uk.silverlabs.silverapple
infoPath: SilverApple/Info.plist
entitlementsPath: SilverApple/SilverApple.entitlements