Skip to content

How it works ​

Three ways to run ​

runAudit() branches three ways depending on what you’ve given it:

ModeTriggerWhat runs
LiveCredentials configured (.p8 + Key ID + Issuer ID)The full App Store Connect API sweep, plus local project analysis, plus bundle-id / version cross-checks.
Local-onlyA project selected, no credentialsOnly the local static analysis checks (see Xcode Project).
DemoNeitherA bundled fixture (CircleMind sample) so you can explore the UI offline.

Authentication ​

  • Base URL: https://api.appstoreconnect.apple.com/v1.
  • Auth is a JWT bearer token, algorithm ES256, signed with your downloaded .p8 private key using Apple’s CryptoKit (P256.Signing).
  • Tokens are capped by Apple at 20 minutes; AuditStore uses ~19 and caches the token in memory, regenerating when it’s older than ~15 minutes.
  • You generate the key in App Store Connect → Users and Access → Integrations → App Store Connect API (needs Admin or App Manager role). The .p8 can only be downloaded once.

The API is JSON:API. Responses carry data, attributes, and relationships — and each relationship carries a full links.related URL.

AuditStore follows those relationship links rather than hardcoding nested endpoint paths. This keeps the app working even if Apple reshuffles secondary endpoints. The entry point is a single lookup:

GET /apps?filter[bundleId]=<your bundle id>

From that one app record, every other section is reached by following links: appInfos, appStoreVersions, appPriceSchedule, subscriptionGroups, and so on.

How a check can’t lie ​

A check that can’t be evaluated becomes an .errored row carrying the raw App Store Connect message. It never crashes, and — critically — it never silently passes. An unevaluated section is surfaced as an error, not a green check.

  • 401 / auth failure on the entry-point lookup blocks every ASC-derived section with the same error, rather than leaving them misleadingly empty.
  • 404 usually means not created yet — often a finding, not a crash.
  • Explicit JSON null is distinguished from an absent key.

The scan lifecycle ​

The live run advances through ordered stages so the progress UI moves monotonically:

  1. Authenticating — sign the JWT, look up the app by bundle id.
  2. Fetching metadata — app info, age rating, privacy, category, pricing, encryption.
  3. Screenshots — per-locale metadata and screenshot sets for the latest editable version.
  4. Subscriptions — subscription groups (if enabled in settings).
  5. Build & compliance — attached build, processing state, export compliance, and review details.
  6. Compiling — aggregate into the final Report.

Local static analysis ​

The macOS sandbox can’t spawn xcodebuild, so the analyzer parses project.pbxproj directly (via PropertyListSerialization, which reads the OpenStep format) and walks your Swift/ObjC sources (bounded to 600 files to stay responsive). It resolves the Release build settings for the app target and:

  • Detects privacy-sensitive API usage and cross-checks it against your Info.plist purpose strings and your App Privacy declaration.
  • Infers an app-type profile (login, tracking, IAP, account system) that gates the Review Guidelines checklist.
  • Cross-checks the project’s bundle id and marketing version against the live App Store Connect app.

If a build setting can’t be statically resolved (an .xcconfig base, or unexpanded $(…) variables), the analyzer emits an Info caveat instead of confidently passing or mis-detecting.


Next: Checks →

AuditStore is a macOS app by NativLab. Runs entirely on your Mac — your API private key never leaves your device.