Skip to content

fix(packaging): support non-upstream Developer ID signing - #3372

Open
krazybean wants to merge 1 commit into
steipete:mainfrom
krazybean:fix/fork-developer-id-signing
Open

fix(packaging): support non-upstream Developer ID signing#3372
krazybean wants to merge 1 commit into
steipete:mainfrom
krazybean:fix/fork-developer-id-signing

Conversation

@krazybean

Copy link
Copy Markdown
Contributor

Summary

Allows CodexBar forks to package/sign the app with a non-upstream Developer ID without embedding upstream provisioning or entitlement metadata.

The existing packaging flow assumes CodexBar's upstream signing team and provisioning profile. That works for upstream releases, but a fork signed with a different Developer ID can end up with a locally signed app that still contains upstream team-bound provisioning/entitlement values, which macOS can reject at launch.

What changes

  • Derives the signing Team ID from the configured Developer ID identity instead of hard-coding a fork-specific value.
  • Embeds Scripts/profiles/CodexBar-DeveloperID.provisionprofile only when packaging with CodexBar's upstream team (Y5PE65HELJ).
  • Generates local app/widget entitlements using the active signing team.
  • Avoids claiming upstream iCloud, keychain, or provisioning resources for non-upstream signers.
  • Preserves the existing strict upstream release-signing behavior.

Timestamp fallback

For non-upstream signing only, packaging now falls back to signing without a timestamp if Apple's timestamp service is unavailable.

Upstream (Y5PE65HELJ) release signing remains strict and does not receive this fallback, so the upstream release path is not weakened.

Launch smoke test

The packaged-app launch verification now detects environments where sandbox-exec itself is unavailable/forbidden and skips that sandboxed smoke step in that specific case.

The existing explicit:

CODEXBAR_SKIP_LAUNCH_SMOKE=1

override remains unchanged.

Normal environments where sandbox-exec works continue to run the smoke test.

Why

This surfaced while testing CodexBar from a fork with a different Developer ID.

The resulting app was correctly signed by the fork's identity, but still contained an upstream provisioning profile/team metadata. Signature verification could succeed while launchd rejected the app at spawn time.

With this change, upstream and fork packaging paths remain internally consistent:

  • upstream signer → upstream provisioning/profile behavior
  • non-upstream signer → derived local team entitlements, no upstream profile

Scope

This PR only changes fork/release packaging behavior.

The Muse provider work that exposed the issue is submitted separately in #3371.

@clawsweeper

clawsweeper Bot commented Sep 1, 2026

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c25f88c6e3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Scripts/package_app.sh
Comment on lines +524 to +526
if [[ "${APP_TEAM_ID}" != "Y5PE65HELJ" ]]; then
echo "WARN: Skipping CodexBarWidget for local team ${APP_TEAM_ID} (build failed, continuing without widget)." >&2
return 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Fail packaging when the widget build fails

For every non-upstream team, any xcodebuild failure—not only the managed-sandbox cache error—is converted into success. Thus an ordinary fork release with a widget compilation error, missing dependency, or invalid project can still produce and potentially distribute an app with CodexBarWidget.appex silently omitted; restrict this exception to the explicitly detected smoke-test environment or propagate the failure.

Useful? React with 👍 / 👎.

Comment thread Scripts/package_app.sh
Comment on lines +244 to +247
echo "WARN: Could not derive team ID from APP_IDENTITY; disabling upstream profile (safe fallback)" >&2
if [[ "${APP_IDENTITY}" != *"Y5PE65HELJ"* ]]; then
# Prevent accidental use of upstream profile/iCloud when team is unparseable
APP_TEAM_ID="LOCAL"

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 Badge Reject an unresolvable signing team instead of using LOCAL

When APP_IDENTITY is otherwise usable for signing but has no parseable parenthesized team and the certificate lookup cannot resolve it, this fabricates LOCAL and embeds LOCAL.com.steipete.codexbar in the app/widget entitlements. At runtime AppGroupSupport.resolvedTeamID prefers the actual team from the code signature, so it requests a different group identifier and the app and widget cannot share their container; derive the real team, omit the group capability, or fail packaging instead.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Sep 2, 2026
@clawsweeper

clawsweeper Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge. Reviewed September 1, 2026, 8:37 PM ET / September 2, 2026, 00:37 UTC.

ClawSweeper review

What this changes

This PR derives a fork signer’s team ID, avoids upstream provisioning for non-upstream signing, adds timestamp retry behavior, and skips the launch smoke check when sandbox execution is denied.

Regression provenance

Possible regression — probable (reviewed change; failure trace). No predecessor PR is attributed.

Merge readiness

Blocked until real behavior proof is added - 9 items remain

Keep open: the fork-signing direction is useful, but the introduced error handling can silently ship a fork build without its widget and can generate invalid app-group entitlements when team resolution fails.

