Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions test/e2e/live/hermes-gpu-startup-integrity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,18 +76,23 @@ def parse_hash(data, label):
text = data.decode("ascii")
except UnicodeDecodeError:
fail(f"{label} is not ASCII")
if not text.endswith("\\n"):
fail(f"{label} is missing its final newline")
lines = text.splitlines()
parts = text.split("\\n")
if len(parts) != 4 or parts[-1] != "":
fail(f"{label} does not contain exactly three records")
lines = parts[:2]
expected_paths = (str(config_path), str(env_path))
if len(lines) != len(expected_paths):
fail(f"{label} does not contain exactly two records")
digests = []
for line, expected_path in zip(lines, expected_paths):
match = re.fullmatch(r"([0-9a-f]{64}) (.+)", line)
if match is None or match.group(2) != expected_path:
fail(f"{label} contains an unexpected record")
fail(f"{label} contains an unexpected file record")
digests.append(match.group(1))
state_match = re.fullmatch(
r"# nemoclaw-hermes-mcp-state-v1 intended=([0-9a-f]{64}) applied=([0-9a-f]{64})",
parts[2],
)
if state_match is None:
fail(f"{label} contains an unexpected MCP state record")
return tuple(digests)

def digest(data):
Expand Down
78 changes: 76 additions & 2 deletions test/e2e/support/hermes-gpu-startup-integrity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface IntegrityFixture {
}

const roots: string[] = [];
const MCP_STATE_RECORD = `# nemoclaw-hermes-mcp-state-v1 intended=${"1".repeat(64)} applied=${"2".repeat(64)}`;

afterEach(() => {
for (const root of roots.splice(0)) fs.rmSync(root, { recursive: true, force: true });
Expand All @@ -38,7 +39,18 @@ function writeHash(
envPath: string,
env: string,
): void {
fs.writeFileSync(hashPath, `${digest(config)} ${configPath}\n${digest(env)} ${envPath}\n`);
fs.writeFileSync(
hashPath,
`${digest(config)} ${configPath}\n${digest(env)} ${envPath}\n${MCP_STATE_RECORD}\n`,
);
}

function readHashRecords(hashPath: string): string[] {
return fs.readFileSync(hashPath, "utf-8").split("\n").slice(0, -1);
}

function writeHashRecords(hashPath: string, records: readonly string[]): void {
fs.writeFileSync(hashPath, `${records.join("\n")}\n`);
}

function createFixture(): IntegrityFixture {
Expand Down Expand Up @@ -96,7 +108,7 @@ function runProof(fixture: IntegrityFixture, extraEnv: NodeJS.ProcessEnv = {}) {
}

describe("Hermes managed startup integrity proof", () => {
it("accepts a current compatibility hash and one generated API key beyond the strict base", () => {
it("accepts canonical file and MCP state records with one generated API key beyond the strict base (#6427)", () => {
const fixture = createFixture();
const rawStrictCheck = spawnSync("sha256sum", ["-c", fixture.strictHashPath, "--status"], {
encoding: "utf-8",
Expand All @@ -111,6 +123,68 @@ describe("Hermes managed startup integrity proof", () => {
expect(proof.stdout).toBe("OK\n");
});

it("rejects a missing Hermes MCP state record (#6427)", () => {
const fixture = createFixture();
const [configRecord, envRecord] = readHashRecords(fixture.compatHashPath);
writeHashRecords(fixture.compatHashPath, [configRecord!, envRecord!]);

const proof = runProof(fixture);
expect(proof.status).not.toBe(0);
expect(proof.stderr).toContain(
"Hermes compatibility hash does not contain exactly three records",
);
});

it("rejects a malformed Hermes MCP state record (#6427)", () => {
const fixture = createFixture();
const [configRecord, envRecord] = readHashRecords(fixture.compatHashPath);
writeHashRecords(fixture.compatHashPath, [
configRecord!,
envRecord!,
`# nemoclaw-hermes-mcp-state-v1 intended=${"1".repeat(64)} applied=invalid`,
]);

const proof = runProof(fixture);
expect(proof.status).not.toBe(0);
expect(proof.stderr).toContain(
"Hermes compatibility hash contains an unexpected MCP state record",
);
});

it("rejects duplicate Hermes MCP state records (#6427)", () => {
const fixture = createFixture();
const records = readHashRecords(fixture.compatHashPath);
writeHashRecords(fixture.compatHashPath, [...records, MCP_STATE_RECORD]);

const proof = runProof(fixture);
expect(proof.status).not.toBe(0);
expect(proof.stderr).toContain(
"Hermes compatibility hash does not contain exactly three records",
);
});

it("rejects a reordered Hermes MCP state record (#6427)", () => {
const fixture = createFixture();
const [configRecord, envRecord, stateRecord] = readHashRecords(fixture.compatHashPath);
writeHashRecords(fixture.compatHashPath, [stateRecord!, configRecord!, envRecord!]);

const proof = runProof(fixture);
expect(proof.status).not.toBe(0);
expect(proof.stderr).toContain("Hermes compatibility hash contains an unexpected file record");
});

it("rejects unexpected records after the Hermes MCP state record (#6427)", () => {
const fixture = createFixture();
const records = readHashRecords(fixture.compatHashPath);
writeHashRecords(fixture.compatHashPath, [...records, "unexpected"]);

const proof = runProof(fixture);
expect(proof.status).not.toBe(0);
expect(proof.stderr).toContain(
"Hermes compatibility hash does not contain exactly three records",
);
});

it("rejects non-key environment drift even when the compatibility hash accepts it", () => {
const fixture = createFixture();
const config = fs.readFileSync(fixture.configPath, "utf-8");
Expand Down
Loading