commit b289e84e408faecb4a5a46368dff5739abd74aeb
parent a3f84c5fbded9fb4fdda9197b529af9ad4bf8795
Author: Michael Camilleri <[email protected]>
Date: Sun, 1 Mar 2026 13:24:58 +0900
Update instructions in AGENTS.md
The instructions for uploading to TestFlight were incomplete. This adds
additional information.
Co-Authored-By: Codex GPT 5.3 <[email protected]>
Diffstat:
| M | AGENTS.md | | | 96 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ |
1 file changed, 74 insertions(+), 22 deletions(-)
diff --git a/AGENTS.md b/AGENTS.md
@@ -23,36 +23,88 @@
## TestFlight Release (asc CLI)
- Use `asc` for App Store Connect/TestFlight automation.
-- In this repo, `asc` auth is stored in `./.asc/config.json` and keychain lookups may fail; run commands with `ASC_BYPASS_KEYCHAIN=1`.
+- In this repo, `asc` auth is stored in `./.asc/config.json` (local file auth); `ASC_BYPASS_KEYCHAIN=1` is not needed for normal commands.
+- In sandboxed coding-agent environments, `asc` may fail with `dial tcp: lookup api.appstoreconnect.apple.com: no such host`; this means outbound network is blocked and the command must be re-run with unrestricted network permissions.
- Listless app identifier in App Store Connect: `6759801710` (bundle ID `net.inqk.listless`).
- Internal beta group currently used: `Personal` (`bc458e15-2743-471c-a16d-c25fb88e07de`).
- Build numbers come from scheme pre-action (`YEAR.COMMIT_COUNT`), so archiving from latest `HEAD` produces the latest-commit build.
### One-time auth setup
- `asc auth login --bypass-keychain --local --name "listless-asc-cli" --key-id "<KEY_ID>" --issuer-id "<ISSUER_ID>" --private-key "./Generated/AuthKey_<KEY_ID>.p8"`
-- Verify: `ASC_BYPASS_KEYCHAIN=1 asc apps list --limit 5 --output table`
-
-### Build latest-commit IPA
-- `xcodebuild -scheme "Listless iOS" -project Listless.xcodeproj -configuration Release -destination 'generic/platform=iOS' -archivePath /tmp/Listless-latest.xcarchive archive`
-- Write export options plist at `/tmp/Listless-ExportOptions.plist` with:
- - `method=app-store`
- - `signingStyle=automatic`
- - `destination=export`
- - `stripSwiftSymbols=true`
- - `manageAppVersionAndBuildNumber=false`
-- Export IPA:
- - `xcodebuild -exportArchive -archivePath /tmp/Listless-latest.xcarchive -exportPath /tmp/Listless-export -exportOptionsPlist /tmp/Listless-ExportOptions.plist`
-- IPA path: `/tmp/Listless-export/Listless iOS.ipa`
-
-### Publish to internal TestFlight
-- `ASC_BYPASS_KEYCHAIN=1 asc publish testflight --app 6759801710 --ipa '/tmp/Listless-export/Listless iOS.ipa' --group bc458e15-2743-471c-a16d-c25fb88e07de --wait --output table`
-- Do not pass `--notify` for this internal-group flow (ASC rejects it).
-- Do not rely on manual internal group assignment commands for this group; internal availability is reflected in build beta state.
+- Verify: `asc apps list --limit 5 --output table`
+- If auth/debug seems broken, run: `asc auth doctor`
+
+### Temporary keychain workaround (headless signing, less-intrusive)
+- Use this when export fails with `No Accounts`, missing distribution cert errors, or `errSecInternalComponent`.
+- Goal: avoid changing default keychain; only add a temporary keychain to the user search list.
+- Create/unlock temp keychain and import signing `.p12` identities:
+ - `security create-keychain -p "<PASS>" "<TMP_KEYCHAIN_PATH>"`
+ - `security unlock-keychain -p "<PASS>" "<TMP_KEYCHAIN_PATH>"`
+ - `security set-keychain-settings -lut 21600 "<TMP_KEYCHAIN_PATH>"`
+ - `security import "<CERT>.p12" -k "<TMP_KEYCHAIN_PATH>" -P "<P12_PASS>" -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild`
+ - `security set-key-partition-list -S apple-tool:,apple:,codesign:,productbuild: -s -k "<PASS>" "<TMP_KEYCHAIN_PATH>"`
+- Prepend temp keychain in search list, keep login as default:
+ - `security list-keychains -d user -s "<TMP_KEYCHAIN_PATH>" "$HOME/Library/Keychains/login.keychain-db"`
+ - `security default-keychain -d user -s "$HOME/Library/Keychains/login.keychain-db"`
+- After export/upload, restore normal user keychain list:
+ - `security list-keychains -d user -s "$HOME/Library/Keychains/login.keychain-db"`
+ - `security default-keychain -d user -s "$HOME/Library/Keychains/login.keychain-db"`
+
+### iOS TestFlight (internal group)
+1. Archive iOS app from latest commit:
+ - `xcodebuild -scheme "Listless iOS" -project Listless.xcodeproj -configuration Release -destination 'generic/platform=iOS' -archivePath /tmp/Listless-latest.xcarchive archive`
+2. Export IPA (App Store Connect method):
+ - Write `/tmp/Listless-ExportOptions.plist` with:
+ - `method=app-store-connect`
+ - `signingStyle=automatic`
+ - `teamID=7TD7PZBNXP`
+ - `destination=export`
+ - `stripSwiftSymbols=true`
+ - `manageAppVersionAndBuildNumber=false`
+ - Export:
+ - `xcodebuild -exportArchive -archivePath /tmp/Listless-latest.xcarchive -exportPath /tmp/Listless-export -exportOptionsPlist /tmp/Listless-ExportOptions.plist`
+ - IPA path: `/tmp/Listless-export/Listless iOS.ipa`
+3. Upload + publish:
+ - `asc publish testflight --app 6759801710 --ipa '/tmp/Listless-export/Listless iOS.ipa' --group bc458e15-2743-471c-a16d-c25fb88e07de --wait --output table`
+4. Notes:
+ - If local distribution signing is required, apply the temporary keychain workaround before `xcodebuild -exportArchive`.
+ - Do not pass `--notify` for this internal-group flow.
+ - If `publish testflight` returns `Cannot add internal group to a build`, treat it as non-fatal; verify with build beta detail (`internalBuildState`).
+
+### macOS TestFlight (internal group, headless)
+1. Archive macOS app from latest commit:
+ - `xcodebuild -scheme "Listless macOS" -project Listless.xcodeproj -configuration Release -destination 'generic/platform=macOS' -archivePath /tmp/Listless-mac-latest.xcarchive archive`
+2. Ensure macOS App Store signing identities exist locally:
+ - Required cert identities during export:
+ - `3rd Party Mac Developer Application`
+ - `3rd Party Mac Developer Installer`
+ - Keep `login.keychain-db` as default (less intrusive). Import certs there if needed.
+3. Export App Store `.pkg`:
+ - Use manual export options with:
+ - `method=app-store-connect`
+ - `signingStyle=manual`
+ - `teamID=7TD7PZBNXP`
+ - `signingCertificate=3rd Party Mac Developer Application`
+ - `installerSigningCertificate=3rd Party Mac Developer Installer`
+ - `provisioningProfiles.net.inqk.listless=<MAC_APP_STORE profile name>`
+ - Run:
+ - `xcodebuild -exportArchive -archivePath /tmp/Listless-mac-latest.xcarchive -exportPath /tmp/Listless-mac-export-<TS> -exportOptionsPlist /tmp/Listless-mac-ExportOptions-<TS>.plist`
+ - PKG path: `/tmp/Listless-mac-export-<TS>/Listless.pkg`
+4. Upload `.pkg` with Transporter CLI (`iTMSTransporter`):
+ - `xcrun iTMSTransporter -m upload -assetFile '/tmp/Listless-mac-export-<TS>/Listless.pkg' -apiKey '<KEY_ID>' -apiIssuer '<ISSUER_ID>' -v informational`
+ - Place `AuthKey_<KEY_ID>.p8` under `./private_keys/` (or one of Transporter’s default private key directories) so `-apiKey` auth resolves.
+5. Known asc limitation:
+ - In `asc` v0.36.0, `asc builds upload --pkg` can fail with `uti` mismatch (`com.apple.installer-package-archive` vs expected `com.apple.pkg`). Prefer Transporter upload for macOS.
+6. Verify internal TestFlight state:
+ - `asc builds find --app 6759801710 --build-number '<YEAR.COMMIT_COUNT>' --platform MAC_OS --output table`
+ - `asc builds build-beta-detail get --build '<BUILD_ID>' --output json --pretty`
+ - Success criterion: `"internalBuildState": "IN_BETA_TESTING"`.
+ - If key access/signing fails during export, apply the temporary keychain workaround first.
### Verify upload/distribution state
-- Latest build: `ASC_BYPASS_KEYCHAIN=1 asc builds latest --app 6759801710 --output table`
-- Specific build: `ASC_BYPASS_KEYCHAIN=1 asc builds find --app 6759801710 --build-number "<YEAR.COMMIT_COUNT>" --output table`
-- Internal state: `ASC_BYPASS_KEYCHAIN=1 asc builds build-beta-detail get --build "<BUILD_ID>" --output json --pretty`
+- Latest build: `asc builds latest --app 6759801710 --output table`
+- Specific build: `asc builds find --app 6759801710 --build-number "<YEAR.COMMIT_COUNT>" --output table`
+- Internal state: `asc builds build-beta-detail get --build "<BUILD_ID>" --output json --pretty`
- Success criterion for internal TestFlight: `"internalBuildState": "IN_BETA_TESTING"`.
## Build Number