Priority: P2
Reviewed head: c25f88c6e37688082f38c4d47020e6db32cc4e18

Review scores

Measure Result What it means
Overall readiness 🦪 silver shellfish (2/6) The patch has a valid goal, but two concrete packaging regressions and missing real behavior proof block merge readiness.
Proof confidence 🦪 silver shellfish (2/6) Needs real behavior proof before merge: The reviewed PR body contains no after-fix real fork package/sign/launch trace for the changed packaging owner. Add a redacted terminal trace showing a non-upstream identity packages and launches with the widget present and matching team entitlements; after updating the PR body, request @clawsweeper re-review if a fresh review does not start automatically. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Patch quality 🦪 silver shellfish (2/6) 2 actionable review findings remain.

Verification

Check Result Evidence
Real behavior Needs proof Needs real behavior proof before merge: The reviewed PR body contains no after-fix real fork package/sign/launch trace for the changed packaging owner. Add a redacted terminal trace showing a non-upstream identity packages and launches with the widget present and matching team entitlements; after updating the PR body, request @clawsweeper re-review if a fresh review does not start automatically. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed 4 items Introduced widget omission: The introduced conditional treats every widget-build failure for a non-upstream team as success, so subsequent packaging and integrity checks proceed with no widget extension.
App-group team contract: The package script writes APP_TEAM_ID into application-group entitlements, while runtime resolves the actual signing team from the code signature before falling back to Info.plist. An unresolved identity replaced with LOCAL therefore makes the signed app request a different group than its entitlement permits.
Packaging feature history: Recent merged packaging and packaged-app launch-smoke work is associated with Peter Steinberger, establishing the current packaging-maintenance routing context.
Findings 2 actionable findings [P1] Do not treat every fork widget build failure as optional
[P2] Fail when the signing team cannot be resolved
Security None None.

How this fits together

CodexBar’s packaging scripts assemble and sign the macOS app, widget, helper binaries, entitlements, and optional upstream provisioning profile. The resulting bundle is then checked for basic launchability before local distribution or release workflows use it.

flowchart LR
  A[Packaging configuration] --> B[Signing identity]
  B --> C[Team ID and entitlements]
  C --> D[App and widget signing]
  D --> E[Packaged app bundle]
  E --> F[Launch smoke check]
Loading

Before merge

  • Add real behavior proof - Needs real behavior proof before merge: The reviewed PR body contains no after-fix real fork package/sign/launch trace for the changed packaging owner. Add a redacted terminal trace showing a non-upstream identity packages and launches with the widget present and matching team entitlements; after updating the PR body, request @clawsweeper re-review if a fresh review does not start automatically. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
  • Do not treat every fork widget build failure as optional (P1) - build_widget_extension exits nonzero for ordinary compilation failures, but this branch converts every such failure for a non-upstream team into a successful package without CodexBarWidget.appex. Limit an omission to a positively identified supported sandbox condition or propagate the failure.
  • Fail when the signing team cannot be resolved (P2) - An identity that codesign can use but this lookup cannot parse is assigned LOCAL. The app subsequently resolves its actual signing team from the signature, so its requested application group differs from the generated entitlement and the app/widget cannot use their shared container.
  • Resolve merge risk (P1) - A normal non-upstream widget compilation failure would produce a successful package missing the widget extension.
  • Resolve merge risk (P1) - An unresolvable but otherwise usable signing identity can write LOCAL app-group entitlements that do not match the bundle’s actual signing team.
  • Complete next step (P2) - Both introduced defects have narrow, source-proven repairs; real behavior proof must still come from a macOS fork-signing setup before merge.
  • Improve patch quality - Propagate ordinary widget build failures and reject unresolved signing-team identities.
  • Improve patch quality - Add focused regression coverage for the two failure paths.
  • Improve patch quality - Provide a redacted real non-upstream package/sign/launch trace with widget and entitlement verification.

Findings

  • [P1] Do not treat every fork widget build failure as optional — Scripts/package_app.sh:524-526
  • [P2] Fail when the signing team cannot be resolved — Scripts/package_app.sh:244-248
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Packaging delta 2 scripts, production +66/-15, tests +0 The new signing and widget behavior has no focused regression coverage in the branch.

Merge-risk options

Maintainer options:

  1. Make fork packaging fail closed (recommended)
    Propagate ordinary widget-build failures and reject unresolved signing teams before generating application-group entitlements.

Technical review

Best possible solution:

Preserve the fork-safe profile restriction while failing packaging on unresolved team identity and on widget build failures except for a positively identified, explicitly supported sandbox-only case.

Do we have a high-confidence way to reproduce the issue?

