VERIFISDK docsengine v2 · contract 1.5.1 · harness-sdk 1.2.0
Harness authoring

Packaging and boot

The container contract — what the Provisioner supplies, what the image must not contain, and how the entrypoint wires it up.


A harness container serves nothing. It dials out, does its work, and exits. One container per run, torn down on settle.

That is why McpSpec.serves is false for a harness and why a harness can never pass an endpoint-based probe — there is no endpoint. Registration of a harness is by image digest, not by URL.

The entrypoint

This is the production ASM harness's main, unabridged in substance:

import type { RunManifest } from '@pragyacyber/engine-contract';
import { runHarness, GrpcEngineChannel } from '@pragyacyber/harness-sdk';
import { myHarness } from './harness.js';

function required(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`${name} is required but not set — the Provisioner supplies it`);
  return value;
}

async function main(): Promise<void> {
  const manifest = JSON.parse(required('RUN_MANIFEST')) as RunManifest;
  const runToken = required('RUN_TOKEN');
  const grpcAddr = required('ENGINE_GRPC_ADDR');
  // The stable internal ALB base, used to re-discover a live engine and reconnect if
  // this engine is replaced mid-run. Optional: without it a dropped stream cannot recover.
  const httpAddr = process.env['ENGINE_HTTP_ADDR'];

  const channel = new GrpcEngineChannel({
    grpcAddr,
    runId: manifest.runId,
    correlationId: manifest.correlationId,
    runToken,
    keepaliveMs: 30_000,
    ...(httpAddr ? { httpAddr } : {}),
  });

  const outcome = await runHarness(myHarness, manifest, channel);

  // Non-zero exit for a failed run, so the container's own status agrees with what it
  // reported over the wire.
  process.exit(outcome.status === 'done' ? 0 : 1);
}

main().catch((err) => {
  console.error(`failed to start: ${err instanceof Error ? err.message : String(err)}`);
  process.exit(1);
});

The environment contract

VariableRequiredWhat it is
RUN_MANIFESTyesThe full RunManifest as JSON.
RUN_TOKENyesSingle-run bearer token, expires at hardDeadline. Never log it.
ENGINE_GRPC_ADDRyesWhere to dial the engine's gRPC endpoint.
ENGINE_HTTP_ADDRno, but set itThe stable internal ALB base. Without it a dropped stream cannot recover from a task replacement.
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKENonly if you call ctx.model()Short-lived, minted per run. Read by credentialsFromEnv().
AWS_REGIONnoDefaults to us-east-1 in runHarness.

The image

The ASM harness's Dockerfile is the reference. Three decisions in it are load-bearing:

Ship lean. Carry no security tools. Every tool runs on an MCP over a metered slot, so the image is just Node plus the harness. This is what puts tool calls back on the ledger — in-process spawning silently bypassed it.

Non-root. A scanner harness needs no privileges of its own.

No HEALTHCHECK, no EXPOSE. The container serves nothing.

FROM node:22-slim AS deps
WORKDIR /app

# The registry token arrives as a BuildKit SECRET, never an ARG — an ARG is readable
# in the image history, which would bake a credential into every pulled layer.
COPY package.json pnpm-lock.yaml ./
RUN --mount=type=secret,id=npm_token \
    corepack enable && \
    { echo "@pragyacyber:registry=https://npm.pkg.github.com"; \
      echo "//npm.pkg.github.com/:_authToken=$(cat /run/secrets/npm_token)"; } > .npmrc && \
    pnpm install --prod --frozen-lockfile && \
    rm -f .npmrc

FROM node:22-slim AS runtime
WORKDIR /app

RUN groupadd -r verifi && useradd -r -g verifi verifi

COPY --from=deps --chown=verifi:verifi /app/node_modules ./node_modules
COPY --chown=verifi:verifi package.json .npmrc ./
COPY --chown=verifi:verifi src ./src

RUN mkdir -p /app/reports && chown verifi:verifi /app /app/reports

USER verifi
ENV NODE_ENV=production

CMD ["node", "--import", "tsx", "src/main.ts"]

The mkdir -p /app/reports && chown line exists because the WORKDIR is root-owned, so a non-root user cannot create directories in it. If your harness writes anything locally, pre-create and chown the directory.

Registration

An admin registers the built image by digest — not by tag.

export const zHarnessRegistration = z.object({
  id: z.string().min(1),
  name: z.string().min(1),
  /** The ECS task-definition family or image. A harness SERVES NOTHING, so no endpoint. */
  image: z.string().min(1),
  /** REQUIRED. A DIGEST, not a tag — a tag can be repointed after the probe passes. */
  imageDigest: z.string().regex(/^sha256:[0-9a-f]{64}$/, 'must be a sha256 digest, not a tag'),
  semver: z.string().min(1).optional(),
}).strict();

Get the digest from the registry after a push, never from your local tag:

aws ecr describe-images --repository-name my-harness \
  --image-ids imageTag=v1.2.0 --query 'imageDetails[0].imageDigest' --output text

zCompositionSnapshot.harnessDigest carries the same value into every manifest, for the same reason: "what exactly ran" has to be answerable months later for audit, and a tag is a moving target.

How a harness is probed

A harness serves nothing — it boots from a manifest, dials out over gRPC, works and exits. It has no /healthz and no port, so the three-gate HTTP probe is a category error for it, and giving the harnesses registry that probe is why a harness could never reach available.

What is verifiable is the artefact. The harness probe checks:

CheckFailure
an imageDigest is registeredno image digest registered — there is nothing to verify (a harness serves no endpoint to probe)
the image scanner is reachablethe image scanner could not be reached: …
the image has been scannedthis image has never been scanned — "no findings" and "no scan" are different statements, and an unscanned image is not evidence of a safe one
the scan is not stale (default: 30 days)the last scan is N days old — a CVE published since then is invisible to it
no finding at a blocking severity (default: critical, high)the offending severities

That claim matters because a harness runs inside a client's blast radius with brokered credentials. Build lean, keep the base image current, and re-push before the scan ages out.

zHarness (the stored registry record) is a richer shape than both HarnessRegistration and the SDK's HarnessDefinition, and nothing generates one from the other — see Registry objects and Registering a component.

Resource declarations

resources: { cpu: '2', memoryMb: 4096, maxRuntimeMinutes: 1440 },

Set maxRuntimeMinutes honestly. A full-surface sweep with heavy tools legitimately runs for hours, and time is the only ceiling. Because findings stream out as they are produced, a long run is safe — a run that is cut short still keeps everything it found.