development
md 120 lines 6.74 KB
Rendered Raw
1 # smbcloud-ascapi — upload + signing-identity hardening: plan (closed)
2
3 Findings from the **Siti AI** release session (macOS App Store upload of
4 `Siti AI.pkg` through App Store Connect). Repo:
5 `github.com:smbcloudXYZ/smbcloud-ascapi`, base branch `development`, remote
6 `setoelkahfi` (there is no `origin`, so use `git`/`gh`, not the sigit MCP
7 tools).
8
9 Companion plan: [`feature-plan-from-klepon-xcode-release-session.md`](./feature-plan-from-klepon-xcode-release-session.md)
10 — that session shipped the builds API + token-source + altool-upload stack
11 (gh stack #6→#7→#8→#10). Both have now closed out.
12
13 **Closed-out progress (2025-10-11, this session):** gh stack #27
14 (bottom→top) #24 `docs/list-builds-pagination` → #25 `feat/signing-doctor`
15 → #26 `feat/apps-await-processing`, rebased onto `development`, all
16 CI-clean (fmt / clippy `-D warnings` / test / `RUSTDOCFLAGS=-D warnings`
17 doc / lower-crate solo builds), signed+verified, auto-merge enabled.
18 This landed finding **#2** (signing doctor), finding **#5**
19 (await-processing), and finding **#6** (list_builds pagination doc).
20
21 **Closed-out progress (later):** the `upload.rs` cluster
22 (findings #1, #3, #4 — pre-flight `--validate-app`, body-aware
23 `success`, `.app`-vs-`.pkg` distinction) shipped together on the same
24 file, sharing the test scaffolding that already covered `altool_args`.
25 Every finding from this plan is now in `development`.
26
27 - Both sessions hit the same root pain: a **stale private key / signing
28 identity with the right id but wrong contents**, which surfaces as an
29 indistinguishable 401 (klepon plan, "Separate / unaddressed bug") or, in
30 this session, ~20 min lost to a stale `SIGNING_IDENTITY` in
31 `.env.appstore`. `ascapi apps upload` already dodges the *key* half by
32 passing `--p8-file-path` (klepon #10); the *local signing identity* half
33 (finding #2 below) is now covered by `asc signing doctor`.
34 - Klepon's open "Live smoke test against ASC" item is the natural place to
35 also exercise findings #1 and #3 once implemented. **Still blocked on
36 credentials.**
37
38 ## Session context
39
40 - Uploaded a macOS build (`Siti AI.pkg`) to ASC successfully. The time sink
41 was a stale `SIGNING_IDENTITY` in `.env.appstore` — nothing in ascapi
42 inspects the local keychain, so the tool gave no signal it was stale.
43 - `ascapi` *does* own upload + TestFlight/review orchestration (`asc apps
44 upload`, `xcrun altool`). It cannot build or sign — out of scope by
45 design. The findings below stay inside what ascapi already owns.
46
47 ## Findings
48
49 ### 1. No pre-upload `altool --validate-app` pass — HIGH ✅ SHIPPED
50 `frontend::upload::validate_app` (added in
51 `crates/frontend/src/upload.rs`) is now a *server-side* check: it runs
52 `xcrun altool --validate-app` with the same `--p8-file-path` auth parity
53 as the upload path, surfacing Apple's JSON verdict. Reachable from the CLI
54 as `asc apps validate <pkg>`. `--wait` is deliberately not passed on the
55 validation path — validation is already synchronous.
56 - **Value:** turns a ~minutes-late failure into a seconds-early one; catches
57 the common "wrong version / bad entitlement" class before upload.
58
59 ### 2. No local-keychain `signing doctor` — HIGH ✅ SHIPPED (PR #25)
60 The `signing` crate (`certificate.rs`, `profile.rs`, `csr.rs`) talks **only
61 to the ASC REST API**. `security find-identity` is called nowhere in the
62 repo; there is no local-keychain code at all. So the exact stale-identity
63 problem this session hit (and the klepon 401 key-drift bug) has **zero
64 coverage**: ascapi can tell you what certs/profiles *Apple* has, but not
65 what's installed and valid locally, nor whether they line up.
66 - **Fix:** add `asc signing doctor` that runs `security find-identity -v
67 -p codesigning`, lists local valid signing identities, and cross-checks
68 them against the certificates the ASC API reports
69 (`CertificateApi::list_certificates`) — flagging identities that are
70 expired, missing locally, or present locally but revoked/absent on Apple.
71 Optionally resolve the `.p8` the CLI would use and confirm it exists and
72 is readable.
73 - **Value:** directly closes the gap that cost ~20 min this session and is
74 the local half of klepon's key-drift bug. Bigger surface (new keychain
75 interaction, macOS-only) → its own branch.
76
77 ### 3. `success` trusts the exit code, not the JSON body — HIGH ✅ SHIPPED
78 `outcome()` (`crates/frontend/src/upload.rs`) now derives `success` from
79 exit code **and** the parsed body — a non-empty `product-errors` /
80 `product_errors` / `errors` array under any of altool's key spellings
81 counts as failure even on exit 0. Exit code stays in `UploadOutcome` for
82 debugging.
83 - **Value:** small, same-file change; removes false "success" reports.
84
85 ### 4. `.app`-vs-`.pkg` gives a generic "does not exist" — MEDIUM ✅ SHIPPED
86 In `validate_package`, a `.app` **bundle** (a directory) now hits a
87 precise message: *"this is an .app bundle, not an uploadable package;
88 export the archive first (`xcodebuild -exportArchive`) to get an
89 .ipa/.pkg"*. A bare directory still reports "is a directory, not a
90 package file" so "path missing" and "wrong kind" stay distinct.
91 - **Value:** tiny, same-file, removes a recurring confusing error.
92
93 ### 5. No non-blocking `await-processing` loop — MEDIUM ✅ SHIPPED (PR #26)
94 The only way to wait for ASC to finish processing a build is altool's
95 `--wait`, which blocks the altool process for the whole duration. There's
96 no poll-based path that uses the builds API (`BuildsApi::list_builds`,
97 shipped in klepon #8) to report processing state incrementally or let the
98 caller poll on its own cadence.
99 - **Fix:** add `asc apps await-processing <build-id|--build-number>` that
100 polls `/v1/builds` for `processingState` until `VALID`/`FAILED`/timeout,
101 with backoff. Complements klepon's builds API; an MCP-friendly
102 alternative to a blocking `--wait`.
103 - **Value:** better UX for CI/agents; builds on existing klepon surface.
104 - **Shipped (PR #26):** `asc apps await-processing <APP_ID>` with
105 `--version`, `--pre-release-version`, `--interval` (30s),
106 `--timeout` (1800s). Shared poll loop + pure `classify()` /
107 `AwaitConfig` / `AwaitOutcome` in `crates/frontend/src/await_processing.rs`
108 (serializes without key material; 7 in-module tests). Terminal map:
109 VALID → success, INVALID/FAILED → failure, else timeout → non-zero exit.
110 CLI-only for now; the pure core is MCP-ready if a tool is added later.
111
112 ### 6. `list_builds` limit=200 pagination — LOW (doc-only) ✅ SHIPPED (PR #24)
113 `list_builds` caps at limit=200 with no cursor follow-through. Fine for
114 normal apps; note it as a known limit. Overlaps klepon's open "MCP
115 `list_builds` doesn't expose `BuildFilter`" item — fold into that rather
116 than tracking separately.
117
118 ## Status
119 Closed. All six findings merged. The only remaining item is the live ASC
120 smoke test, shared with the klepon plan and credential-blocked.