Skip to content
Draft
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
39 changes: 21 additions & 18 deletions .github/workflows/verify.yml
Original file line number Diff line number Diff line change
@@ -1,38 +1,41 @@
name: Riverbraid Verification Gate

on:
push:
branches: [ main ]
branches: [main]
pull_request:
branches: [ main ]
branches: [main]
workflow_dispatch:

permissions:
contents: read

jobs:
verify:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- name: Checkout Repository
uses: actions/checkout@v4
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262

- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: '20.11.0'
node-version: '24.11.1'

- name: Install Dependencies
run: |
set -euo pipefail
if [ -f package-lock.json ]; then
npm ci
npm ci --ignore-scripts
else
echo "No package-lock.json found. Skipping dependency install."
fi
- name: Execute Riverbraid Verifier

- name: Execute positive verifier path
run: |
if [ -f verify.mjs ]; then
node verify.mjs
elif [ -f package.json ] && grep -q '"verify":' package.json 2>/dev/null; then
npm run verify
elif [ -f package.json ] && grep -q '"test":' package.json 2>/dev/null; then
npm test
else
echo "Error: No standard verifier found."
exit 1
fi
set -euo pipefail
node verify.mjs
node -e "const fs=require('fs'); const r=JSON.parse(fs.readFileSync('verify-output.json','utf8')); if(r.status!=='VERIFIED'||r.failure_codes.length!==0) process.exit(1); console.log('REFUSAL_GOLD_POSITIVE_PASS')"

- name: Execute isolated fail-closed negative path
run: node tests/verify-fail-closed.mjs
45 changes: 45 additions & 0 deletions tests/verify-fail-closed.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { spawnSync } from "node:child_process";

const repoRoot = process.cwd();
const requiredFiles = [
"verify.mjs",
"index.js",
"protocol.steps",
"package.json",
"AUTHORITY.md",
"RING.md"
];

const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "riverbraid-refusal-fail-closed-"));

try {
for (const file of requiredFiles) {
fs.copyFileSync(path.join(repoRoot, file), path.join(tempRoot, file));
}

fs.rmSync(path.join(tempRoot, "AUTHORITY.md"));

const result = spawnSync(process.execPath, ["verify.mjs"], {
cwd: tempRoot,
encoding: "utf8"
});

assert.equal(result.status, 1, `expected exit code 1, received ${result.status}`);

const outputPath = path.join(tempRoot, "verify-output.json");
assert.equal(fs.existsSync(outputPath), true, "verify-output.json must be written on failure");

const output = JSON.parse(fs.readFileSync(outputPath, "utf8"));
assert.equal(output.status, "FILES_PRESENT_UNVERIFIED");
assert.equal(output.missing_files.includes("AUTHORITY.md"), true);
assert.equal(output.failure_codes.includes("REQUIRED_FILES_MISSING"), true);
assert.equal(output.claim_boundary, "declared-conditions-only");

console.log("REFUSAL_GOLD_FAIL_CLOSED_NEGATIVE_PASS");
} finally {
fs.rmSync(tempRoot, { recursive: true, force: true });
}
Loading