Skip to content

fix(ci): fix iOS release workflow provisioning profile and build number - #197

Merged
Chibuzor-Nwemambu merged 16 commits into
mainfrom
fix/iOS-release-workflow-debug
Jun 8, 2026
Merged

fix(ci): fix iOS release workflow provisioning profile and build number#197
Chibuzor-Nwemambu merged 16 commits into
mainfrom
fix/iOS-release-workflow-debug

Conversation

@Chibuzor-Nwemambu

@Chibuzor-Nwemambu Chibuzor-Nwemambu commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR fixes two issues that were blocking the build-release-ios workflow from successfully building and uploading the Storybook app to TestFlight, and adds encryption compliance configuration to avoid manual answers on every App Store submission.

1. UUID extraction fails on macos-26 runner

The original step used security cms -D to decode the provisioning profile and extract the UUID:

UUID=$(security cms -D -i "$PROFILE" | /usr/libexec/PlistBuddy -c "Print :UUID" /dev/stdin)

On the macos-26 runner, security cms -D consistently fails with Cannot parse a NULL or zero-length data, even though the provisioning profile file is valid (12 KB, correct content). The root cause is unclear — likely a runner-level compatibility issue with the Security framework on macOS 26.

Fix: Extract the UUID by grepping the raw binary directly. The UUID is stored as plain ASCII within the CMS envelope, so this works reliably without needing to decode the CMS wrapper:

UUID=$(grep -aEo '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}' "$PROFILE" | head -1)

Note: the pattern uses [0-9a-fA-F] (case-insensitive) because Apple provisioning profiles use lowercase UUIDs. An uppercase-only pattern returns no match.

2. patch-files-action fails because buildNumber field is missing

The workflow patches app.json to set the build number before archiving:

= /expo/ios/buildNumber => "${{ env.BUILD_NUMBER }}"

The patch-files-action requires the field to already exist at the target path — it cannot create new fields. Since ios.buildNumber was absent from app.json, the patch step failed with OPERATION_PATH_UNRESOLVABLE.

Fix: Added "buildNumber": "1" as a placeholder to app.json. The value is overwritten on every CI run and never used as-is.

3. Encryption compliance key added to app.json

Added ITSAppUsesNonExemptEncryption: false to the ios.infoPlist section of app.json. This tells Apple the app uses no exempt encryption algorithms, skipping the manual compliance questionnaire on every future App Store and TestFlight submission.

Added via app.json rather than directly in Info.plist so it is applied automatically on every expo prebuild run and cannot be accidentally wiped.

Test plan

  • Triggered workflow manually via workflow_dispatch on this branch
  • Build completed successfully end-to-end
  • IPA uploaded and appeared in App Store Connect TestFlight within minutes

@Chibuzor-Nwemambu Chibuzor-Nwemambu linked an issue Jun 3, 2026 that may be closed by this pull request
4 tasks
@Chibuzor-Nwemambu

Copy link
Copy Markdown
Collaborator Author

@claude review

@claude

claude Bot commented Jun 3, 2026

Copy link
Copy Markdown

Claude finished @Chibuzor-Nwemambu's task in 1m 19s —— View job


Code Review — PR #197

  • Read PR diff and changed files
  • Review UUID extraction change
  • Review app.json buildNumber change
  • Review package.json script rename
  • Post review feedback

Overall this is a solid, well-documented fix. The PR description does a great job explaining the why behind each change, and the test plan (full workflow run → TestFlight) gives real confidence. Two of the three changes are clearly correct; the third has a documentation ripple effect worth addressing.

🔴 package.json rename breaks documented commands (and is out of scope)

.github/.../package.json renames dev:storybookstorybook:

-    "dev:storybook": "turbo run dev --filter @equinor/mobile-storybook",
+    "storybook": "turbo run dev --filter @equinor/mobile-storybook",

This rename is unrelated to the iOS release fix that the PR is about, and more importantly it leaves 8 stale references to pnpm dev:storybook across the repo's docs, all of which now point to a script that no longer exists:

  • CLAUDE.md:30
  • README.md:152, README.md:179
  • packages/components/CLAUDE.md:168
  • apps/storybook/CLAUDE.md:18
  • apps/storybook/README.md:31, apps/storybook/README.md:50, apps/storybook/README.md:102

