From aef80c31059708a710090643d27854222625b2e9 Mon Sep 17 00:00:00 2001 From: Enginex0 Date: Tue, 19 May 2026 05:55:18 +0100 Subject: [PATCH] fix(spoof): emit validation_rejected status The source plan's bulletin-history schema declared a four-value status enum: success, network_error, parse_error, validation_rejected. The poller only ever wrote the first three; when PatchLevelManager.updateTo silently rejected a date for bad format, floor violation, past/future bounds, or atomicWrite IO error, the history still recorded status=success and applied=true because applied was set from isNewer before updateTo ran. Make updateTo return Boolean. Wire the result through fetchAndParse so a rejected apply lands as status=validation_rejected with applied=false and an error string identifying the date that failed. Closes the only spec gap from fancy-humming-firefly.md uncovered during the source-plan cross-audit. --- .../TEESimulator/config/BulletinPoller.kt | 17 ++++++++++++----- .../TEESimulator/config/PatchLevelManager.kt | 13 +++++++------ 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/org/matrix/TEESimulator/config/BulletinPoller.kt b/app/src/main/java/org/matrix/TEESimulator/config/BulletinPoller.kt index 69ce02b..bf5a477 100644 --- a/app/src/main/java/org/matrix/TEESimulator/config/BulletinPoller.kt +++ b/app/src/main/java/org/matrix/TEESimulator/config/BulletinPoller.kt @@ -102,14 +102,21 @@ object BulletinPoller { ) } val current = currentPatch() - if (current == null) { + if (current == null || date <= current) { return FetchResult(ts, "success", code, date, false, null) } - val isNewer = date > current - if (isNewer) { - PatchLevelManager.updateTo(date) + if (PatchLevelManager.updateTo(date)) { + FetchResult(ts, "success", code, date, true, null) + } else { + FetchResult( + ts, + "validation_rejected", + code, + date, + false, + "PatchLevelManager.updateTo rejected $date", + ) } - FetchResult(ts, "success", code, date, isNewer, null) } catch (e: Exception) { FetchResult(ts, "network_error", null, null, false, e.toString()) } finally { diff --git a/app/src/main/java/org/matrix/TEESimulator/config/PatchLevelManager.kt b/app/src/main/java/org/matrix/TEESimulator/config/PatchLevelManager.kt index d92cec2..50dc679 100644 --- a/app/src/main/java/org/matrix/TEESimulator/config/PatchLevelManager.kt +++ b/app/src/main/java/org/matrix/TEESimulator/config/PatchLevelManager.kt @@ -79,15 +79,15 @@ object PatchLevelManager { AndroidDeviceUtils.setProperty("ro.vendor.build.security_patch", date) } - fun updateTo(date: String) { + fun updateTo(date: String): Boolean { if (!DATE_PATTERN.matches(date)) { SystemLogger.warning("PatchLevelManager: invalid date format: $date") - return + return false } val dateInt = date.replace("-", "").toInt() if (dateInt < FLOOR_YYYYMMDD) { SystemLogger.warning("PatchLevelManager: $date below floor $FLOOR_YYYYMMDD") - return + return false } val now = LocalDate.now() val today = now.year * 10000 + now.monthValue * 100 + now.dayOfMonth @@ -95,7 +95,7 @@ object PatchLevelManager { SystemLogger.warning( "PatchLevelManager: $date more than 1y older than today ($today)" ) - return + return false } val maxFuture = now.plusDays(MAX_FUTURE_DAYS).let { @@ -105,16 +105,17 @@ object PatchLevelManager { SystemLogger.warning( "PatchLevelManager: $date more than $MAX_FUTURE_DAYS days in future ($maxFuture)" ) - return + return false } try { atomicWrite(date) } catch (e: Exception) { SystemLogger.error("PatchLevelManager: atomicWrite failed for $date", e) - return + return false } applyToProps(date) SystemLogger.info("PatchLevelManager: applied patch date $date") + return true } private fun resolvePifPatch(): String? {