Skip to content
This repository was archived by the owner on May 12, 2026. It is now read-only.

Commit 183c963

Browse files
toraidlcodex
andcommitted
feat: improve diff-report readability with partition groups and risk highlights
Enhance artifact diff output with partition-grouped file changes, critical-path highlights, and derived risk flags (high-impact paths, identity property changes, priv-app changes, init-script changes). This makes post-porting review faster by surfacing likely boot/security-impacting deltas without manual filtering. Add regression assertions for grouped output and highlight/risk sections in tests/test_diff_report.py. Verification: - .venv/bin/python -m ruff check src/app/diff_report.py tests/test_diff_report.py - .venv/bin/python -m mypy --config-file mypy-curated.ini - .venv/bin/python -m pytest -q tests/test_diff_report.py - .venv/bin/python -m pytest -q Co-authored-by: OpenAI Codex <noreply@openai.com>
1 parent 01b5e8d commit 183c963

2 files changed

Lines changed: 145 additions & 5 deletions

File tree

src/app/diff_report.py

Lines changed: 139 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,30 @@
1010
from pathlib import Path
1111
from typing import Any
1212

13+
PARTITION_KEYS = {
14+
"system",
15+
"product",
16+
"system_ext",
17+
"vendor",
18+
"odm",
19+
"mi_ext",
20+
"vendor_dlkm",
21+
"vendor_boot",
22+
"boot",
23+
}
24+
25+
CRITICAL_PATH_MARKERS = (
26+
"/etc/selinux/",
27+
"/sepolicy/",
28+
"build.prop",
29+
"file_contexts",
30+
"fs_config",
31+
"/etc/init/",
32+
"init.rc",
33+
"/framework/",
34+
"/priv-app/",
35+
)
36+
1337

1438
def _sha256(path: Path) -> str:
1539
digest = hashlib.sha256()
@@ -126,6 +150,102 @@ def _diff_map(before: dict[str, Any], after: dict[str, Any]) -> dict[str, list[s
126150
}
127151

128152

153+
def _partition_for_path(path: str) -> str:
154+
first = path.split("/", 1)[0]
155+
if first in PARTITION_KEYS:
156+
return first
157+
return "_root"
158+
159+
160+
def _group_paths_by_partition(paths: list[str]) -> dict[str, list[str]]:
161+
grouped: dict[str, list[str]] = {}
162+
for path in paths:
163+
partition = _partition_for_path(path)
164+
grouped.setdefault(partition, []).append(path)
165+
for partition, entries in grouped.items():
166+
grouped[partition] = sorted(entries)
167+
return dict(sorted(grouped.items(), key=lambda item: item[0]))
168+
169+
170+
def _collect_critical_path_changes(
171+
file_changes: dict[str, list[str]], apk_changes: list[dict[str, Any]]
172+
) -> list[str]:
173+
candidates = file_changes["added"] + file_changes["removed"] + file_changes["modified"]
174+
candidates.extend(change["path"] for change in apk_changes)
175+
critical = []
176+
for path in candidates:
177+
if any(marker in path for marker in CRITICAL_PATH_MARKERS):
178+
critical.append(path)
179+
return sorted(set(critical))
180+
181+
182+
def _build_risk_flags(
183+
file_changes: dict[str, list[str]],
184+
prop_changes: list[dict[str, Any]],
185+
apk_changes: list[dict[str, Any]],
186+
critical_paths: list[str],
187+
) -> list[dict[str, Any]]:
188+
flags: list[dict[str, Any]] = []
189+
190+
if critical_paths:
191+
flags.append(
192+
{
193+
"code": "HIGH_IMPACT_PATH_CHANGED",
194+
"message": "Critical system/security paths changed.",
195+
"paths": critical_paths,
196+
}
197+
)
198+
199+
identity_prop_paths = sorted(
200+
{
201+
item["path"]
202+
for item in prop_changes
203+
if item["key"].startswith("ro.product.")
204+
or item["key"].startswith("ro.build.fingerprint")
205+
}
206+
)
207+
if identity_prop_paths:
208+
flags.append(
209+
{
210+
"code": "IDENTITY_PROP_CHANGED",
211+
"message": "Device identity properties changed.",
212+
"paths": identity_prop_paths,
213+
}
214+
)
215+
216+
priv_app_paths = sorted(
217+
{
218+
change["path"]
219+
for change in apk_changes
220+
if "/priv-app/" in change["path"] or change["path"].startswith("priv-app/")
221+
}
222+
)
223+
if priv_app_paths:
224+
flags.append(
225+
{
226+
"code": "PRIV_APP_CHANGED",
227+
"message": "Privileged APK content changed.",
228+
"paths": priv_app_paths,
229+
}
230+
)
231+
232+
init_related = sorted(
233+
path
234+
for path in (file_changes["added"] + file_changes["removed"] + file_changes["modified"])
235+
if "/etc/init/" in path or path.endswith("init.rc")
236+
)
237+
if init_related:
238+
flags.append(
239+
{
240+
"code": "INIT_SCRIPT_CHANGED",
241+
"message": "Init scripts changed and may affect boot.",
242+
"paths": init_related,
243+
}
244+
)
245+
246+
return flags
247+
248+
129249
def generate_diff_report(before: dict[str, Any], after: dict[str, Any]) -> dict[str, Any]:
130250
"""Generate a structured artifact diff report."""
131251
file_scope = _diff_map(before.get("files", {}), after.get("files", {}))
@@ -169,25 +289,39 @@ def generate_diff_report(before: dict[str, Any], after: dict[str, Any]) -> dict[
169289
}
170290
)
171291

292+
file_changes = {
293+
"added": file_scope["added"],
294+
"removed": file_scope["removed"],
295+
"modified": modified_files,
296+
}
297+
critical_paths = _collect_critical_path_changes(file_changes, apk_changes)
298+
risk_flags = _build_risk_flags(file_changes, prop_changes, apk_changes, critical_paths)
299+
172300
return {
173301
"summary": {
174302
"files_added": len(file_scope["added"]),
175303
"files_removed": len(file_scope["removed"]),
176304
"files_modified": len(modified_files),
177305
"prop_changes": len(prop_changes),
178306
"apk_changes": len(apk_changes),
307+
"risk_flags": len(risk_flags),
179308
},
180-
"files": {
181-
"added": file_scope["added"],
182-
"removed": file_scope["removed"],
183-
"modified": modified_files,
184-
},
309+
"files": file_changes,
185310
"build_props": {
186311
"added_files": prop_scope["added"],
187312
"removed_files": prop_scope["removed"],
188313
"changes": prop_changes,
189314
},
190315
"apks": apk_changes,
316+
"partition_groups": {
317+
"added": _group_paths_by_partition(file_scope["added"]),
318+
"removed": _group_paths_by_partition(file_scope["removed"]),
319+
"modified": _group_paths_by_partition(modified_files),
320+
},
321+
"highlights": {
322+
"critical_path_changes": critical_paths,
323+
"risk_flags": risk_flags,
324+
},
191325
}
192326

193327

tests/test_diff_report.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,9 @@ def test_generate_diff_report_tracks_file_and_prop_changes(tmp_path: Path):
2929
and item["after"] == "device_b"
3030
for item in report["build_props"]["changes"]
3131
)
32+
assert "system/new.conf" in report["partition_groups"]["added"]["system"]
33+
assert "system/build.prop" in report["highlights"]["critical_path_changes"]
34+
assert any(
35+
flag["code"] == "IDENTITY_PROP_CHANGED"
36+
for flag in report["highlights"]["risk_flags"]
37+
)

0 commit comments

Comments
 (0)