Files
Benjamin Diedrichsen da84523a6d
Publish snapshot / snapshot (push) Successful in 1m4s
[fix] keyman: a permission-based test the CI runner is root for
The snapshot run for 0.7.0 failed on this one test and published nothing.
`scanPrivateKeys` classifies a file it cannot open as not-a-key, and the test
made the file unopenable with `chmod 0o000` — which stops nobody with uid 0,
and Gitea's act_runner is a container running as root. So the file was read,
recognised as a private key not named id_*, and reported as skipped.

A dangling symlink instead: ENOENT is not a permission anyone can override,
and it is a realistic ~/.ssh inhabitant. Verified by running the gate in a
node:22 container as root, where the whole workspace is now green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 20:32:36 +02:00
..

/**
 * The README is the only document that ships (`package.json` files: dist,
 * README.md, LICENSE), so a reader on the registry sees it and nothing else. It
 * had drifted to describing four of the menu's entries and none of the command
 * line; these assertions are the parts that can drift again silently.
 */

import fs from 'node:fs';
import path from 'node:path';
import { describe, expect, it } from 'vitest';
import { helpText } from '../src/keyman.args.js';

const README = fs.readFileSync(path.join(import.meta.dirname, '..', 'README.md'), 'utf-8');

describe('README', () => {
  it('quotes --help verbatim', () => {
    // Copied rather than described, and checked rather than trusted: a flag added
    // to helpText() now fails here instead of shipping undocumented.
    expect(README).toContain(helpText().trim());
  });

  it('documents every menu operation', () => {
    const main = fs.readFileSync(
      path.join(import.meta.dirname, '..', 'src', 'keyman.main.ts'),
      'utf-8'
    );
    const labels = [...main.matchAll(/\{ name: '([^']+)', value: '[a-z]+' \}/g)].map((m) => m[1]);

    // The labels themselves, emoji included, so a renamed entry is caught too —
    // but with runs of whitespace collapsed, because some of them carry a second
    // space to align a variation-selector emoji in a terminal, and prose should
    // not have to reproduce that.
    const collapse = (text: string) => text.replace(/\s+/g, ' ');
    const readme = collapse(README);

    expect(labels.length).toBe(9);
    for (const label of labels) {
      expect(readme, label).toContain(collapse(label));
    }
  });

  it('documents every configuration key', () => {
    for (const key of ['vaultRoot', 'keysDir', 'tmpDir', 'ageKeyFile']) {
      expect(README, key).toContain(key);
    }
  });
});