This repository has been archived on 2026-11-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
platform-ci/source_checks/check-source.mjs
forge-recoveryandClaude Sonnet 5.5 70eb3ee0ab
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
feat(ci): advance shared pipeline capabilities
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 04:36:22 +00:00

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);
}