Skip to content

asc v0.17.8

Choose a tag to compare

@github-actions github-actions released this 29 Apr 12:22
· 143 commits to main since this release

Added

  • asc iris iap-submissions delete --submission-id <id> — iris-side dequeue of an IAP submission (DELETE /iris/v1/inAppPurchaseSubmissions/{id}). Iris-queued submissions don't round-trip through the public-SDK delete; they can only be removed via this iris-cookie-authed path. New IrisClient.delete, new IrisInAppPurchaseSubmissionRepository.deleteSubmission(session:submissionId:). REST equivalent: DELETE /api/v1/iris/iap-submissions/:submissionId on IrisIAPSubmissionsController. removeFromNextVersion affordance now resolves end-to-end through iris (CLI: asc iris iap-submissions delete --submission-id <id>; REST: DELETE /api/v1/iris/iap-submissions/<id>). RESTPathResolver.resourcePath now converts spaces in segment names to slashes so multi-word commands like iris iap-submissions produce clean URL segments. Removed the short-lived public-SDK alias POST /api/v1/iap/:iapId/unsubmit (incorrect — public DELETE doesn't accept iris-queued submissions).
  • removeFromNextVersion affordance on queued IAPs — when an IAP is in READY_TO_SUBMIT and Apple's iris listing reports submitWithNextAppStoreVersion: true (queued to ride along with the next app version), InAppPurchase.structuredAffordances surfaces removeFromNextVersion → asc iap unsubmit --submission-id <iapId> and suppresses the submit affordance (mutually exclusive — Apple rejects re-submits on already-queued IAPs). The dequeue uses the existing public-SDK DELETE /v1/inAppPurchaseSubmissions/{id} (Apple's iris flow keys the submission resource by parent IAP id, so --submission-id <iapId> works). Underpinned by a new best-effort iris enrichment: IrisSDKInAppPurchaseStateRepository calls GET /iris/v1/apps/:appId/inAppPurchasesV2?fields[inAppPurchases]=submitWithNextAppStoreVersion&filter[state]=READY_TO_SUBMIT, mapping each IAP to its queued bit. SDKInAppPurchaseRepository.listInAppPurchases accepts an optional irisFlagsProvider closure; the factory wires it from IrisCookieProvider + IrisSDKInAppPurchaseStateRepository. CI scripts using API-key auth keep their existing JSON output (flag stays false, no removeFromNextVersion affordance). New InAppPurchase.submitWithNextAppStoreVersion: Bool field, encoded only when true to avoid snapshot churn. New IrisInAppPurchaseStateRepository @Mockable Domain protocol.

Changed

  • InAppPurchase submission affordances reorganized into iris-queue family vs. public-SDK direct submit. Two inverse pairs, all gated on state == .readyToSubmit:
    • addToNextVersion (NEW) → asc iris iap-submissions create --iap-id <id> — queues the IAP to ride along with the next App Store version submission. Always available for ready, not-yet-queued IAPs.
    • removeFromNextVersion → asc iap unsubmit --submission-id <iapId> — dequeues. Mutually exclusive with the others; emitted only when iris listing reports submitWithNextAppStoreVersion: true.
    • submit → asc iap submit --iap-id <id> — public-SDK direct submit (standalone review). Now emitted only when isFirstTimeSubmission == false (Apple rejects the direct path for the first IAP for an app).
    • Established-app ready IAPs see both submit and addToNextVersion; agent picks based on release strategy.
    • Replaces the previous behavior where submit quietly auto-dispatched between iris and public SDK paths — keys are now explicit about what each call does. New InAppPurchaseState.hasBeenApproved semantic boolean. New iris iap-submissions REST route registered with the path resolver so addToNextVersion _links resolve to /api/v1/iris/iap/<id>/submissions.

Added

  • asc iris iap-submissions create --iap-id <id> — IAP submission via the iris private API — closes the parity gap with the public SDK's POST /v1/inAppPurchaseSubmissions, which has no attributes field and therefore can't carry submitWithNextAppStoreVersion. The new command posts to POST /iris/v1/inAppPurchaseSubmissions with that attribute set, which is required for first-time IAP submissions (Apple binds the first IAP to the next App Store version). Defaults to --with-next-version; pass --no-with-next-version to opt out. Lives under asc iris … because it needs iris cookies (either browser cookies or a session from asc iris auth login). Surfaced via IrisStatus.affordances.submitIAP so asc iris status advertises the path when authenticated. Existing asc iap submit stays untouched — CI scripts using key-auth keep working unchanged. See docs/features/iap-subscriptions/submission-iris-parity.md.
  • REST: POST /api/v1/iris/iap/:iapId/submissions — body {"submitWithNextAppStoreVersion": true} (default true); returns the submission resource with _links.viewIAP pointing back at the public IAP endpoint.

Fixed

  • iris 2FA verify-code no longer 401s with a valid code — IdmsaAPIClient.applyHeaders was sending X-Apple-OAuth-Client-Id, X-Apple-OAuth-Redirect-URI, X-Apple-OAuth-Response-Mode, X-Apple-OAuth-Response-Type, Origin, and Referer on signin/init and signin/complete. None of XcodesOrg/XcodesApp, XcodesOrg/XcodesLoginKit, or the rorkai/App-Store-Connect-CLI Go reference send those — they taint the SRP session so the post-409 GET /appleauth/auth returns 401, rotates scnt, and the subsequent POST /verify/trusteddevice/securitycode is rejected as out-of-sequence. Header set is now narrowed to Accept, Content-Type, X-Requested-With, X-Apple-Widget-Key, scnt, X-Apple-ID-Session-Id (+ X-Apple-HC on signin/complete). signinComplete also flips to ?isRememberMeEnabled=false with body rememberMe: false to match the same references — true puts Apple in the "trust this browser" path, which mismatches a CLI session.

Added

  • asc iris auth login / verify-code / logout — Apple ID SRP login for the iris private API — until now iris features (asc iris apps list, asc iris status) only worked when the user had logged into App Store Connect in their browser; we'd borrow cookies from there. Headless CI had no path. The new command performs a full Apple SRP-6a handshake against idmsa.apple.com, handles 2FA (trusted-device push or phone code), then persists the resulting session to ~/.asc/iris/session.json (0600 perms). New CompositeIrisCookieProvider chains SRP-stored cookies before browser cookies, so any existing iris command immediately picks up the SRP session without code changes elsewhere. See docs/features/iris/iris-srp-login.md.
    • asc iris auth login --apple-id user@example.com — prompts for password on stdin, runs SRP, persists session on success or pending-2FA state on 409.
    • asc iris auth verify-code 123456 — submits the 2FA code, calls 2sv/trust, fetches olympus/v1/session for team metadata, persists the full session.
    • asc iris auth logout — deletes the persisted session.
    • ASC_IRIS_DEBUG=1 — dumps every idmsa request/response to stderr with a/m1/m2 redacted, so failures self-capture safely-shareable test data.
    • Built on adam-fowler/swift-srp (Apache 2.0) for RFC 5054 group-2048 constants, BigNum, and key generation. Apple's PBKDF2-derived x is layered on top in AppleSRPClient. PBKDF2-HMAC-SHA256 implementation cross-checked against RFC 7914 §11 vectors.
    • Caveat: while every layer is unit-tested with mocked HTTP and synthesized vectors, real-world correctness against Apple's specific M1 shape gets validated only on the first real login attempt. If Apple's protocol shifts, expect churn here.