Validate macOS bundle identifiers#595
Conversation
Greptile SummaryThis PR adds reverse-DNS bundle identifier validation for the macOS target, throwing early (in both
Confidence Score: 3/5Safe to merge after fixing the stale log reference; the validation logic itself is sound but has a small gap. The ship method validates and trims the bundleId correctly for the returned ID but still logs the raw config value, meaning log-based audit trails can show a different string than what was actually used. The regex also accepts labels that end with a hyphen (e.g. packages/targets/desktop-mac/src/index.ts — the log call and the regex pattern both need a small fix. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[build / ship called] --> B[requireBundleId]
B --> C{bundleId present?}
C -- No --> D[throw: desktop-mac requires bundleId]
C -- Yes --> E{matches BUNDLE_ID_PATTERN?}
E -- No --> F[throw: must be valid reverse-DNS identifier]
E -- Yes --> G[return trimmed bundleId]
G --> H[build: write macos-build-plan.json using validated bundleId]
G --> I[ship: log config.bundleId ⚠️ / return id = bundleId@version]
Reviews (1): Last reviewed commit: "Validate macOS bundle identifiers" | Re-trigger Greptile |
| async ship(ctx, config) { | ||
| const bundleId = requireBundleId(config); | ||
| const targets = config.distribution === 'both' ? ['App Store', 'DMG host'] : [config.distribution === 'mas' ? 'App Store' : 'DMG host']; | ||
| ctx.log(`publish ${config.bundleId}@${ctx.version} → ${targets.join(', ')}`); |
There was a problem hiding this comment.
The
ctx.log call logs config.bundleId (the raw, untrimmed value) instead of the validated bundleId returned by requireBundleId. If the caller passes a bundle ID with leading/trailing whitespace (e.g., " com.acme.app "), the log entry and the returned ship ID will disagree, making log-based audit trails unreliable.
| ctx.log(`publish ${config.bundleId}@${ctx.version} → ${targets.join(', ')}`); | |
| ctx.log(`publish ${bundleId}@${ctx.version} → ${targets.join(', ')}`); |
| signingIdentity?: string; // e.g. "Developer ID Application: ACME Inc (ABCDE12345)" | ||
| } | ||
|
|
||
| const BUNDLE_ID_PATTERN = /^[A-Za-z][A-Za-z0-9-]*(\.[A-Za-z][A-Za-z0-9-]*)+$/; |
There was a problem hiding this comment.
The current pattern allows each label segment to end with a hyphen (e.g.,
com.acme-.app passes validation). Per DNS label rules, a label may not start or end with a hyphen. Tightening the character class so each label ends with an alphanumeric character prevents invalid identifiers like com.my-app-.utils from slipping through.
| 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]+)*)+$/; |
Fixes #594.
Changes:
Validation: