mirror of
https://github.com/newliver666/apk-reverse.git
synced 2026-09-28 21:56:59 +02:00
Register the ASC indexers as capabilities so G2 reports them instead of guessing
The kit documented rasc and told the reader to reach for it first, but nothing knew whether it was
present: doctor.py had no entry for either indexer, so an environment gate could not answer "is the
fastest indexer available here", and the reference file had no way to say where a built binary lives.
capabilities.py two new capabilities, dex_index_rust and dex_index_python, plus the two tool atoms
they depend on. rasc's install line is its build command, because that is what
acquiring it means; its cost is marked measured (a clean clone built in 117 s here)
rather than estimated. The probe also accepts the work-area path that
rasc_build.py builds into, so a machine that followed the kit's own instructions
is not reported as BLOCKED.
doctor.py reports both, with the next action on the blocked one. Verified: OK with the built
binary present, BLOCKED with the build command when it is moved away.
toolchain.md says the capability is registered, so G2 does not have to guess.
Also fixed, found while verifying this: `doctor.py --json` printed the RESULT= token after the JSON
document, so its output was not parseable by the tool the flag exists for. Same defect that was fixed
in check_commands.py; the status stays a field in the document and the exit code carries the meaning.
Gates: check_repo 0, check_refs 0 dangling, check_routing coherent, check_budget 0, check_commands 0
drift, pytest 625 passed, flake8 0, mypy clean over 55 files.
This commit is contained in:
@@ -56,6 +56,13 @@ python scripts/rasc_build.py --build # needs git + rustup; ~2 min
|
||||
python scripts/rasc_build.py --verify app.apk # compares class sets against droidasc, fails on a difference
|
||||
```
|
||||
|
||||
**It is a registered capability, so G2 does not have to guess:** `doctor.py` reports `dex_index_rust`
|
||||
as `OK` when a binary is present (PATH, `APKREV_TOOLS`, or the work-area path `rasc_build.py` builds
|
||||
into) and `BLOCKED` with that build command as the next action when it is not — alongside
|
||||
`dex_index_python` for the `pip install` route. A machine with neither is not stuck: the Python
|
||||
indexer is one command away, and the two are cross-checked against each other by
|
||||
`rasc_build.py --verify`.
|
||||
|
||||
**The one thing to know before trusting its `getclass`:** on an `enum` whose constants override an
|
||||
abstract method, the outer class is printed as a bare constant list and the per-constant bodies are
|
||||
**not inlined** — no warning, and none in the Python tool either, because both leave those bodies in
|
||||
|
||||
@@ -190,6 +190,27 @@ ATOMS = {
|
||||
'est_minutes': 5,
|
||||
'basis': 'unverified',
|
||||
},
|
||||
'tool:rasc': {
|
||||
'name': 'rasc (Rust ASC: whole-APK dex index)',
|
||||
'kind': 'tool',
|
||||
'tool': 'rasc',
|
||||
'install': 'it ships no artifact -- run `python scripts/rasc_build.py --build` '
|
||||
'(needs git plus rustup; on Windows the GNU host toolchain also needs a '
|
||||
'64-bit MinGW-w64 gcc), or set RASC to an existing binary',
|
||||
'est_minutes': 5,
|
||||
# Measured here: a clean clone built in 117 s once the toolchain existed, which is the
|
||||
# toolchain-acquisition cost on top. The toolchain itself is the larger part and is
|
||||
# machine-specific, so the estimate covers the build step and says so.
|
||||
'basis': 'measured',
|
||||
},
|
||||
'tool:droidasc': {
|
||||
'name': 'droidasc (Python ASC: whole-APK dex index)',
|
||||
'kind': 'tool',
|
||||
'tool': 'droidasc',
|
||||
'install': 'pip install droidasc',
|
||||
'est_minutes': 1,
|
||||
'basis': 'measured',
|
||||
},
|
||||
'tool:apktool': {
|
||||
'name': 'apktool (resource round-trip)',
|
||||
'kind': 'tool',
|
||||
@@ -317,6 +338,24 @@ GATE_FILES = {
|
||||
# `depends_on` is expanded recursively, so a prerequisite's blockers are inherited.
|
||||
|
||||
CAPABILITIES = {
|
||||
'dex_index_rust': {
|
||||
'name': 'Whole-APK dex index and single-class decompilation (rasc, the Rust ASC)',
|
||||
'required': ['python39', 'tool:rasc'],
|
||||
'optional': [],
|
||||
'scripts': ['rasc_build.py'],
|
||||
'note': 'the fastest indexer this kit documents -- same answers as droidasc on '
|
||||
'both archives measured, 4-15x quicker -- but it ships no prebuilt '
|
||||
'artifact, so `rasc_build.py --build` is how a machine acquires it. Its '
|
||||
'outer-class view of an enum does not inline the constant bodies; the '
|
||||
'subclasses decompile fine (references/rasc-and-droidsaw.md)',
|
||||
},
|
||||
'dex_index_python': {
|
||||
'name': 'Whole-APK dex index and single-class decompilation (droidasc, the Python ASC)',
|
||||
'required': ['python39', 'tool:droidasc'],
|
||||
'optional': [],
|
||||
'note': 'one `pip install droidasc` away, and the cross-check for the Rust one: '
|
||||
'their class-definition sets are compared in scripts/rasc_build.py --verify',
|
||||
},
|
||||
'static_dex': {
|
||||
'name': 'Static dex / zip / strings analysis',
|
||||
'required': ['python39'],
|
||||
@@ -520,6 +559,18 @@ class Probe:
|
||||
if name in self._tool_cache:
|
||||
return self._tool_cache[name]
|
||||
hit = shutil.which(name)
|
||||
if not hit and name == 'rasc':
|
||||
# rasc ships no artifact, so a machine that followed this kit's own build step has it
|
||||
# under the repository's ignored work area rather than on PATH. Accepting that location
|
||||
# keeps the capability table from reporting BLOCKED at an agent that already did the
|
||||
# work -- the same reasoning as APKREV_TOOLS, for the one tool whose install step is a
|
||||
# build (scripts/rasc_build.py).
|
||||
for cand in (os.path.join(REPO_ROOT, 'tools', '_work', 'rust', 'target', 'release',
|
||||
'rasc' + ('.exe' if os.name == 'nt' else '')),
|
||||
os.environ.get('RASC', '')):
|
||||
if cand and os.path.isfile(cand):
|
||||
hit = cand
|
||||
break
|
||||
if not hit:
|
||||
exts = [''] if os.name != 'nt' else ['.exe', '.bat', '.cmd', '.ps1', '']
|
||||
for d in extra_tool_dirs():
|
||||
|
||||
@@ -561,7 +561,10 @@ def main():
|
||||
'blocked': counts['blocked'], 'unknown': counts['unknown']},
|
||||
}
|
||||
print(json.dumps(payload, indent=2, ensure_ascii=False))
|
||||
print('RESULT=%s' % token)
|
||||
# No `RESULT=` line on this path: appending one makes the stream invalid JSON for a caller
|
||||
# doing `--json | jq` or `json.loads(stdout)`, which is what `--json` is for. The status is a
|
||||
# field in the document, and the exit code carries the same meaning. (Same defect that was
|
||||
# found in check_commands.py, and it was found here by trying to parse this output.)
|
||||
return code
|
||||
|
||||
print('=' * 74)
|
||||
|
||||
Reference in New Issue
Block a user