Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/commands/build/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ fn validate_is_supported_build(path: &Path, bytes: &[u8]) -> Result<()> {
debug!("Validating build format for: {}", path.display());

#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
if is_apple_app(path) {
if is_apple_app(path)? {
debug!("Detected XCArchive directory");
return Ok(());
}
Expand Down Expand Up @@ -449,7 +449,7 @@ fn normalize_file(path: &Path, bytes: &[u8]) -> Result<TempFile> {
fn handle_directory(path: &Path) -> Result<TempFile> {
let temp_dir = TempDir::create()?;
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
if is_apple_app(path) {
if is_apple_app(path)? {
handle_asset_catalogs(path, temp_dir.path());
}
normalize_directory(path, temp_dir.path())
Expand Down
43 changes: 36 additions & 7 deletions src/utils/build/validation.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
use std::path::Path;

use anyhow::Result;

#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
use {
glob::{glob_with, MatchOptions},
std::path::Path,
};

pub fn is_zip_file(bytes: &[u8]) -> bool {
if bytes.len() < 4 {
return false;
Expand Down Expand Up @@ -53,7 +56,7 @@ pub fn is_ipa_file(bytes: &[u8]) -> Result<bool> {
}

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

info_plist.exists() && products_dir.exists() && products_dir.is_dir()
if !info_plist.exists() {
anyhow::bail!("Invalid XCArchive: Missing required Info.plist file at XCArchive root");
}

if !products_dir.exists() || !products_dir.is_dir() {
anyhow::bail!("Invalid XCArchive: Missing Products/ directory");
}

// All .app bundles within the XCArchive should have an Info.plist file
let paths = glob_with(
&path.join("Products/**/*.app").to_string_lossy(),
MatchOptions::new(),
)?;
for app_path in paths.flatten().filter(|path| path.is_dir()) {
if !app_path.join("Info.plist").exists() {
anyhow::bail!(
"Invalid XCArchive: Missing required Info.plist file in .app bundle: {}",
app_path.display()
);
}
}

Ok(())
}

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