Anyone following the README/CLAUDE quickstart will hit Command "dev:storybook" not found. Two options:

  1. Update the docs to use pnpm storybook (matches the "easier to run" intent), or
  2. Keep both — add "storybook" as an alias while leaving "dev:storybook" in place, so existing docs/muscle-memory keep working.

I'd lean toward updating the docs since the rename is intentional. Fix this →

Consider splitting this rename into its own PR so the CI fix stays focused — but not a blocker.

🟡 UUID grep relies on head -1 (minor robustness)

UUID=$(grep -aEo '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}' "$PROFILE" | head -1)

The grep-the-raw-binary approach is a pragmatic workaround for the security cms -D failure on macos-26, and in practice the profile's UUID key is the only canonical 8-4-4-4-12 string in the envelope (cert serials/key IDs are raw binary, not hyphenated ASCII), so head -1 should reliably land on it. The fragility is that it's positional rather than keyed — if a future profile ever embeds another UUID-formatted value (e.g. in entitlements), head -1 could grab the wrong one silently.

Two cheap hardenings if you want belt-and-suspenders:

  • Add a guard so the build fails loudly instead of proceeding with an empty/wrong UUID:
    if [ -z "$UUID" ]; then echo "::error::Failed to extract UUID from provisioning profile"; exit 1; fi
  • Or anchor to the key, e.g. extract the plist slice and read :UUID with PlistBuddy from the decoded XML range — but that reintroduces decode complexity, so the guard alone is probably the better cost/benefit.

Not blocking given the successful end-to-end run.

app.json buildNumber placeholder — correct

-            "bundleIdentifier": "com.equinor.eds.mobile"
+            "bundleIdentifier": "com.equinor.eds.mobile",
+            "buildNumber": "1"

This is exactly right: patch-files-action does an in-place = replace and can't create missing paths, so seeding ios.buildNumber is required for the OPERATION_PATH_UNRESOLVABLE fix. The value is overwritten each run by the Patch app.json step, so the placeholder is harmless. Good catch on the root cause.

✅ Debug echo

The added echo "Extracted UUID: $UUID" is a nice, low-cost aid for diagnosing future signing issues. 👍


Summary

Change Verdict
app.json buildNumber placeholder ✅ Correct
UUID grep extraction ✅ Works; consider an empty-value guard
package.json rename 🔴 Update the 8 stale dev:storybook doc references (or alias)

The core CI fix is good to go. The main thing I'd resolve before merge is the doc drift from the script rename.

Note: I can review and comment, but I can't modify files under .github/workflows/ (GitHub App permission), so I haven't applied any changes — this is review feedback only.
· fix/iOS-release-workflow-debug

@Chibuzor-Nwemambu

Copy link
Copy Markdown
Collaborator Author

Added an empty-value guard after the UUID extraction (line 64). The concern isn't that head -1 is unreliable; provisioning profiles are Apple-generated and the UUID key is structurally first. The real risk is a misconfigured secret or a silent base64 decode failure producing an empty $UUID. Without the guard, that propagates silently: PlistBuddy writes an empty string to ExportOptions.plist and xcodebuild gets PROVISIONING_PROFILE="", both failing later with errors that don't point back here. The guard surfaces the real failure immediately.

Also updated 8 doc references from pnpm dev:storybook to pnpm storybook to match the earlier script rename.

Adds an empty-value guard after UUID extraction to surface misconfigured
secrets or silent base64 decode failures immediately rather than letting
an empty value propagate silently through PlistBuddy and xcodebuild.

Updates 8 doc references from pnpm dev:storybook to pnpm storybook to
match the earlier script rename.
HaakonSvane
HaakonSvane previously approved these changes Jun 5, 2026

@HaakonSvane HaakonSvane left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔥

Comment thread .github/workflows/build-release-ios.yml Outdated
Comment thread README.md Outdated
Replaces the grep workaround with the structured security cms -D approach.
The original failure (Cannot parse a NULL or zero-length data) was caused by
an empty provisioning profile file, not a security cms limitation. A -s file
size guard now surfaces that failure immediately with a clear error message.

Also reverts dev:storybook script rename to preserve the verb:scope convention
used throughout the repo, and updates docs accordingly.
security cms -D fails on macos-26 runners because they lack the Apple root
certificate needed to verify the CMS signature. openssl smime with -noverify
performs the same structured DER decode without requiring the signing cert,
giving a keyed UUID extraction that works on the current runner image.
Both security cms -D and openssl smime fail on macos-26 — the former needs
Apple root certs in the keychain, the latter is incompatible with the runner's
LibreSSL. Python's plistlib reads the UUID by key name from the embedded XML
plist, requiring no external tools or certificates.
xcodebuild accepts a profile name in ExportOptions.plist, so extracting the
UUID from the binary mobileprovision file is unnecessary. The profile name is
stored as APPLE_PROVISIONING_PROFILE_NAME in repository variables, removing
the macos-26 runner incompatibility entirely.

