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.
This commit is contained in:
Enginex0
2026-05-19 05:55:18 +01:00
parent 99957e18c4
commit d15abe3c62
2 changed files with 19 additions and 11 deletions
@@ -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 {
@@ -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? {