Yes for the introduced defects: source shows that any non-upstream widget-build failure returns success, and an unresolved identity assigns LOCAL before app-group entitlements are generated. A real macOS package/sign/launch trace has not been supplied or executed in this read-only review.

Is this the best way to solve the issue?

No. The derived-team and upstream-profile restriction are narrowly targeted, but broad widget omission and a fabricated team ID undermine the packaging contract.

Full review comments:

  • [P1] Do not treat every fork widget build failure as optional — Scripts/package_app.sh:524-526
    build_widget_extension exits nonzero for ordinary compilation failures, but this branch converts every such failure for a non-upstream team into a successful package without CodexBarWidget.appex. Limit an omission to a positively identified supported sandbox condition or propagate the failure.
    Confidence: 0.99
  • [P2] Fail when the signing team cannot be resolved — Scripts/package_app.sh:244-248
    An identity that codesign can use but this lookup cannot parse is assigned LOCAL. The app subsequently resolves its actual signing team from the signature, so its requested application group differs from the generated entitlement and the app/widget cannot use their shared container.
    Confidence: 0.97

Overall correctness: patch is incorrect
Overall confidence: 0.98

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 2cac84440c42.

Labels

Label changes:

  • add P2: The introduced defects affect non-upstream packaged builds and can remove a shipped widget or break its shared state.
  • add merge-risk: 🚨 compatibility: Fork releases can appear successfully packaged while losing the widget or using app-group entitlements inconsistent with the actual signer.
  • add rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🦪 silver shellfish.
  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The reviewed PR body contains no after-fix real fork package/sign/launch trace for the changed packaging owner. Add a redacted terminal trace showing a non-upstream identity packages and launches with the widget present and matching team entitlements; after updating the PR body, request @clawsweeper re-review if a fresh review does not start automatically. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Label justifications:

  • P2: The introduced defects affect non-upstream packaged builds and can remove a shipped widget or break its shared state.
  • merge-risk: 🚨 compatibility: Fork releases can appear successfully packaged while losing the widget or using app-group entitlements inconsistent with the actual signer.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🦪 silver shellfish.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The reviewed PR body contains no after-fix real fork package/sign/launch trace for the changed packaging owner. Add a redacted terminal trace showing a non-upstream identity packages and launches with the widget present and matching team entitlements; after updating the PR body, request @clawsweeper re-review if a fresh review does not start automatically. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Evidence

Acceptance criteria:

  • [P1] bash -n Scripts/package_app.sh Scripts/verify_packaged_app_launch.sh.
  • [P1] make test.
  • [P1] make check.

What I checked:

  • Introduced widget omission: The introduced conditional treats every widget-build failure for a non-upstream team as success, so subsequent packaging and integrity checks proceed with no widget extension. (Scripts/package_app.sh:519, c25f88c6e376)
  • App-group team contract: The package script writes APP_TEAM_ID into application-group entitlements, while runtime resolves the actual signing team from the code signature before falling back to Info.plist. An unresolved identity replaced with LOCAL therefore makes the signed app request a different group than its entitlement permits. (Sources/CodexBarCore/AppGroupSupport.swift:57, c25f88c6e376)
  • Packaging feature history: Recent merged packaging and packaged-app launch-smoke work is associated with Peter Steinberger, establishing the current packaging-maintenance routing context. (Scripts/package_app.sh:452, ce55c65c8474)
  • Current-main and release check: The PR head is not contained by local main or any tag; current main is 2cac844 and the latest release is v0.56.3, so this work is neither merged nor released. (2cac84440c42)

Likely related people:

  • Peter Steinberger: Suggested for follow-up; no historical authorship or introduction is verified. (role: unverified routing candidate; confidence: low)
  • Nimrod Gutman: Suggested for follow-up; no historical authorship or introduction is verified. (role: unverified routing candidate; confidence: low)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

steipete added a commit that referenced this pull request Sep 7, 2026
Select upstream CloudKit provisioning only for its resolved signing team, and share the resolved bundle ID when deriving app/widget groups.

Extracted from #3372. Sixteen actual entitlement/profile-selection configurations, existing signing checks, make check, full 1,028-selection suite and exact-head CI pass. Direct alternate identity discovery remains separate.

Co-authored-by: Juanito <krazybean@gmail.com>
@steipete

steipete commented Sep 7, 2026

Copy link
Copy Markdown
Owner

The resolved-team provisioning mismatch is now fixed on main in #3461 (02c073a22ab), with your co-author and changelog credit preserved. The actual entitlement-generation/profile-copy code passes all 16 upstream/alternate-team, debug/release, identity/ad-hoc, profile-present/absent cases; full tests and exact-head CI passed.

The narrower repair also derives app/widget groups from the resolved bundle ID. This PR remains open for the separate direct-identity discovery path. Timestamp fallback, widget omission and sandbox-smoke bypass were not needed for the verified profile-selection defect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants