Skip to content

Validate iOS bundle identifiers#593

Open
jsdavid278-cyber wants to merge 1 commit into
profullstack:masterfrom
jsdavid278-cyber:codex/ios-bundle-id-validation
Open

Validate iOS bundle identifiers#593
jsdavid278-cyber wants to merge 1 commit into
profullstack:masterfrom
jsdavid278-cyber:codex/ios-bundle-id-validation

Conversation

@jsdavid278-cyber
Copy link
Copy Markdown
Contributor

Fixes #592.

Changes:

  • validate mobile-ios bundleId as a reverse-DNS identifier before build or ship
  • use the normalized bundleId for real ship IDs
  • add regression tests for invalid bundleId values in build and ship flows

Validation:

  • vitest run packages/targets/mobile-ios/src/index.test.ts
  • tsc -p packages/targets/mobile-ios/tsconfig.json --noEmit

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jun 5, 2026

Greptile Summary

This PR introduces a requireBundleId helper that validates iOS bundle identifiers against a reverse-DNS regex before build() or ship() proceeds, and uses the normalized result as the ship ID. Regression tests covering two invalid-format cases (../Acme and com.acme/ios) are also added.

  • The new BUNDLE_ID_PATTERN regex correctly rejects slashes, dots at the start, and labels that begin with a digit, but it accepts labels that end with a hyphen (e.g., com.example-.ios), which violates RFC 1123 and is rejected by Apple at submission time.
  • Test coverage is rejection-only; there is no positive case asserting that a valid bundle ID (e.g., com.example.app) actually allows build() and ship() to succeed.

Confidence Score: 3/5

The validation logic contains a defect that lets malformed bundle IDs through, so the guard is not as complete as intended.

The regex permits segments ending with a hyphen; a bundle ID like com.example-.ios passes requireBundleId but will be rejected by Apple at submission time, defeating the purpose of the new validation.

packages/targets/mobile-ios/src/index.ts — the BUNDLE_ID_PATTERN regex on line 11 needs tightening to disallow trailing hyphens in each label.

Important Files Changed

Filename Overview
packages/targets/mobile-ios/src/index.ts Adds requireBundleId validation with a reverse-DNS regex; the regex accepts labels that end with a hyphen (e.g. com.example-.ios), which is invalid per RFC 1123 and Apple's requirements.
packages/targets/mobile-ios/src/index.test.ts Adds rejection tests for build() and ship() with invalid bundle IDs; missing a positive happy-path test to guard against an overly strict regex in the future.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[build / ship called] --> B[requireBundleId]
    B --> C{bundleId present?}
    C -- No --> D[throw: mobile-ios requires bundleId]
    C -- Yes --> E{BUNDLE_ID_PATTERN.test}
    E -- Fail --> F[throw: must be valid reverse-DNS identifier]
    E -- Pass --> G[return normalized bundleId]
    G --> H[build: xcodebuild archive log]
    G --> I[ship: upload to App Store / TestFlight]
    I --> J{dryRun?}
    J -- Yes --> K[return id: dry-run]
    J -- No --> L[return id: bundleId@version]
Loading

Reviews (1): Last reviewed commit: "Validate iOS bundle identifiers" | Re-trigger Greptile

testflightGroups?: string[];
}

const BUNDLE_ID_PATTERN = /^[A-Za-z][A-Za-z0-9-]*(\.[A-Za-z][A-Za-z0-9-]*)+$/;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 The regex allows labels that end with a hyphen (e.g., com.example-.ios), which is invalid per RFC 1123 and Apple's bundle-ID rules. A segment like [A-Za-z0-9-]* can match a trailing hyphen because * imposes no constraint on the final character. This means requireBundleId would silently accept com.my-corp-.ios, com.acme-.app, etc., which Apple rejects at submission time.

Suggested change
const BUNDLE_ID_PATTERN = /^[A-Za-z][A-Za-z0-9-]*(\.[A-Za-z][A-Za-z0-9-]*)+$/;
const BUNDLE_ID_PATTERN = /^[A-Za-z]([A-Za-z0-9-]*[A-Za-z0-9])?(\.[A-Za-z]([A-Za-z0-9-]*[A-Za-z0-9])?)+$/;

Comment on lines +7 to +27
describe('iOS target', () => {
it('rejects invalid bundle identifiers while building', async () => {
await expect(adapter.build(fakeBuildContext({
outDir: '/repo/.sh1pt/out',
projectDir: '/repo',
}) as any, {
bundleId: '../Acme',
teamId: 'TEAM123456',
})).rejects.toThrow('mobile-ios bundleId must be a valid reverse-DNS identifier');
});

it('rejects invalid bundle identifiers while shipping', async () => {
await expect(adapter.ship(fakeShipContext({
channel: 'stable',
dryRun: false,
version: '1.2.3',
}) as any, {
bundleId: 'com.acme/ios',
teamId: 'TEAM123456',
})).rejects.toThrow('mobile-ios bundleId must be a valid reverse-DNS identifier');
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Both new tests cover rejection paths only. There is no positive test confirming that a well-formed bundle ID (e.g., com.example.app) actually lets build() and ship() proceed — the smokeTest skips both methods entirely. Without a passing case, a future regression that makes the regex overly strict (rejecting all IDs) would not be caught by this test suite.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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.

mobile-ios accepts invalid bundle identifiers

1 participant