@HaakonSvane HaakonSvane left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@Chibuzor-Nwemambu
Chibuzor-Nwemambu merged commit 5ed8c9a into main Jun 8, 2026
9 checks passed
@Chibuzor-Nwemambu
Chibuzor-Nwemambu deleted the fix/iOS-release-workflow-debug branch June 8, 2026 07:35
@github-actions github-actions Bot mentioned this pull request Jun 8, 2026
Chibuzor-Nwemambu added a commit that referenced this pull request Jun 30, 2026
🤖 I have created a release *beep* *boop*
---


<details><summary>eds-mobile-components: 0.3.0</summary>

##
[0.3.0](eds-mobile-components-v0.2.0...eds-mobile-components-v0.3.0)
(2026-06-30)


### ⚠ BREAKING CHANGES

* **deps:** upgrade Expo SDK 53 → 55
([#202](#202))

### Features

* **components:** add Badge component
([#190](#190))
([6c18b76](6c18b76))
* **components:** implement Divider component
([#207](#207))
([069e07d](069e07d))
* **components:** implement Link component
([#188](#188))
([b0b3a6d](b0b3a6d))
* **components:** implement TextArea component
([#204](#204))
([4fe04dc](4fe04dc)),
closes
[#131](#131)
* **components:** implement TextField component
([#195](#195))
([2701d5b](2701d5b))
* **components:** migrate Search component
([#206](#206))
([606dedb](606dedb))


### Bug Fixes

* **components:** adopt nested typography token shape from
@equinor/eds-tokens@2.3.0-beta.3
([#180](#180))
([02e82bd](02e82bd))
* **components:** read-only Input allows copy; disabled blocks all
interaction
([#200](#200))
([cec811f](cec811f))


### Miscellaneous Chores

* **deps:** upgrade Expo SDK 53 → 55
([#202](#202))
([7eaef66](7eaef66)),
closes
[#196](#196)
</details>

<details><summary>mobile-storybook: 0.3.0</summary>

##
[0.3.0](mobile-storybook-v0.2.0...mobile-storybook-v0.3.0)
(2026-06-30)


### ⚠ BREAKING CHANGES

* **deps:** upgrade Expo SDK 53 → 55
([#202](#202))

### Features

* **components:** add Badge component
([#190](#190))
([6c18b76](6c18b76))
* **components:** implement Divider component
([#207](#207))
([069e07d](069e07d))
* **components:** implement Link component
([#188](#188))
([b0b3a6d](b0b3a6d))
* **components:** implement TextArea component
([#204](#204))
([4fe04dc](4fe04dc)),
closes
[#131](#131)
* **components:** implement TextField component
([#195](#195))
([2701d5b](2701d5b))
* **components:** migrate Search component
([#206](#206))
([606dedb](606dedb))


### Bug Fixes

* **ci:** fix iOS release workflow provisioning profile and build number
([#197](#197))
([5ed8c9a](5ed8c9a))
* **components:** adopt nested typography token shape from
@equinor/eds-tokens@2.3.0-beta.3
([#180](#180))
([02e82bd](02e82bd))
* **components:** read-only Input allows copy; disabled blocks all
interaction
([#200](#200))
([cec811f](cec811f))
* **storybook:** Components header title not theme-aware in dark mode
([#210](#210))
([432242f](432242f))


### Miscellaneous Chores

* **deps:** upgrade Expo SDK 53 → 55
([#202](#202))
([7eaef66](7eaef66)),
closes
[#196](#196)
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Chibuzor Nwemambu <75029767+Chibuzor-Nwemambu@users.noreply.github.com>
Chibuzor-Nwemambu added a commit to equinor/design-system that referenced this pull request Aug 7, 2026
🤖 I have created a release *beep* *boop*
---


<details><summary>eds-mobile-components: 0.3.0</summary>

##
[0.3.0](equinor/design-system-mobile@eds-mobile-components-v0.2.0...eds-mobile-components-v0.3.0)
(2026-06-30)


### ⚠ BREAKING CHANGES

* **deps:** upgrade Expo SDK 53 → 55
([#202](equinor/design-system-mobile#202))

### Features

* **components:** add Badge component
([#190](equinor/design-system-mobile#190))
([6c18b76](equinor/design-system-mobile@6c18b76))
* **components:** implement Divider component
([#207](equinor/design-system-mobile#207))
([069e07d](equinor/design-system-mobile@069e07d))
* **components:** implement Link component
([#188](equinor/design-system-mobile#188))
([b0b3a6d](equinor/design-system-mobile@b0b3a6d))
* **components:** implement TextArea component
([#204](equinor/design-system-mobile#204))
([4fe04dc](equinor/design-system-mobile@4fe04dc)),
closes
[#131](equinor/design-system-mobile#131)
* **components:** implement TextField component
([#195](equinor/design-system-mobile#195))
([2701d5b](equinor/design-system-mobile@2701d5b))
* **components:** migrate Search component
([#206](equinor/design-system-mobile#206))
([606dedb](equinor/design-system-mobile@606dedb))


### Bug Fixes

* **components:** adopt nested typography token shape from
@equinor/eds-tokens@2.3.0-beta.3
([#180](equinor/design-system-mobile#180))
([02e82bd](equinor/design-system-mobile@02e82bd))
* **components:** read-only Input allows copy; disabled blocks all
interaction
([#200](equinor/design-system-mobile#200))
([cec811f](equinor/design-system-mobile@cec811f))


### Miscellaneous Chores

* **deps:** upgrade Expo SDK 53 → 55
([#202](equinor/design-system-mobile#202))
([7eaef66](equinor/design-system-mobile@7eaef66)),
closes
[#196](equinor/design-system-mobile#196)
</details>

<details><summary>mobile-storybook: 0.3.0</summary>

##
[0.3.0](equinor/design-system-mobile@mobile-storybook-v0.2.0...mobile-storybook-v0.3.0)
(2026-06-30)


### ⚠ BREAKING CHANGES

* **deps:** upgrade Expo SDK 53 → 55
([#202](equinor/design-system-mobile#202))

### Features

* **components:** add Badge component
([#190](equinor/design-system-mobile#190))
([6c18b76](equinor/design-system-mobile@6c18b76))
* **components:** implement Divider component
([#207](equinor/design-system-mobile#207))
([069e07d](equinor/design-system-mobile@069e07d))
* **components:** implement Link component
([#188](equinor/design-system-mobile#188))
([b0b3a6d](equinor/design-system-mobile@b0b3a6d))
* **components:** implement TextArea component
([#204](equinor/design-system-mobile#204))
([4fe04dc](equinor/design-system-mobile@4fe04dc)),
closes
[#131](equinor/design-system-mobile#131)
* **components:** implement TextField component
([#195](equinor/design-system-mobile#195))
([2701d5b](equinor/design-system-mobile@2701d5b))
* **components:** migrate Search component
([#206](equinor/design-system-mobile#206))
([606dedb](equinor/design-system-mobile@606dedb))


### Bug Fixes

* **ci:** fix iOS release workflow provisioning profile and build number
([#197](equinor/design-system-mobile#197))
([5ed8c9a](equinor/design-system-mobile@5ed8c9a))
* **components:** adopt nested typography token shape from
@equinor/eds-tokens@2.3.0-beta.3
([#180](equinor/design-system-mobile#180))
([02e82bd](equinor/design-system-mobile@02e82bd))
* **components:** read-only Input allows copy; disabled blocks all
interaction
([#200](equinor/design-system-mobile#200))
([cec811f](equinor/design-system-mobile@cec811f))
* **storybook:** Components header title not theme-aware in dark mode
([#210](equinor/design-system-mobile#210))
([432242f](equinor/design-system-mobile@432242f))


### Miscellaneous Chores

* **deps:** upgrade Expo SDK 53 → 55
([#202](equinor/design-system-mobile#202))
([7eaef66](equinor/design-system-mobile@7eaef66)),
closes
[#196](equinor/design-system-mobile#196)
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Chibuzor Nwemambu <75029767+Chibuzor-Nwemambu@users.noreply.github.com>
Chibuzor-Nwemambu added a commit to equinor/design-system that referenced this pull request Aug 7, 2026
🤖 I have created a release *beep* *boop*
---


<details><summary>eds-mobile-components: 0.3.0</summary>

##
[0.3.0](equinor/design-system-mobile@eds-mobile-components-v0.2.0...eds-mobile-components-v0.3.0)
(2026-06-30)


### ⚠ BREAKING CHANGES

* **deps:** upgrade Expo SDK 53 → 55
([#202](equinor/design-system-mobile#202))

### Features

* **components:** add Badge component
([#190](equinor/design-system-mobile#190))
([6c18b76](equinor/design-system-mobile@6c18b76))
* **components:** implement Divider component
([#207](equinor/design-system-mobile#207))
([069e07d](equinor/design-system-mobile@069e07d))
* **components:** implement Link component
([#188](equinor/design-system-mobile#188))
([b0b3a6d](equinor/design-system-mobile@b0b3a6d))
* **components:** implement TextArea component
([#204](equinor/design-system-mobile#204))
([4fe04dc](equinor/design-system-mobile@4fe04dc)),
closes
[#131](equinor/design-system-mobile#131)
* **components:** implement TextField component
([#195](equinor/design-system-mobile#195))
([2701d5b](equinor/design-system-mobile@2701d5b))
* **components:** migrate Search component
([#206](equinor/design-system-mobile#206))
([606dedb](equinor/design-system-mobile@606dedb))


### Bug Fixes

* **components:** adopt nested typography token shape from
@equinor/eds-tokens@2.3.0-beta.3
([#180](equinor/design-system-mobile#180))
([02e82bd](equinor/design-system-mobile@02e82bd))
* **components:** read-only Input allows copy; disabled blocks all
interaction
([#200](equinor/design-system-mobile#200))
([cec811f](equinor/design-system-mobile@cec811f))


### Miscellaneous Chores

* **deps:** upgrade Expo SDK 53 → 55
([#202](equinor/design-system-mobile#202))
([7eaef66](equinor/design-system-mobile@7eaef66)),
closes
[#196](equinor/design-system-mobile#196)
</details>

<details><summary>mobile-storybook: 0.3.0</summary>

##
[0.3.0](equinor/design-system-mobile@mobile-storybook-v0.2.0...mobile-storybook-v0.3.0)
(2026-06-30)


### ⚠ BREAKING CHANGES

* **deps:** upgrade Expo SDK 53 → 55
([#202](equinor/design-system-mobile#202))

### Features

* **components:** add Badge component
([#190](equinor/design-system-mobile#190))
([6c18b76](equinor/design-system-mobile@6c18b76))
* **components:** implement Divider component
([#207](equinor/design-system-mobile#207))
([069e07d](equinor/design-system-mobile@069e07d))
* **components:** implement Link component
([#188](equinor/design-system-mobile#188))
([b0b3a6d](equinor/design-system-mobile@b0b3a6d))
* **components:** implement TextArea component
([#204](equinor/design-system-mobile#204))
([4fe04dc](equinor/design-system-mobile@4fe04dc)),
closes
[#131](equinor/design-system-mobile#131)
* **components:** implement TextField component
([#195](equinor/design-system-mobile#195))
([2701d5b](equinor/design-system-mobile@2701d5b))
* **components:** migrate Search component
([#206](equinor/design-system-mobile#206))
([606dedb](equinor/design-system-mobile@606dedb))


### Bug Fixes

* **ci:** fix iOS release workflow provisioning profile and build number
([#197](equinor/design-system-mobile#197))
([5ed8c9a](equinor/design-system-mobile@5ed8c9a))
* **components:** adopt nested typography token shape from
@equinor/eds-tokens@2.3.0-beta.3
([#180](equinor/design-system-mobile#180))
([02e82bd](equinor/design-system-mobile@02e82bd))
* **components:** read-only Input allows copy; disabled blocks all
interaction
([#200](equinor/design-system-mobile#200))
([cec811f](equinor/design-system-mobile@cec811f))
* **storybook:** Components header title not theme-aware in dark mode
([#210](equinor/design-system-mobile#210))
([432242f](equinor/design-system-mobile@432242f))


### Miscellaneous Chores

* **deps:** upgrade Expo SDK 53 → 55
([#202](equinor/design-system-mobile#202))
([7eaef66](equinor/design-system-mobile@7eaef66)),
closes
[#196](equinor/design-system-mobile#196)
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Chibuzor Nwemambu <75029767+Chibuzor-Nwemambu@users.noreply.github.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

Development

Successfully merging this pull request may close these issues.

Fix iOS release workflow and ship first build to App Store

2 participants