← Files OpsTruthARCHIVED FILE

test/protocol.test.js

6.86 KB · Oct 2, 2026 · 00:31 UTC

↓ Download file

import assert from "node:assert/strict";
import test from "node:test";
import { readFile } from "node:fs/promises";
import { verifyExecutionOutcome } from "../src/post-execution.js";
import { signProtocolArtifact, verifyHandoffChain, verifyProtocolArtifact } from "../src/protocol.js";
import { loadRepositorySnapshot } from "../src/github.js";
import { validateAgainstSchema } from "../scripts/validate-contracts.mjs";
import { installGithubFetchMock } from "./fixtures.js";
import { protocolChain } from "./protocol-fixtures.js";

const resultSchema = JSON.parse(await readFile(new URL("../contracts/verification-result.schema.json", import.meta.url), "utf8"));

test("protocol artifacts use valid canonical digests, signatures and explicit trust", async () => {
  const chain = await protocolChain();
  const trusted = [chain.authorization.proof.signerFingerprint, chain.receipt.proof.signerFingerprint];
  const verification = await verifyHandoffChain(chain, { now: "2026-08-27T12:10:00Z", trustedSignerFingerprints: trusted });
  assert.equal(verification.valid, true);
  assert.equal(verification.authorization.signatureValid, true);
  assert.equal(verification.authorization.trusted, true);
  assert.equal(verification.receipt.signatureValid, true);
  assert.equal(verification.replayStatus, "unproven");
});

test("tampered and over-broad handoff chains fail closed", async () => {
  const chain = await protocolChain();
  const tampered = structuredClone(chain.authorization);
  tampered.grantedOperations.push("deploy");
  const artifact = await verifyProtocolArtifact(tampered, { now: "2026-08-27T12:10:00Z" });
  assert.equal(artifact.digestValid, false);
  assert.equal(artifact.signatureValid, false);
  const verification = await verifyHandoffChain({ ...chain, authorization: tampered }, { now: "2026-08-27T12:10:00Z" });
  assert.equal(verification.valid, false);
  assert.ok(verification.errors.includes("authorization_scope_expansion:deploy"));
});

test("expired, replayed and untrusted handoffs remain distinct failures", async () => {
  const chain = await protocolChain();
  const expired = await verifyHandoffChain(chain, { now: "2026-08-29T12:10:00Z" });
  assert.equal(expired.valid, false);
  assert.ok(expired.errors.includes("request:artifact_expired"));
  assert.ok(expired.errors.includes("authorization:artifact_expired"));

  const replayed = await verifyHandoffChain(chain, {
    now: "2026-08-27T12:10:00Z",
    trustedSignerFingerprints: [chain.authorization.proof.signerFingerprint, chain.receipt.proof.signerFingerprint],
    consumedNonces: new Set([chain.authorization.nonce]),
  });
  assert.equal(replayed.replayStatus, "replayed");
  assert.equal(replayed.valid, false);
  assert.ok(replayed.errors.includes("authorization_nonce_replayed"));

  const untrusted = await verifyProtocolArtifact(chain.receipt, { now: "2026-08-27T12:10:00Z", trustedSignerFingerprints: [] });
  assert.equal(untrusted.signatureValid, true);
  assert.equal(untrusted.trusted, false);

  const future = await verifyProtocolArtifact(chain.authorization, { now: "2026-08-27T11:00:00Z" });
  assert.ok(future.errors.includes("issuedAt_in_future"));
});

test("authorizer, executor and verifier signing identities remain separate", async () => {
  const chain = await protocolChain();
  const receiptPayload = structuredClone(chain.receipt);
  delete receiptPayload.digest;
  delete receiptPayload.proof;
  const sameIdentityReceipt = await signProtocolArtifact(receiptPayload, chain.authorizerEnv);
  const handoff = await verifyHandoffChain({ ...chain, receipt: sameIdentityReceipt }, {
    now: "2026-08-27T12:10:00Z",
    trustedAuthorizerFingerprints: [chain.authorization.proof.signerFingerprint],
    trustedExecutorFingerprints: [sameIdentityReceipt.proof.signerFingerprint],
  });
  assert.equal(handoff.valid, false);
  assert.ok(handoff.errors.includes("authorizer_executor_signing_identity_not_separate"));

  const restore = installGithubFetchMock();
  try {
    const snapshot = await loadRepositorySnapshot("Example/project", {}, {});
    const outcome = await verifyExecutionOutcome({
      ...chain,
      repositorySnapshot: snapshot,
      trustedAuthorizerFingerprints: [chain.authorization.proof.signerFingerprint],
      trustedExecutorFingerprints: [chain.receipt.proof.signerFingerprint],
      observedAt: "2026-08-27T12:10:00Z",
      env: chain.authorizerEnv,
    });
    assert.equal(outcome.result.verdict, "CONTRADICTED");
    assert.ok(outcome.result.errors.includes("verifier_authorizer_signing_identity_not_separate"));
  } finally {
    restore();
  }
});

test("post-execution verification ignores executor success and uses fresh bound evidence", async () => {
  const restore = installGithubFetchMock();
  try {
    const chain = await protocolChain();
    const snapshot = await loadRepositorySnapshot("Example/project", {}, {});
    const trusted = [chain.authorization.proof.signerFingerprint, chain.receipt.proof.signerFingerprint];
    const verified = await verifyExecutionOutcome({
      ...chain,
      repositorySnapshot: snapshot,
      trustedSignerFingerprints: trusted,
      observedAt: "2026-08-27T12:10:00Z",
      env: chain.verifierEnv,
    });
    assert.equal(verified.result.verdict, "VERIFIED");
    assert.equal(verified.result.assertionResults[0].verdict, "VERIFIED");
    assert.notEqual(verified.result.proof.signerFingerprint, chain.receipt.proof.signerFingerprint);
    assert.deepEqual(validateAgainstSchema(verified.result, resultSchema), []);

    const forged = structuredClone(chain.receipt);
    forged.executionState = "FAILED";
    const rejected = await verifyExecutionOutcome({
      request: chain.request,
      authorization: chain.authorization,
      receipt: forged,
      repositorySnapshot: snapshot,
      trustedSignerFingerprints: trusted,
      observedAt: "2026-08-27T12:10:00Z",
      env: chain.verifierEnv,
    });
    assert.notEqual(rejected.result.verdict, "VERIFIED");
    assert.ok(rejected.result.errors.some((error) => /receipt:.*mismatch|receipt:signature_invalid/.test(error)));
  } finally {
    restore();
  }
});

test("post-execution verification rejects a different repository subject", async () => {
  const restore = installGithubFetchMock();
  try {
    const chain = await protocolChain();
    chain.request.subject.repositoryId = "999999";
    chain.request.digest = await (await import("../src/protocol.js")).computeArtifactDigest(chain.request);
    const snapshot = await loadRepositorySnapshot("Example/project", {}, {});
    const outcome = await verifyExecutionOutcome({
      ...chain,
      repositorySnapshot: snapshot,
      trustedSignerFingerprints: [chain.authorization.proof.signerFingerprint, chain.receipt.proof.signerFingerprint],
      observedAt: "2026-08-27T12:10:00Z",
      env: chain.verifierEnv,
    });
    assert.notEqual(outcome.result.verdict, "VERIFIED");
    assert.ok(outcome.result.errors.includes("subject_repository_mismatch"));
  } finally {
    restore();
  }
});

SHA-256: 66fdd987a3364ea50106db0fa8a472c651837be6b7ccb78706dd836920f462ca