Ctrl K
ComunidadGuías…

scripts/verification-fixtures.mjs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env node
import { lstatSync, readFileSync } from 'node:fs';
import { isAbsolute, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { parseArgs } from 'node:util';

import { outsideGit } from './lib/private-evidence.mjs';
import { fixtureReadiness } from './lib/verification-fixtures.mjs';

function readPrivateJson(file) {
  if (!isAbsolute(file)) throw new Error('Input paths must be absolute.');
  const initial = lstatSync(file);
  if (!initial.isFile() || initial.isSymbolicLink() || initial.size > 8 * 1024 * 1024) throw new Error('Input must be a bounded private regular file.');
  const path = outsideGit(file);
  const stat = lstatSync(path);
  if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 8 * 1024 * 1024) throw new Error('Input must be a bounded private regular file.');
  return JSON.parse(readFileSync(path, 'utf8'));
}

export function runFixtureCli(argv, io = {}) {
  const stdout = io.stdout ?? ((value) => process.stdout.write(value));
  const stderr = io.stderr ?? ((value) => process.stderr.write(value));
  try {
    const { values, positionals } = parseArgs({ args: argv, allowPositionals: true, options: {
      spec: { type: 'string' }, inventory: { type: 'string' }, operation: { type: 'string' },
      'reset-rights': { type: 'string' }, from: { type: 'string' }, to: { type: 'string' },
      'max-age-ms': { type: 'string' }, help: { type: 'boolean' },
    } });
    if (values.help) { stdout('Usage: verification-fixtures.mjs readiness --spec FILE --inventory FILE [--operation ID] [--reset-rights RIGHT] [--from RELEASE --to RELEASE] [--max-age-ms MS]\nRead-only advisory: this command creates no fixture reservation or authorization.\n'); return 0; }
    if (positionals.length !== 1 || positionals[0] !== 'readiness' || !values.spec || !values.inventory) throw new Error('Choose readiness and pass --spec and --inventory.');
    if ((values.from === undefined) !== (values.to === undefined)) throw new Error('Pass --from and --to together.');
    if (values['reset-rights'] && !['none', 'restore', 'dispose'].includes(values['reset-rights'])) throw new Error('Choose reset rights none, restore, or dispose.');
    for (const value of [values.operation, values.from, values.to].filter(Boolean)) {
      if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(value)) throw new Error('Operation and release selectors must be aliases.');
    }
    const maxAgeMs = values['max-age-ms'] === undefined ? undefined : Number(values['max-age-ms']);
    const result = fixtureReadiness(readPrivateJson(values.spec), readPrivateJson(values.inventory), {
      operation: values.operation, resetRights: values['reset-rights'], fromRelease: values.from,
      toRelease: values.to, maxAgeMs,
    });
    stdout(`${JSON.stringify(result, null, 2)}\n`);
    return result.cases.every(({ ready }) => ready) ? 0 : 1;
  } catch (error) {
    stderr(`Fixture readiness failed: ${error instanceof Error ? error.message : 'Invalid input.'}\n`);
    return 2;
  }
}

if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
  process.exitCode = runFixtureCli(process.argv.slice(2));
}