Skip to content

fix(signing): exact App ID resolution + regenerate stale profiles on the build path (#291, #292)#293

Merged
YosefHayim merged 1 commit into
mainfrom
fix/291-292-signing-resolution
Jul 2, 2026
Merged

fix(signing): exact App ID resolution + regenerate stale profiles on the build path (#291, #292)#293
YosefHayim merged 1 commit into
mainfrom
fix/291-292-signing-resolution

Conversation

@YosefHayim

@YosefHayim YosefHayim commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Summary

Two signing-resolution bugs found while verifying the #289 multi-target fix on a live widget app.

Closes #291. Closes #292.

#291findBundleId resolved the wrong App ID for multi-target apps

Apple's filter[identifier] is a substring match, so findBundleId('com.acme.app') also matched com.acme.app.widget, and limit=1 + data[0] could return the widget's App ID. findBundleId now fetches the matches and selects the exact identifier (limit raised off 1 so the exact row isn't paginated away behind its siblings). This is on the critical path for ensureAppStoreProfileForBundle, which otherwise bound the main app's provisioning profile to the widget's App ID resource.

#292launch build reused a stale profile; only setup self-healed

The setup path guards reuse with profileStaleAgainstCapabilities (#261), but the build path reused credentials.signing blind. resolveSigning now grades each cached profile (main + every extensionProfiles entry) against its App ID's live capabilities via the new staleCachedSigningTargets, and regenerates a stale set instead of dying at exit 65. Best-effort and network-bound — a flaky lookup or off-Mac decode grades the target as current, so reuse stands (staleness only ever forces a regenerate, never blocks one). Extracted into reuseCachedSigning to keep resolveSigning under the complexity cap.

Tests

  • findBundleId: picks the exact row when the substring filter also returns child bundle ids; null when only siblings match.
  • staleCachedSigningTargets: flags a stale main + extension, [] when covered, best-effort on unreadable/unregistered targets, main-only when the app has no extensions.

Validation

npm run typecheck && npm run lint && npm run test && npm run build — all green (1974 tests). README / llms.txt / commands test-count badge regenerated.

🤖 Generated with Claude Code


Summary by cubic

Fixes two signing bugs: exact App ID matching for multi-target apps and automatic regeneration of stale provisioning profiles during builds. Prevents binding profiles to the wrong App ID and avoids exit 65 by checking capabilities before reuse.

  • Bug Fixes
    • findBundleId: select the exact identifier and raise the query limit to 200 to avoid substring collisions (e.g., app vs widget).
    • Build path: check cached profiles (main + extensions) against live App ID capabilities; regenerate stale profiles instead of reusing them. Best-effort and skipped under --dry-run. Extracted into staleCachedSigningTargets and reuseCachedSigning.

Written for commit 363044c. Summary will update on new commits.

Review in cubic

…the build path (#291, #292)

findBundleId resolved the wrong App ID for multi-target apps: Apple's filter[identifier]
is a substring match, so a query for com.acme.app also returned com.acme.app.widget and
data[0] could be the widget. Select the exact identifier and raise the limit off 1. This
also fixes ensureAppStoreProfileForBundle binding the main app's profile to the widget's
App ID (#291).

launch build reused a cached profile without checking staleness — only setup self-healed.
resolveSigning now grades each cached profile (main + every extension) against its App ID's
live capabilities via staleCachedSigningTargets before silent reuse, and regenerates a stale
set instead of failing the archive at exit 65. Best-effort and network-bound, mirroring
warnUnreadySigningTargets: a flaky read or off-Mac decode grades as current so reuse stands (#292).

7 unit tests; README/llms/commands test-count badge regenerated (1967 -> 1974).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jul 2, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 363044c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@YosefHayim, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 27 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 42a78fae-b791-47d4-89be-d214a12a8957

📥 Commits

Reviewing files that changed from the base of the PR and between 62b22da and 363044c.

📒 Files selected for processing (16)
  • README.de.md
  • README.es.md
  • README.fr.md
  • README.ja.md
  • README.ko.md
  • README.md
  • README.pt-BR.md
  • README.ru.md
  • README.zh-CN.md
  • docs/commands.md
  • llms.txt
  • src/apple/ascClient.test.ts
  • src/apple/ascClient.ts
  • src/apple/credentials.test.ts
  • src/apple/credentials.ts
  • src/core/pipeline.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/291-292-signing-resolution

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@YosefHayim
YosefHayim merged commit f08bc16 into main Jul 2, 2026
13 checks passed
@YosefHayim
YosefHayim deleted the fix/291-292-signing-resolution branch July 2, 2026 17:43

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 16 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/apple/ascClient.ts">

<violation number="1" location="src/apple/ascClient.ts:984">
P2: `findBundleId` can still return `null` for an existing bundle ID when more than 200 `filter[identifier]` matches are present, because only the first page is searched. Using `requestAll` here would fully close the pagination edge case this change is addressing.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/apple/ascClient.ts
const { data } = await this.request<ResourceList<{ identifier: string; seedId?: string }>>(
'GET',
`/bundleIds?filter[identifier]=${encodeURIComponent(identifier)}&limit=1`,
`/bundleIds?filter[identifier]=${encodeURIComponent(identifier)}&limit=200`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: findBundleId can still return null for an existing bundle ID when more than 200 filter[identifier] matches are present, because only the first page is searched. Using requestAll here would fully close the pagination edge case this change is addressing.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/apple/ascClient.ts, line 984:

<comment>`findBundleId` can still return `null` for an existing bundle ID when more than 200 `filter[identifier]` matches are present, because only the first page is searched. Using `requestAll` here would fully close the pagination edge case this change is addressing.</comment>

<file context>
@@ -971,18 +971,24 @@ export class AppStoreConnectClient {
     const { data } = await this.request<ResourceList<{ identifier: string; seedId?: string }>>(
       'GET',
-      `/bundleIds?filter[identifier]=${encodeURIComponent(identifier)}&limit=1`,
+      `/bundleIds?filter[identifier]=${encodeURIComponent(identifier)}&limit=200`,
     );
-    const first = data[0];
</file context>

YosefHayim added a commit that referenced this pull request Jul 8, 2026
…the build path (#291, #292) (#293)

findBundleId resolved the wrong App ID for multi-target apps: Apple's filter[identifier]
is a substring match, so a query for com.acme.app also returned com.acme.app.widget and
data[0] could be the widget. Select the exact identifier and raise the limit off 1. This
also fixes ensureAppStoreProfileForBundle binding the main app's profile to the widget's
App ID (#291).

launch build reused a cached profile without checking staleness — only setup self-healed.
resolveSigning now grades each cached profile (main + every extension) against its App ID's
live capabilities via staleCachedSigningTargets before silent reuse, and regenerates a stale
set instead of failing the archive at exit 65. Best-effort and network-bound, mirroring
warnUnreadySigningTargets: a flaky read or off-Mac decode grades as current so reuse stands (#292).

7 unit tests; README/llms/commands test-count badge regenerated (1967 -> 1974).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant