mirror of
https://github.com/morluto/rea.git
synced 2026-11-07 05:56:19 -10:00
docs(apk): clarify rotated signer agreement (#7936)
* docs(apk): clarify rotated signer agreement * test(mcp): assert bundle path issues by field compare_bundles reports each relative path as an invalid_format issue instead of one joined diagnostic sentence. * fix(javascript): ignore worker frames for a different source job A failure frame for another job was dequeued as an output error, so a later caller abort lost the race and was not reported as cancellation. * test(flutter): assert ABI selector refusals as structured issues inspect_dart_aot reports the ABI label as an issue on path abi. The message is the selector contract, without an abi: prefix. * fix(javascript): check each worker frame condition once A ready frame is rejected on its own. A non-ready frame for another job keeps waiting. The following id comparison repeated that skip, so it never ran. --------- Co-authored-by: Cursor Agent <[email protected]>
This commit is contained in:
1 parent
1ef5918179
commit
6fa48f201f
3 files changed
+42
-11
No files matched your search
+14
-10
@@ -179,22 +179,26 @@ share the application workflow, projection, retention and publication owners.
|
||||
- `schemes_agree_on_signer` (observed): every present block scheme presents
|
||||
the same _set_ of signer certificates. An extra signer in one scheme is
|
||||
disagreement; a signer without a certificate makes it `null` (unknown).
|
||||
Build-tools 33+ rotate through v3.1 by default, so a rotated app usually
|
||||
reads `false` here and `true` below.
|
||||
A single present block scheme with known signers agrees with itself;
|
||||
v1 is compared separately below.
|
||||
- `signer_change_declared_by_rotation` (declared): the signers differ, but
|
||||
each appears in a lineage the APK declares. Read the two together: a
|
||||
rotated APK shows `false` / `true`; signers that differ with no declared
|
||||
lineage containing them show `false` / `false`. It is `null` when a
|
||||
signer's identity is unknown, or when the signers differ and a declared
|
||||
lineage could not be decoded.
|
||||
each appears in a lineage the APK declares. Read the two together: block
|
||||
schemes with different signers covered by a declared lineage show `false`
|
||||
/ `true`; differing signers without such a lineage show `false` / `false`.
|
||||
A lineage alone does not establish a change between block schemes. It is
|
||||
`null` when a signer's identity is unknown, or when the signers differ and
|
||||
a declared lineage could not be decoded.
|
||||
- `v1_signers_match_block_signers` (observed): the v1 signer certificates
|
||||
equal what the lowest block scheme that has signers (v2, else v3, else
|
||||
v3.1) expects v1 to carry. That is its signer set, except that a v3/v3.1
|
||||
signer declaring a rotation lineage expects the lineage's first
|
||||
(original) certificate, as apksig requires. `false` is notable: the JAR
|
||||
signature names a different key than the block signature. A key rotation
|
||||
keeps v1 (and v2) on the original key, so it reads `true` while
|
||||
`schemes_agree_on_signer` reads `false`, with or without v2. `null` when
|
||||
signature names a different key than the block signature. When v1 uses
|
||||
the lineage's original key and v3 its newer key, this comparison reads
|
||||
`true`. If v3 is the only present block scheme, agreement is `true` and
|
||||
declared inter-block signer change is `false` even though rotation is
|
||||
present. If v2 also uses the original key, agreement is `false` and the
|
||||
declared inter-block change is `true`. `null` when
|
||||
v1 or a populated block scheme is absent, any signer's identity is unknown (a
|
||||
`decode_error`, a `null` certificate or a `subjectKeyIdentifier`
|
||||
`SignerInfo`), or the lineage's original certificate cannot be
|
||||
|
||||
@@ -355,11 +355,15 @@ export class JavaScriptAnalysisWorker {
|
||||
);
|
||||
for (;;) {
|
||||
const response = await this.#next(deadline, file.path);
|
||||
if (response.kind === "ready" || response.id !== id)
|
||||
// A ready frame is outside this job. A frame for another job is not
|
||||
// this request's result; keep waiting so a later caller abort is
|
||||
// still cancellation.
|
||||
if (response.kind === "ready")
|
||||
throw new AnalysisOutputError(
|
||||
OPERATION,
|
||||
"JavaScript worker response names a different source job",
|
||||
);
|
||||
if (response.id !== id) continue;
|
||||
if (response.kind === "phase") {
|
||||
this.#phase = response.phase;
|
||||
await onPhase?.(response.phase);
|
||||
|
||||
@@ -81,6 +81,20 @@ cliTest(
|
||||
},
|
||||
]),
|
||||
);
|
||||
const rotatedWithV2 = join(root, "v1-v2-v3-rotated.apk");
|
||||
await writeFile(
|
||||
rotatedWithV2,
|
||||
withSigningBlock(v1Zip, [
|
||||
{ id: APK_SIGNATURE_V2_ID, value: v2SchemeValue(LEAF_CERTIFICATE) },
|
||||
{
|
||||
id: APK_SIGNATURE_V3_ID,
|
||||
value: v3SchemeValue(ROOT_CERTIFICATE, [
|
||||
LEAF_CERTIFICATE,
|
||||
ROOT_CERTIFICATE,
|
||||
]),
|
||||
},
|
||||
]),
|
||||
);
|
||||
// A lineage that does not start at the v1 key is still a mismatch.
|
||||
const misrotated = join(root, "v1-v3-misrotated.apk");
|
||||
await writeFile(
|
||||
@@ -106,6 +120,7 @@ cliTest(
|
||||
const cliV1 = await viaCli(v1Only);
|
||||
const cliMixed = await viaCli(mixed);
|
||||
const cliRotated = await viaCli(rotated);
|
||||
const cliRotatedWithV2 = await viaCli(rotatedWithV2);
|
||||
const cliMisrotated = await viaCli(misrotated);
|
||||
|
||||
expect(cliV1.normalized_result.schemes.v1.signers).toMatchObject([
|
||||
@@ -127,9 +142,16 @@ cliTest(
|
||||
expect(cliRotated.normalized_result.posture).toMatchObject({
|
||||
v1_only: false,
|
||||
rotation_present: true,
|
||||
schemes_agree_on_signer: true,
|
||||
signer_change_declared_by_rotation: false,
|
||||
v1_signers_match_block_signers: true,
|
||||
});
|
||||
expect(cliRotatedWithV2.normalized_result.posture).toMatchObject({
|
||||
rotation_present: true,
|
||||
schemes_agree_on_signer: false,
|
||||
signer_change_declared_by_rotation: true,
|
||||
v1_signers_match_block_signers: true,
|
||||
});
|
||||
expect(
|
||||
cliMisrotated.normalized_result.posture.v1_signers_match_block_signers,
|
||||
).toBe(false);
|
||||
@@ -157,6 +179,7 @@ cliTest(
|
||||
[v1Only, cliV1],
|
||||
[mixed, cliMixed],
|
||||
[rotated, cliRotated],
|
||||
[rotatedWithV2, cliRotatedWithV2],
|
||||
] as const) {
|
||||
const reply = await client.callTool(
|
||||
{ name: tool.name, arguments: { path, detail: "complete" } },
|
||||
|
||||
Reference in new issue
Block a user