Skip to content

Commit 93dcac7

Browse files
authored
feat(preprod): fail upload if app is missing Info.plist (#2793)
Every `.app` inside of the `Product/Applications` directory needs a corresponding `Info.plist` file since we use this to gather important information about the app. Currently we are allowing these uploads to take place which then immediately fail during processing -- not the greatest UX. It would be better to fail immediately so the user knows there is an issue since this means something went wrong with packaging their app. Worth noting: technically there's a way to embed this file directly in the Mach-O binary but that is seldom used and we don't support parsing that in `launchpad` either. Now we will fail and produce an error log: ``` ERROR 2025-09-23 10:28:40.771928 -04:00 Invalid XCArchive: Missing required Info.plist file in .app bundle: /Users/telkins/Downloads/<redacted>.app.xcarchive/Products/Applications/<redacted>.app error: File is not a recognized supported build format (APK, AAB, XCArchive, or IPA): /Users/telkins/Downloads/<redacted>.app.xcarchive ``` Resolves EME-311
1 parent fc9297e commit 93dcac7

File tree

2 files changed

+38
-9
lines changed

2 files changed

+38
-9
lines changed

src/commands/build/upload.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ fn validate_is_supported_build(path: &Path, bytes: &[u8]) -> Result<()> {
378378
debug!("Validating build format for: {}", path.display());
379379

380380
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
381-
if is_apple_app(path) {
381+
if is_apple_app(path)? {
382382
debug!("Detected XCArchive directory");
383383
return Ok(());
384384
}
@@ -452,7 +452,7 @@ fn normalize_file(path: &Path, bytes: &[u8]) -> Result<TempFile> {
452452
fn handle_directory(path: &Path) -> Result<TempFile> {
453453
let temp_dir = TempDir::create()?;
454454
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
455-
if is_apple_app(path) {
455+
if is_apple_app(path)? {
456456
handle_asset_catalogs(path, temp_dir.path());
457457
}
458458
normalize_directory(path, temp_dir.path())

src/utils/build/validation.rs

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
2-
use std::path::Path;
3-
41
use anyhow::Result;
52

3+
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
4+
use {
5+
glob::{glob_with, MatchOptions},
6+
std::path::Path,
7+
};
8+
69
pub fn is_zip_file(bytes: &[u8]) -> bool {
710
if bytes.len() < 4 {
811
return false;
@@ -53,7 +56,7 @@ pub fn is_ipa_file(bytes: &[u8]) -> Result<bool> {
5356
}
5457

5558
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
56-
pub fn is_xcarchive_directory<P>(path: P) -> bool
59+
pub fn validate_xcarchive_directory<P>(path: P) -> Result<()>
5760
where
5861
P: AsRef<Path>,
5962
{
@@ -63,11 +66,37 @@ where
6366
let info_plist = path.join("Info.plist");
6467
let products_dir = path.join("Products");
6568

66-
info_plist.exists() && products_dir.exists() && products_dir.is_dir()
69+
if !info_plist.exists() {
70+
anyhow::bail!("Invalid XCArchive: Missing required Info.plist file at XCArchive root");
71+
}
72+
73+
if !products_dir.exists() || !products_dir.is_dir() {
74+
anyhow::bail!("Invalid XCArchive: Missing Products/ directory");
75+
}
76+
77+
// All .app bundles within the XCArchive should have an Info.plist file
78+
let paths = glob_with(
79+
&path.join("Products/**/*.app").to_string_lossy(),
80+
MatchOptions::new(),
81+
)?;
82+
for app_path in paths.flatten().filter(|path| path.is_dir()) {
83+
if !app_path.join("Info.plist").exists() {
84+
anyhow::bail!(
85+
"Invalid XCArchive: Missing required Info.plist file in .app bundle: {}",
86+
app_path.display()
87+
);
88+
}
89+
}
90+
91+
Ok(())
6792
}
6893

6994
/// A path is an Apple app if it points to an xarchive directory
7095
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
71-
pub fn is_apple_app(path: &Path) -> bool {
72-
path.is_dir() && is_xcarchive_directory(path)
96+
pub fn is_apple_app(path: &Path) -> Result<bool> {
97+
if !path.is_dir() {
98+
return Ok(false);
99+
}
100+
validate_xcarchive_directory(path)?;
101+
Ok(true)
73102
}

0 commit comments

Comments
 (0)