Files
phishing/scripts/checkRepoMeta.mjs
Satoshi Qazi Muhammed d05316750e Move to @pezkuwi/dev 0.86 (eslint 10 toolchain)
- @pezkuwi/dev, dev-test, dev-ts ^0.86.2
- addrcheck.spec: optional call instead of a guard expression
  (@typescript-eslint/prefer-optional-chain)
- checkRepoMeta: drop the initial value every path overwrites
  (no-useless-assignment)
- ipfsUpload: drop a disable directive for a rule the toolchain no
  longer reports
2026-10-09 15:35:51 +04:00

109 lines
3.8 KiB
JavaScript

// Copyright 2020-2026 @pezkuwi/phishing authors & contributors
// SPDX-License-Identifier: Apache-2.0
// What this repository says about itself must be true, and must be something the
// build toolchain can read.
//
// On 2026-04-21 a commit pointed repository/homepage/bugs at our Gitea instance
// ("migrate git dependencies to Gitea mirror"). Nothing else moved: origin is
// still GitHub, the published package still says GitHub, and
// git.pezkuwichain.io/pezkuwichain/phishing answers 500 — so every installer of
// @pezkuwi/phishing got dead links for its homepage and its bug tracker.
//
// It also broke `yarn build` from 2026-09-13, when the toolchain started reading
// the field. @pezkuwi/dev does this, and it is ours:
//
// const repoPath = pkg.repository.url
// .split('https://github.com/')[1]
// .split('.git')[0];
//
// A URL from any other host makes [1] undefined and the build dies with
// "Cannot read properties of undefined (reading 'split')" — a message that names
// neither the field nor the file.
//
// So this check is also the tripwire for the migration that was started and left
// half-done: moving this repository to Gitea for real means fixing @pezkuwi/dev
// first, so that a toolchain built for a state that hosts its own git stops
// assuming github.com. Until that happens, this check turns the metadata red
// here rather than letting it fail as an unreadable stack trace, or ship as a
// dead link.
//
// node scripts/checkRepoMeta.mjs
import { execFileSync } from 'node:child_process';
import { existsSync, readdirSync, readFileSync } from 'node:fs';
const errors = [];
function check (name, ok, detail) {
console.log((ok ? 'ok ' : 'FAIL ') + name + (ok ? '' : ` — got: ${JSON.stringify(detail)}`));
if (!ok) {
errors.push(name);
}
}
// Exactly the expression @pezkuwi/dev uses, so this fails where the build fails.
function toolchainCanRead (url) {
try {
const path = String(url).split('https://github.com/')[1].split('.git')[0];
return !!path && path.includes('/');
} catch {
return false;
}
}
const files = ['package.json'];
for (const dir of readdirSync('packages', { withFileTypes: true })) {
if (dir.isDirectory() && existsSync(`packages/${dir.name}/package.json`)) {
files.push(`packages/${dir.name}/package.json`);
}
}
check('every package describes itself', files.length > 1, files);
const hosts = new Set();
for (const file of files) {
const pkg = JSON.parse(readFileSync(file, 'utf8'));
const url = pkg.repository?.url;
check(`${file}: has a repository url`, !!url, pkg.repository);
check(`${file}: the build toolchain can read that url`, toolchainCanRead(url), url);
check(`${file}: homepage and bugs live on the same host as the repository`,
!!url && !!pkg.homepage && !!pkg.bugs &&
new URL(pkg.homepage).host === new URL(url).host &&
new URL(String(pkg.bugs)).host === new URL(url).host,
{ bugs: pkg.bugs, homepage: pkg.homepage, url });
if (url) {
hosts.add(new URL(url).host);
}
}
check('the whole repository agrees on one host', hosts.size === 1, [...hosts]);
// And that host is where the code actually is. Without this the metadata can be
// internally consistent and still point somewhere the code has never been.
let origin;
try {
origin = execFileSync('git', ['remote', 'get-url', 'origin'], { encoding: 'utf8' }).trim();
} catch {
origin = '';
}
if (origin) {
check('the metadata names the remote the code is actually pushed to',
hosts.has(new URL(origin.replace(/^git@([^:]+):/, 'https://$1/')).host),
{ hosts: [...hosts], origin }
);
} else {
console.log('ok (no origin remote here — nothing to compare against)');
}
console.log(errors.length ? `FAILED: ${errors.length}` : 'all repository metadata checks passed');
process.exit(errors.length ? 1 : 0);