mirror of
https://github.com/morluto/rea.git
synced 2026-11-08 07:46:28 +00:00
* docs: organize canonical documentation layout (URGENTE) Group all existing authored guides by domain and ownership, expose complete navigation, and preserve their public routes. Update physical path consumers and release configuration while retaining historical records. Document domain-based specs and ADR slugs without global numbering. Co-Authored-By: Codex <noreply@openai.com> * fix(docs): honor home layout in all-page route verification * style: format reviewed source changes * fix(docs): preserve routes and navigation cache inputs * fix: repair the static-check failures on the default branch (#2895) * fix: repair the static-check failures on the default branch The default branch fails its own required `Static checks` job three ways, so every pull request reports that job as failed regardless of its own change. - `npm run format:check` reports `src/domain/functionComparison.test.ts` and `src/ida/IdaOperationRunner.ts`. - `npm run lint` reports a duplicate `import { join } from "node:path"` in `tests/boundary/mcp/ghidraInventoryMcp.test.ts` (lines 4 and 17). - `npm run typecheck` reports `format: "devin"` missing from the client format union in `src/application/SupportedClients.ts`, and an unchecked index in `tests/boundary/cli/clientProfileLifecycle.test.ts`, whose pair array is inferred as `string[][]`. Apply the pinned formatter, drop the duplicate import, list the `"devin"` format that its own definition already uses, and mark the pair array `as const`. Validation: `npm run check:fast` and `npm run format:check` pass. * fix(setup): keep Devin on the JSON configuration dialect --------- Co-authored-by: 吴佳浩 <wujiahao@supremind.com> Co-authored-by: morluto <76467478+morluto@users.noreply.github.com> * fix(docs): update links after guide relocation * docs: correct verified documentation route counts * fix(docs): update browser capture guide link after move (#2820) Refresh gettext protected-link comments alongside the authored href. Co-authored-by: Codex <noreply@openai.com> * fix(docs): include http3 lab in stable routes * fix(docs): preserve historical release evidence and links * fix(ghidra): restore Windows verifier identity import * docs(wakaru): preserve pinned upstream policy link * docs(index): retain recently added guide links * docs(mcp): preserve parent retention clarification * fix(cli): preserve standalone import guidance * fix(test): preserve translated guide link drift coverage --------- Co-authored-by: Matheus Breguêz <matbrgz@gmail.com> Co-authored-by: Codex <noreply@openai.com> Co-authored-by: morluto <17176810+morluto@users.noreply.github.com> Co-authored-by: 吴佳浩Alben <35291372+XiaoBinGan@users.noreply.github.com> Co-authored-by: 吴佳浩 <wujiahao@supremind.com>
227 lines
7.7 KiB
JavaScript
227 lines
7.7 KiB
JavaScript
import { requireMcpOutput } from "../../lib/mcp-verifier-results.mjs";
|
|
import assert from "node:assert/strict";
|
|
import { execFile } from "node:child_process";
|
|
import { createHash } from "node:crypto";
|
|
import { createReadStream } from "node:fs";
|
|
import { access, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { dirname, join, resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { promisify } from "node:util";
|
|
|
|
import { Client } from "@modelcontextprotocol/client";
|
|
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
|
|
|
|
import { parseEvidence } from "../../../dist/domain/evidence.js";
|
|
import { harmonyApplicationProjectionResultSchema } from "../../../dist/domain/harmony/harmonyApplication.js";
|
|
import fixture from "../../fixtures/harmony/pipeline.json" with { type: "json" };
|
|
|
|
const repository = resolve(dirname(fileURLToPath(import.meta.url)), "../../..");
|
|
const hap = process.env.REA_HARMONY_TEST_HAP;
|
|
if (hap === undefined)
|
|
throw new Error(
|
|
"verify:harmony requires REA_HARMONY_TEST_HAP. Run npm run fixtures:harmony and set it to the downloaded file; see docs/guides/harmony/harmony-analysis.md.",
|
|
);
|
|
await access(hap);
|
|
const hashFile = async (path) => {
|
|
const hash = createHash("sha256");
|
|
for await (const chunk of createReadStream(path)) hash.update(chunk);
|
|
return hash.digest("hex");
|
|
};
|
|
assert.equal(
|
|
await hashFile(hap),
|
|
fixture.sha256,
|
|
"Real HarmonyOS lane requires the pinned Harmony pipeline release fixture",
|
|
);
|
|
const entrypoint =
|
|
process.env.REA_HARMONY_ENTRYPOINT ?? resolve(repository, "scripts/rea.mjs");
|
|
const execute = promisify(execFile);
|
|
const path = resolve(hap);
|
|
const workspace = await mkdtemp(join(tmpdir(), "rea-harmony-verify-"));
|
|
|
|
try {
|
|
const inspectResponse = await execute(
|
|
process.execPath,
|
|
[entrypoint, "inspect-artifact", path, "--format", "json"],
|
|
{ cwd: repository, timeout: 150_000, maxBuffer: 64 * 1024 * 1024 },
|
|
);
|
|
const inspection = parseEvidence(JSON.parse(inspectResponse.stdout));
|
|
assert.equal(inspection.operation, "inspect_artifact");
|
|
assert.equal(inspection.subject?.format, "hap");
|
|
assert.equal(inspection.subject?.digest.sha256, fixture.sha256);
|
|
console.log("PASS CLI inspect_artifact");
|
|
|
|
const projectionInput = JSON.stringify({
|
|
inventory_evidence: [inspection],
|
|
});
|
|
const projectionFile = resolve(workspace, "projection-input.json");
|
|
await writeFile(projectionFile, projectionInput);
|
|
const projectionResponse = await execute(
|
|
process.execPath,
|
|
[
|
|
entrypoint,
|
|
"project-harmony-application-graph",
|
|
projectionFile,
|
|
"--format",
|
|
"json",
|
|
],
|
|
{ cwd: repository, timeout: 150_000, maxBuffer: 64 * 1024 * 1024 },
|
|
);
|
|
const projectionEvidence = parseEvidence(
|
|
JSON.parse(projectionResponse.stdout),
|
|
);
|
|
assert.equal(
|
|
projectionEvidence.operation,
|
|
"project_harmony_application_graph",
|
|
);
|
|
const projection = harmonyApplicationProjectionResultSchema.parse(
|
|
projectionEvidence.normalized_result,
|
|
);
|
|
const repeatResponse = await execute(
|
|
process.execPath,
|
|
[
|
|
entrypoint,
|
|
"project-harmony-application-graph",
|
|
projectionFile,
|
|
"--format",
|
|
"json",
|
|
],
|
|
{ cwd: repository, timeout: 150_000, maxBuffer: 64 * 1024 * 1024 },
|
|
);
|
|
assert.equal(
|
|
JSON.parse(repeatResponse.stdout).normalized_result.projection_id,
|
|
projection.projection_id,
|
|
"projection must be deterministic for the same inventory Evidence",
|
|
);
|
|
|
|
assert.equal(projection.root_format, "hap");
|
|
assert.equal(projection.packaging_model, "stage");
|
|
assert.deepEqual(
|
|
projection.components.manifests.map(({ path }) => path).sort(),
|
|
["module.json", "pack.info"],
|
|
);
|
|
assert.deepEqual(
|
|
projection.components.bytecode.map(({ path }) => path),
|
|
["ets/modules.abc"],
|
|
);
|
|
assert.deepEqual(projection.components.native_libraries, []);
|
|
assert.equal(
|
|
projection.components.resources.length,
|
|
8,
|
|
"resources.index plus every resources/ entry",
|
|
);
|
|
assert.ok(
|
|
projection.components.resources.some(
|
|
({ path }) => path === "resources.index",
|
|
),
|
|
);
|
|
assert.equal(projection.components.javascript.length, 0);
|
|
assert.equal(
|
|
projection.components.signing.length,
|
|
0,
|
|
"this fixture has no META-INF certificate entries; signing status is unverified",
|
|
);
|
|
assert.deepEqual(projection.runtime_families, ["ark"]);
|
|
assert.deepEqual(projection.bridge_candidates, []);
|
|
assert.deepEqual(projection.unavailable_components, []);
|
|
assert.deepEqual(projection.coverage, {
|
|
status: "complete-within-inventory",
|
|
inventory_complete: true,
|
|
});
|
|
assert.ok(
|
|
projection.limitations.some((limitation) =>
|
|
limitation.startsWith(
|
|
"Manifest, module, resource, and signing semantics require a dedicated HarmonyOS provider",
|
|
),
|
|
),
|
|
);
|
|
console.log("PASS CLI project_harmony_application_graph");
|
|
|
|
const transport = new StdioClientTransport({
|
|
command: process.execPath,
|
|
args: [entrypoint, "mcp"],
|
|
cwd: repository,
|
|
env: process.env,
|
|
stderr: "pipe",
|
|
});
|
|
let stderr = "";
|
|
transport.stderr?.on("data", (chunk) => {
|
|
stderr += chunk.toString();
|
|
});
|
|
const client = new Client({
|
|
name: "rea-real-harmony-verifier",
|
|
version: "1",
|
|
});
|
|
try {
|
|
await client.connect(transport, { timeout: 30_000 });
|
|
await client.listTools();
|
|
const opened = await client.callTool(
|
|
{ name: "open_binary", arguments: { path } },
|
|
{ timeout: 150_000 },
|
|
);
|
|
assert.notEqual(opened.isError, true, JSON.stringify(opened));
|
|
assert.equal(opened.structuredContent?.result?.format, "hap");
|
|
assert.equal(opened.structuredContent?.result?.sha256, fixture.sha256);
|
|
const status = await client.callTool(
|
|
{ name: "binary_session", arguments: {} },
|
|
{ timeout: 150_000 },
|
|
);
|
|
assert.notEqual(status.isError, true, JSON.stringify(status));
|
|
assert.equal(status.structuredContent?.result?.open, true);
|
|
assert.equal(status.structuredContent?.result?.format, "hap");
|
|
const inspected = await client.callTool(
|
|
{ name: "inspect_artifact", arguments: {} },
|
|
{ timeout: 150_000 },
|
|
);
|
|
assert.notEqual(inspected.structuredContent, undefined);
|
|
const mcpInspection = parseEvidence(
|
|
requireMcpOutput(inspected, "inspect_artifact"),
|
|
);
|
|
assert.deepEqual(
|
|
mcpInspection.normalized_result,
|
|
inspection.normalized_result,
|
|
);
|
|
console.log("PASS MCP open/status/inspect_artifact parity");
|
|
const response = await client.callTool(
|
|
{
|
|
name: "project_harmony_application_graph",
|
|
arguments: { inventory_evidence: [mcpInspection] },
|
|
},
|
|
{ timeout: 150_000 },
|
|
);
|
|
assert.notEqual(response.structuredContent, undefined);
|
|
const mcpEvidence = parseEvidence(
|
|
requireMcpOutput(response, "project_harmony_application_graph"),
|
|
);
|
|
assert.deepEqual(
|
|
mcpEvidence.normalized_result,
|
|
projectionEvidence.normalized_result,
|
|
);
|
|
console.log("PASS MCP/CLI parity project_harmony_application_graph");
|
|
const closed = await client.callTool(
|
|
{ name: "close_binary", arguments: {} },
|
|
{ timeout: 150_000 },
|
|
);
|
|
assert.notEqual(closed.isError, true, JSON.stringify(closed));
|
|
const empty = await client.callTool(
|
|
{ name: "binary_session", arguments: {} },
|
|
{ timeout: 150_000 },
|
|
);
|
|
assert.notEqual(empty.isError, true, JSON.stringify(empty));
|
|
assert.equal(empty.structuredContent?.result?.open, false);
|
|
assert.equal(
|
|
await hashFile(path),
|
|
fixture.sha256,
|
|
"MCP workflow must preserve source bytes",
|
|
);
|
|
console.log("PASS MCP close and unchanged source bytes");
|
|
} catch (cause) {
|
|
process.stderr.write(stderr);
|
|
throw cause;
|
|
} finally {
|
|
await client.close();
|
|
}
|
|
} finally {
|
|
await rm(workspace, { recursive: true, force: true });
|
|
}
|