From db2f8c59bc7c838de163d15ff12e69327bfd8da0 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Mon, 9 Mar 2026 09:33:21 +0100 Subject: [PATCH 1/7] fix(proguard): Drop redundant line info validation for mapping files The proguard mapper can remap and support files without line information, so the has_line_info() check was unnecessarily rejecting valid mappings. Co-Authored-By: Claude Opus 4.6 --- src/commands/proguard/upload.rs | 5 +-- src/commands/proguard/uuid.rs | 3 +- src/utils/dif.rs | 2 +- src/utils/proguard/mapping.rs | 33 +++---------------- .../proguard/proguard-upload-no-upload.trycmd | 1 - .../proguard-uuid-invalid-mapping.trycmd | 12 ------- .../upload_proguard-no-upload.trycmd | 1 - 7 files changed, 7 insertions(+), 50 deletions(-) delete mode 100644 tests/integration/_cases/proguard/proguard-uuid-invalid-mapping.trycmd diff --git a/src/commands/proguard/upload.rs b/src/commands/proguard/upload.rs index 624b1b9fd4..c1831d32b2 100644 --- a/src/commands/proguard/upload.rs +++ b/src/commands/proguard/upload.rs @@ -95,10 +95,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { // them all up. for path in &paths { match ByteView::open(path) { - Ok(byteview) => match ProguardMapping::try_from(byteview) { - Ok(mapping) => mappings.push(mapping), - Err(e) => eprintln!("warning: ignoring proguard mapping '{path}': {e}"), - }, + Ok(byteview) => mappings.push(ProguardMapping::from(byteview)), Err(ref err) if err.kind() == io::ErrorKind::NotFound => { eprintln!( "warning: proguard mapping '{path}' does not exist. This \ diff --git a/src/commands/proguard/uuid.rs b/src/commands/proguard/uuid.rs index 188825afee..e0a4b3034f 100644 --- a/src/commands/proguard/uuid.rs +++ b/src/commands/proguard/uuid.rs @@ -29,8 +29,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { let byteview = ByteView::open(path) .with_context(|| format!("failed to open proguard mapping '{path}'"))?; - let mapping = ProguardMapping::try_from(byteview) - .with_context(|| format!("failed to parse proguard mapping '{path}'"))?; + let mapping = ProguardMapping::from(byteview); println!("{}", mapping.uuid()); Ok(()) diff --git a/src/utils/dif.rs b/src/utils/dif.rs index cf510dad91..472b58d6cb 100644 --- a/src/utils/dif.rs +++ b/src/utils/dif.rs @@ -380,7 +380,7 @@ impl<'a> DifFile<'a> { pub fn is_usable(&self) -> bool { match self { DifFile::Archive(_) => self.has_ids() && self.features().has_some(), - DifFile::Proguard(pg) => pg.get().has_line_info(), + DifFile::Proguard(..) => true, } } diff --git a/src/utils/proguard/mapping.rs b/src/utils/proguard/mapping.rs index 40117cad5e..51d021d65d 100644 --- a/src/utils/proguard/mapping.rs +++ b/src/utils/proguard/mapping.rs @@ -2,23 +2,16 @@ use std::borrow::Cow; use std::fmt::{Display, Formatter, Result as FmtResult}; use symbolic::common::{ByteView, DebugId}; -use thiserror::Error; use uuid::Uuid; use crate::utils::chunks::Assemblable; -#[derive(Debug, Error)] -pub enum ProguardMappingError { - #[error("Proguard mapping does not contain line information")] - MissingLineInfo, -} - pub struct ProguardMapping<'a> { bytes: ByteView<'a>, uuid: Uuid, } -impl<'a> ProguardMapping<'a> { +impl ProguardMapping<'_> { /// Get the UUID of the mapping. pub fn uuid(&self) -> Uuid { self.uuid @@ -29,31 +22,13 @@ impl<'a> ProguardMapping<'a> { pub fn force_uuid(&mut self, uuid: Uuid) { self.uuid = uuid; } - - /// Create a new `ProguardMapping` from a `ByteView`. - /// Not public because we want to ensure that the `ByteView` contains line - /// information, and this method does not check for that. To create a - /// `ProguardMapping` externally, use the `TryFrom` implementation. - fn new(bytes: ByteView<'a>, uuid: Uuid) -> Self { - Self { bytes, uuid } - } } -impl<'a> TryFrom> for ProguardMapping<'a> { - type Error = ProguardMappingError; - - /// Try to create a `ProguardMapping` from a `ByteView`. - /// The method returns an error if the mapping does not contain - /// line information. - fn try_from(value: ByteView<'a>) -> Result { +impl<'a> From> for ProguardMapping<'a> { + fn from(value: ByteView<'a>) -> Self { let mapping = ::proguard::ProguardMapping::new(&value); - - if !mapping.has_line_info() { - return Err(ProguardMappingError::MissingLineInfo); - } - let uuid = mapping.uuid(); - Ok(ProguardMapping::new(value, uuid)) + Self { bytes: value, uuid } } } diff --git a/tests/integration/_cases/proguard/proguard-upload-no-upload.trycmd b/tests/integration/_cases/proguard/proguard-upload-no-upload.trycmd index b2c1e0a483..a601ef21bc 100644 --- a/tests/integration/_cases/proguard/proguard-upload-no-upload.trycmd +++ b/tests/integration/_cases/proguard/proguard-upload-no-upload.trycmd @@ -1,7 +1,6 @@ ``` $ sentry-cli proguard upload tests/integration/_fixtures/proguard.txt --no-upload ? success -warning: ignoring proguard mapping 'tests/integration/_fixtures/proguard.txt': Proguard mapping does not contain line information > skipping upload. ``` diff --git a/tests/integration/_cases/proguard/proguard-uuid-invalid-mapping.trycmd b/tests/integration/_cases/proguard/proguard-uuid-invalid-mapping.trycmd deleted file mode 100644 index 18cb2afed4..0000000000 --- a/tests/integration/_cases/proguard/proguard-uuid-invalid-mapping.trycmd +++ /dev/null @@ -1,12 +0,0 @@ -``` -$ sentry-cli proguard uuid tests/integration/_fixtures/proguard.txt -? failed -error: failed to parse proguard mapping 'tests/integration/_fixtures/proguard.txt' - -Caused by: - Proguard mapping does not contain line information - -Add --log-level=[info|debug] or export SENTRY_LOG_LEVEL=[info|debug] to see more output. -Please attach the full debug log to all bug reports. - -``` diff --git a/tests/integration/_cases/upload_proguard/upload_proguard-no-upload.trycmd b/tests/integration/_cases/upload_proguard/upload_proguard-no-upload.trycmd index cb30fac691..51b33b8feb 100644 --- a/tests/integration/_cases/upload_proguard/upload_proguard-no-upload.trycmd +++ b/tests/integration/_cases/upload_proguard/upload_proguard-no-upload.trycmd @@ -1,7 +1,6 @@ ``` $ sentry-cli upload-proguard tests/integration/_fixtures/proguard.txt --no-upload ? success -warning: ignoring proguard mapping 'tests/integration/_fixtures/proguard.txt': Proguard mapping does not contain line information > skipping upload. ``` From 7a418025491f7d5af6558cc6d193b3575fdf0904 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Mon, 9 Mar 2026 09:35:06 +0100 Subject: [PATCH 2/7] docs(changelog): Add entry for proguard line info validation removal Co-Authored-By: Claude Opus 4.6 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ce3b4f655..982b5375fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Fixes + +- Accept ProGuard mapping files without line information instead of rejecting them ([#3192](https://github.com/getsentry/sentry-cli/pull/3192)). + ### Experimental Feature 🧑‍🔬 (internal-only) - Pipe snapshot sidecar metadata into upload as part of `sentry-cli build snapshots` command ([#3163](https://github.com/getsentry/sentry-cli/pull/3163)). From af19d68d4fb0e3b05339dfea30e98a4e3a2c93a0 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Mon, 9 Mar 2026 10:03:57 +0100 Subject: [PATCH 3/7] ref(proguard): Mark unreachable Proguard branch in get_problem() Since is_usable() now always returns true for Proguard mappings, the Proguard arm in get_problem() is dead code. Co-Authored-By: Claude Opus 4.6 --- src/utils/dif.rs | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/utils/dif.rs b/src/utils/dif.rs index 472b58d6cb..c61aa47b77 100644 --- a/src/utils/dif.rs +++ b/src/utils/dif.rs @@ -380,24 +380,18 @@ impl<'a> DifFile<'a> { pub fn is_usable(&self) -> bool { match self { DifFile::Archive(_) => self.has_ids() && self.features().has_some(), - DifFile::Proguard(..) => true, + _ => true, } } pub fn get_problem(&self) -> Option<&'static str> { - if self.is_usable() { - None - } else { - Some(match self { - DifFile::Archive(..) => { - if !self.has_ids() { - "missing debug identifier, likely stripped" - } else { - "missing debug or unwind information" - } - } - DifFile::Proguard(..) => "missing line information", - }) + match self { + DifFile::Archive(..) if !self.is_usable() => Some(if !self.has_ids() { + "missing debug identifier, likely stripped" + } else { + "missing debug or unwind information" + }), + _ => None, } } From fc26480d4b9881d47c6259ac58beb0b403430e46 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Mon, 9 Mar 2026 16:10:47 +0100 Subject: [PATCH 4/7] fix(proguard): Address PR feedback - Use exhaustive match instead of wildcard in is_usable() and get_problem() to catch future DifFile variants at compile time - Add test verifying UUID generation succeeds for mappings without line info Co-Authored-By: Claude Opus 4.6 --- src/utils/dif.rs | 4 ++-- .../_cases/proguard/proguard-uuid-no-line-info.trycmd | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 tests/integration/_cases/proguard/proguard-uuid-no-line-info.trycmd diff --git a/src/utils/dif.rs b/src/utils/dif.rs index c61aa47b77..b070ef72b8 100644 --- a/src/utils/dif.rs +++ b/src/utils/dif.rs @@ -380,7 +380,7 @@ impl<'a> DifFile<'a> { pub fn is_usable(&self) -> bool { match self { DifFile::Archive(_) => self.has_ids() && self.features().has_some(), - _ => true, + DifFile::Proguard(..) => true, } } @@ -391,7 +391,7 @@ impl<'a> DifFile<'a> { } else { "missing debug or unwind information" }), - _ => None, + DifFile::Archive(..) | DifFile::Proguard(..) => None, } } diff --git a/tests/integration/_cases/proguard/proguard-uuid-no-line-info.trycmd b/tests/integration/_cases/proguard/proguard-uuid-no-line-info.trycmd new file mode 100644 index 0000000000..e0caea5b65 --- /dev/null +++ b/tests/integration/_cases/proguard/proguard-uuid-no-line-info.trycmd @@ -0,0 +1,6 @@ +``` +$ sentry-cli proguard uuid tests/integration/_fixtures/proguard.txt +? success +5db7294d-87fc-5726-a5c0-4a90679657a5 + +``` From 764ef724852a4f10f98e0077408693a05d06c46f Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Mon, 9 Mar 2026 16:11:52 +0100 Subject: [PATCH 5/7] ref(proguard): Restore original get_problem() structure Co-Authored-By: Claude Opus 4.6 --- src/utils/dif.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/utils/dif.rs b/src/utils/dif.rs index b070ef72b8..b1a9376504 100644 --- a/src/utils/dif.rs +++ b/src/utils/dif.rs @@ -385,14 +385,20 @@ impl<'a> DifFile<'a> { } pub fn get_problem(&self) -> Option<&'static str> { - match self { - DifFile::Archive(..) if !self.is_usable() => Some(if !self.has_ids() { - "missing debug identifier, likely stripped" - } else { - "missing debug or unwind information" - }), - DifFile::Archive(..) | DifFile::Proguard(..) => None, + if self.is_usable() { + return None; } + + Some(match self { + DifFile::Archive(..) => { + if !self.has_ids() { + "missing debug identifier, likely stripped" + } else { + "missing debug or unwind information" + } + } + DifFile::Proguard(..) => return None, + }) } pub fn get_note(&self) -> Option<&'static str> { From 0acc3a9ebefc50cfc22779a3095d5ffefda0978c Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Mon, 9 Mar 2026 16:29:58 +0100 Subject: [PATCH 6/7] ref(proguard): Simplify get_problem() to flat match Co-Authored-By: Claude Opus 4.6 --- src/utils/dif.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/utils/dif.rs b/src/utils/dif.rs index b1a9376504..b070ef72b8 100644 --- a/src/utils/dif.rs +++ b/src/utils/dif.rs @@ -385,20 +385,14 @@ impl<'a> DifFile<'a> { } pub fn get_problem(&self) -> Option<&'static str> { - if self.is_usable() { - return None; + match self { + DifFile::Archive(..) if !self.is_usable() => Some(if !self.has_ids() { + "missing debug identifier, likely stripped" + } else { + "missing debug or unwind information" + }), + DifFile::Archive(..) | DifFile::Proguard(..) => None, } - - Some(match self { - DifFile::Archive(..) => { - if !self.has_ids() { - "missing debug identifier, likely stripped" - } else { - "missing debug or unwind information" - } - } - DifFile::Proguard(..) => return None, - }) } pub fn get_note(&self) -> Option<&'static str> { From 946e52050df04440a3ed4ad2660d670a7569b278 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Mon, 9 Mar 2026 16:30:36 +0100 Subject: [PATCH 7/7] ref(proguard): Keep is_usable() early return in get_problem() Co-Authored-By: Claude Opus 4.6 --- src/utils/dif.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/utils/dif.rs b/src/utils/dif.rs index b070ef72b8..321244f378 100644 --- a/src/utils/dif.rs +++ b/src/utils/dif.rs @@ -385,13 +385,17 @@ impl<'a> DifFile<'a> { } pub fn get_problem(&self) -> Option<&'static str> { + if self.is_usable() { + return None; + } + match self { - DifFile::Archive(..) if !self.is_usable() => Some(if !self.has_ids() { + DifFile::Archive(..) => Some(if !self.has_ids() { "missing debug identifier, likely stripped" } else { "missing debug or unwind information" }), - DifFile::Archive(..) | DifFile::Proguard(..) => None, + DifFile::Proguard(..) => None, } }