import assert from 'node:assert/strict'; import { readFile } from 'node:fs/promises'; import test from 'node:test'; const workflowUrl = new URL('../examples/gitea-actions/forgeflow-approved-deploy.yml', import.meta.url); const deployUrl = new URL('../examples/server/forgeflow-deploy', import.meta.url); test('central approved workflow transports signed target evidence only to the root-owned deploy wrapper', async () => { const workflow = await readFile(workflowUrl, 'utf8'); for (const input of [ 'repository', 'environment', 'commit_sha', 'request_id', 'approval_id', 'approval_fingerprint', 'evidence_issued_at', 'evidence_signature', ]) { assert.match(workflow, new RegExp(`\\b${input}:`)); } assert.match(workflow, /\$\{\{ inputs\.repository \}\}/); assert.doesNotMatch(workflow, /\$\{\{ gitea\.repository \}\}/); assert.match(workflow, /FF_APPROVAL_ID.*FF_REQUEST_ID/s); assert.match(workflow, /sudo \/usr\/local\/bin\/forgeflow-deploy/); assert.doesNotMatch(workflow, /actions\/checkout/); assert.doesNotMatch(workflow, /docker compose/); assert.doesNotMatch(workflow, /git\s+-C/); }); test('server wrapper verifies Ed25519 evidence before any live git or compose mutation', async () => { const script = await readFile(deployUrl, 'utf8'); const verifyIndex = script.indexOf('openssl pkeyutl -verify'); const resetIndex = script.indexOf('git -C "$APP_DIR" reset --hard "$SHA"'); const composeIndex = script.indexOf('docker compose -f "$COMPOSE_FILE" up -d --build'); assert.ok(verifyIndex > 0, 'expected cryptographic verification'); assert.ok(resetIndex > verifyIndex, 'git reset must happen after evidence verification'); assert.ok(composeIndex > verifyIndex, 'compose mutation must happen after evidence verification'); assert.match(script, /EVIDENCE_PUBLIC_KEY_FILE="\/etc\/forgeflow\/evidence\.pub"/); assert.match(script, /evidence_owner.*root/s); assert.match(script, /8#022/); assert.match(script, /EVIDENCE_ISSUED_AT >= now_epoch - 1800/); assert.match(script, /"evidence_verified": \$EVIDENCE_VERIFIED/); assert.match(script, /\(\( \$# == 3 \|\| \$# == 4 \|\| \$# == 8 \)\)/); }); test('signed message fields match the AppOps evidence v1 contract and exclude runner-chosen workflow/ref', async () => { const script = await readFile(deployUrl, 'utf8'); const marker = "printf 'forgeflow-evidence-v1\\n%s\\n%s\\n%s\\n%s\\n%s\\n%s\\n%s\\n'"; assert.ok(script.includes(marker)); assert.match( script, /"\$APPROVAL_ID"[\s\\]+"\$APPROVAL_FINGERPRINT"[\s\\]+"\$REPOSITORY"[\s\\]+"\$ENVIRONMENT"[\s\\]+"\$\{SHA,,\}"[\s\\]+"\$REQUEST_ID"[\s\\]+"\$EVIDENCE_ISSUED_AT"/s, ); assert.doesNotMatch(script.slice(0, script.indexOf('APP_DIR=""')), /WORKFLOW|workflow|ref=/); });