Archived
KofTwentyTwo/ci-policy: ci / fork-guard (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / go-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / go-nix-1 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / gradle-2 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / gradle-3 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / java-docker-4 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / java-maven-5 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / manifests-6 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / nix-7 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / node-8 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / python-9 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / rust-10 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / rust-11 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / rust-12 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / source-config-13 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / source-config-14 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-1 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-2 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-3 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-4 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-5 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-6 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-7 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / not-enrolled (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / content-validate-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / standards-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / node-matrix-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / source-config-15 (pull_request) Blocked by required conditions
KofTwentyTwo/ci-policy: Shared source and config CI / verify (pull_request) Blocked by required conditions
KofTwentyTwo/ci-policy: Shared source and config CI / secrets (pull_request) Blocked by required conditions
KofTwentyTwo/ci-policy: Shared source and config CI / gate (pull_request) Waiting for needed jobs
KofTwentyTwo/ci-policy: ci / ci-result (pull_request) Waiting for needed jobs
KofTwentyTwo/ci-policy: native / fork-deny (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-macos-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-macos-1 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-macos-2 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-macos-3 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-windows-4 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-windows-5 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-windows-6 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-windows-7 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / dotnet-8 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / dotnet-9 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / dotnet-10 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / dotnet-11 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-12 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-13 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-14 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-15 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-16 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-17 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-18 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-19 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / native-result (pull_request) Canceled after 4s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
68 lines
4.1 KiB
JavaScript
68 lines
4.1 KiB
JavaScript
// Source/config lint for repositories with no supported build: tracked JSON must
|
|
// parse, tracked shell must pass `bash -n`, and no merge-conflict markers.
|
|
// usage: node check-source.mjs (run at the repository root)
|
|
import { execFileSync, spawnSync } from 'node:child_process';
|
|
import { readFileSync } from 'node:fs';
|
|
import { isUtf8 } from 'node:buffer';
|
|
import { jsonc } from './jsonc.mjs';
|
|
|
|
const entries = execFileSync('git', ['ls-files', '--stage', '-z'], { encoding: 'utf8', maxBuffer: 1 << 28 })
|
|
.split('\0').filter(Boolean).map(entry => [entry.slice(0, 6), entry.slice(entry.indexOf('\t') + 1)]);
|
|
const files = entries.map(entry => entry[1]);
|
|
const links = new Set(entries.filter(entry => entry[0] === '120000').map(entry => entry[1]));
|
|
const bad = [];
|
|
let json = 0, shell = 0, encrypted = 0, captures = 0;
|
|
// Tracked Python is only compiled (never imported or run); vendored trees are not ours to gate.
|
|
const python = [];
|
|
const gitCryptHeader = Buffer.from('\0GITCRYPT\0');
|
|
for (const file of files) {
|
|
// A tracked link is metadata, not configuration content. Never follow a link
|
|
// into host files or interpret its target as JSON when Git materializes it as text.
|
|
if (links.has(file)) continue;
|
|
// .data holds raw command-response captures, including intentionally empty response files.
|
|
// Secret scanning still examines the full repository history independently.
|
|
if (file.startsWith('.data/')) { captures++; continue; }
|
|
const isText = /\.(md|txt|ya?ml|json|sh|py|tf|toml|ini|cfg|conf)$/.test(file);
|
|
const bytes = isText ? readFileSync(file) : null;
|
|
// Respect git-crypt boundaries: ciphertext cannot be parsed as source/configuration.
|
|
if (bytes?.subarray(0, gitCryptHeader.length).equals(gitCryptHeader)) { encrypted++; continue; }
|
|
// DBeaver stores encrypted binary credentials under this documented .json filename.
|
|
if (bytes && /(^|\/)\.dbeaver\/credentials-config\.json$/.test(file) && !isUtf8(bytes)) { encrypted++; continue; }
|
|
const text = bytes?.toString('utf8');
|
|
if (/\.py$/.test(file) && !/(^|\/)(vendor|third_party|node_modules)\//.test(file)) python.push(file);
|
|
if (/\.json$/.test(file) && !/(^|\/)(tsconfig[^/]*|\.eslintrc|\.babelrc|devcontainer)\.json$/.test(file)) {
|
|
json++;
|
|
const vscode = /(^|\/)(\.vscode|vscode)\/(settings|extensions|launch|tasks)\.json$/.test(file);
|
|
try { if (vscode) jsonc(text); else JSON.parse(text); }
|
|
catch { bad.push(`${file}: invalid ${vscode ? 'JSONC' : 'JSON'}`); }
|
|
} else if (/\.sh$/.test(file)) {
|
|
shell++;
|
|
const run = spawnSync('bash', ['-n', file], { encoding: 'utf8' });
|
|
if (run.status !== 0) bad.push(`${file}: shell syntax error ${run.stderr.trim()}`);
|
|
}
|
|
if (/\.(md|txt|ya?ml|json|sh|py|tf|toml|ini|cfg|conf)$/.test(file)) {
|
|
if (/^<{7} .+$/m.test(text) && /^>{7} .+$/m.test(text)) bad.push(`${file}: merge-conflict markers`);
|
|
}
|
|
}
|
|
if (python.length) {
|
|
// compile() parses and byte-compiles in memory: no execution, no import, no __pycache__.
|
|
const program = 'import sys\n' +
|
|
'for p in sys.stdin.buffer.read().split(b"\\0"):\n' +
|
|
' if not p: continue\n' +
|
|
' path = p.decode("utf-8", "surrogateescape")\n' +
|
|
' try:\n' +
|
|
' compile(open(path, "rb").read(), path, "exec", dont_inherit=True)\n' +
|
|
' except (SyntaxError, ValueError) as e:\n' +
|
|
' print(f"{path}: {type(e).__name__}: {e}")\n';
|
|
const run = spawnSync(process.env.CHECK_SOURCE_PYTHON || 'python3', ['-I', '-B', '-c', program],
|
|
{ input: python.join('\0'), encoding: 'utf8', env: { ...process.env, PYTHONDONTWRITEBYTECODE: '1' } });
|
|
if (run.error) bad.push(`python3 is required to check ${python.length} tracked .py files: ${run.error.message}`);
|
|
else if (run.status !== 0) bad.push(`python checker failed: ${run.stderr.trim()}`);
|
|
else for (const line of run.stdout.split('\n').filter(Boolean)) bad.push(`${line} (python syntax)`);
|
|
}
|
|
console.log(`source: ${files.length} tracked files, ${json} json, ${shell} shell, ${python.length} python, ${encrypted} encrypted, ${captures} raw captures`);
|
|
if (bad.length) {
|
|
for (const line of bad) console.error(`source: ${line}`);
|
|
process.exit(1);
|
|
}
|