#!/usr/bin/env node /** * test-all.mjs — Comprehensive test suite for career-ops * * Run before merging any PR or pushing changes. * Tests: syntax, scripts, dashboard, data contract, personal data, paths. * * Usage: * node test-all.mjs # Run all tests * node test-all.mjs --quick # Skip dashboard build (faster) */ import { execSync, execFileSync, spawn } from 'child_process'; import { readFileSync, existsSync, readdirSync, mkdtempSync, mkdirSync, writeFileSync, rmSync, statSync, unlinkSync, realpathSync, symlinkSync } from 'fs'; import { join, dirname, delimiter } from 'path'; import { tmpdir } from 'os'; import { fileURLToPath, pathToFileURL } from 'url'; const __dirname = dirname(fileURLToPath(import.meta.url)); const ROOT = __dirname; const QUICK = process.argv.includes('--quick'); const NODE = process.execPath; let passed = 0; let failed = 0; let warnings = 0; /** * Record and print one passing test assertion. * * The suite uses these small counters instead of a framework so it can run in * any freshly cloned career-ops checkout with only Node.js available. * * @param {string} msg - Human-readable success message for the terminal log. * @returns {void} */ function pass(msg) { console.log(` ✅ ${msg}`); passed++; } /** * Record and print one failing test assertion. * * Failures increment the shared counter that controls the final process exit * code, while still allowing later checks to run and show the full problem set. * * @param {string} msg - Human-readable failure message for the terminal log. * @returns {void} */ function fail(msg) { console.log(` ❌ ${msg}`); failed++; } /** * Record and print one non-fatal warning. * * Warnings are used for expected local-environment gaps, such as missing user * data in a clean repo, where the check should stay visible but not fail CI. * * @param {string} msg - Human-readable warning message for the terminal log. * @returns {void} */ function warn(msg) { console.log(` ⚠️ ${msg}`); warnings++; } /** * Run a shell command or executable and return trimmed stdout on success. * * Array-form arguments use execFileSync to avoid shell parsing. String-only * commands use execSync for existing simple checks. Failures return null so the * caller can decide whether to count the result as a failure or warning. * * @param {string} cmd - Command or executable to run. * @param {string[]} [args=[]] - Optional argument vector for execFileSync. * @param {object} [opts={}] - Extra child_process options. * @returns {string|null} Trimmed stdout, or null when the command fails. */ function run(cmd, args = [], opts = {}) { try { if (Array.isArray(args) && args.length > 0) { return execFileSync(cmd, args, { cwd: ROOT, encoding: 'utf-8', timeout: 30000, ...opts }).trim(); } return execSync(cmd, { cwd: ROOT, encoding: 'utf-8', timeout: 30000, ...opts }).trim(); } catch (e) { return null; } } /** * Check whether a repo-relative file exists. * * @param {string} path - Path relative to the career-ops repository root. * @returns {boolean} True when the file exists. */ function fileExists(path) { return existsSync(join(ROOT, path)); } const BASH = (() => { if (process.platform !== 'win32') return 'bash'; try { execSync('wsl -e bash -c "true"', { stdio: 'ignore' }); return 'bash'; } catch {} const candidates = [ 'C:\\Program Files\\Git\\bin\\bash.exe', 'C:\\Program Files\\Git\\usr\\bin\\bash.exe', 'bash' ]; for (const cmd of candidates) { try { execSync(`"${cmd}" -c "true"`, { stdio: 'ignore' }); return cmd; } catch {} } return 'bash'; })(); function toBashPath(wpath) { if (process.platform !== 'win32') return wpath; const forwardSlashed = wpath.replace(/\\/g, '/'); // Try cygpath first: it ships with Git for Windows, which is also what // provides `bash` on PATH on most Windows dev machines (see BASH const // above). cygpath emits /c/... paths that match Git Bash's mount scheme. // wslpath emits /mnt/c/... paths, which only resolve inside WSL's own // bash -- if WSL happens to be installed but `bash` on PATH still // resolves to Git Bash, a wslpath-first order silently produces a path // Git Bash can't find (see #1409). Only fall back to wslpath (and only // pay the cost of booting the WSL VM) when cygpath is unavailable. try { const cygpathCmd = existsSync('C:\\Program Files\\Git\\usr\\bin\\cygpath.exe') ? '"C:\\Program Files\\Git\\usr\\bin\\cygpath.exe"' : 'cygpath'; const out = execSync(`${cygpathCmd} -u "${forwardSlashed}"`, { stdio: ['pipe', 'pipe', 'ignore'] }).toString().trim(); if (out) return out; } catch {} try { execSync('wsl -e bash -c "true"', { stdio: 'ignore' }); const out = execSync(`wsl wslpath -u "${forwardSlashed}"`, { stdio: ['pipe', 'pipe', 'ignore'] }).toString().trim(); if (out) return out; } catch {} return wpath.replace(/^[A-Za-z]:/, m => '/' + m[0].toLowerCase()).replace(/\\/g, '/'); } /** * Read a repo-relative text file as UTF-8. * * @param {string} path - Path relative to the career-ops repository root. * @returns {string} File contents. */ function readFile(path) { const fullPath = join(ROOT, path); let content = readFileSync(fullPath, 'utf-8'); if (content.trim().startsWith('..') && content.trim().split('\n').length === 1) { const target = join(dirname(fullPath), content.trim()); if (existsSync(target)) { content = readFileSync(target, 'utf-8'); } } return content; } console.log('\n🧪 career-ops test suite\n'); // ── 1. SYNTAX CHECKS ──────────────────────────────────────────── console.log('1. Syntax checks'); const mjsFiles = readdirSync(ROOT).filter(f => f.endsWith('.mjs')); for (const f of mjsFiles) { const result = run(NODE, ['--check', f]); if (result !== null) { pass(`${f} syntax OK`); } else { fail(`${f} has syntax errors`); } } // ── 2. SCRIPT EXECUTION ───────────────────────────────────────── console.log('\n2. Script execution (graceful on empty data)'); const scripts = [ { name: 'cv-sync-check.mjs', expectExit: 1, allowFail: true }, // fails without cv.md (normal in repo) { name: 'verify-pipeline.mjs', expectExit: 0 }, // --dry-run: these scripts resolve ROOT from import.meta.url and write // data/applications.md (or data/pipeline.md) in place. On a provisioned working // copy with a real tracker present, running them without --dry-run mutates user // data. Harmless in this repo (no tracker shipped), risky for end users who run // tests inside their active career-ops workspace. { name: 'normalize-statuses.mjs --dry-run', expectExit: 0 }, { name: 'dedup-tracker.mjs --dry-run', expectExit: 0 }, { name: 'merge-tracker.mjs --dry-run', expectExit: 0 }, { name: 'reconcile-pipeline.mjs --dry-run', expectExit: 0 }, { name: 'analyze-patterns.mjs --self-test', expectExit: 0 }, { name: 'detect-reposts.mjs --self-test', expectExit: 0 }, { name: 'process-quality.mjs --self-test', expectExit: 0 }, { name: 'updater-migration-tests.mjs', expectExit: 0 }, { name: 'tracker-columns-tests.mjs', expectExit: 0 }, { name: 'agent-inbox-tests.mjs', expectExit: 0 }, { name: 'followup-seed-tests.mjs', expectExit: 0 }, { name: 'validate-portals.mjs --file templates/portals.example.yml', expectExit: 0 }, { name: 'validate-system-paths-coverage.mjs --self-test', expectExit: 0 }, { name: 'validate-system-paths-coverage.mjs', expectExit: 0 }, // Missing-file run: must exit 0 gracefully and hit no network. Do not use the // default portals.yml because end-user workspaces often have a real user-layer // portals file that would trigger a live remote sweep during tests. { name: 'verify-portals.mjs --file .tmp-test-missing-portals.yml', expectExit: 0 }, { name: 'update-system.mjs check', expectExit: 0 }, { name: 'archive-posting.mjs --help', expectExit: 0 }, ]; for (const { name, allowFail } of scripts) { const result = run(NODE, name.split(' '), { stdio: ['pipe', 'pipe', 'pipe'] }); if (result !== null) { pass(`${name} runs OK`); } else if (allowFail) { warn(`${name} exited with error (expected without user data)`); } else { fail(`${name} crashed`); } } // ── 3. LIVENESS CLASSIFICATION ────────────────────────────────── console.log('\n3. Liveness classification'); try { const { classifyLiveness } = await import(pathToFileURL(join(ROOT, 'liveness-core.mjs')).href); const expiredChromeApply = classifyLiveness({ finalUrl: 'https://example.com/jobs/closed-role', bodyText: 'Company Careers\nApply\nThe job you are looking for is no longer open.', applyControls: [], }); if (expiredChromeApply.result === 'expired') { pass('Expired pages are not revived by nav/footer "Apply" text'); } else { fail(`Expired page misclassified as ${expiredChromeApply.result}`); } const activeWorkdayPage = classifyLiveness({ finalUrl: 'https://example.workday.com/job/123', bodyText: [ '663 JOBS FOUND', 'Senior AI Engineer', 'Join our applied AI team to ship production systems, partner with customers, and own delivery across evaluation, deployment, and reliability.', ].join('\n'), applyControls: ['Apply for this Job'], }); if (activeWorkdayPage.result === 'active') { pass('Visible apply controls still keep real job pages active'); } else { fail(`Active job page misclassified as ${activeWorkdayPage.result}`); } const closedMycareersfuture = classifyLiveness({ finalUrl: 'https://www.mycareersfuture.gov.sg/job/engineering/senior-staff-embedded-software-engineer', bodyText: [ 'Senior Staff Embedded Software Engineer', 'MaxLinear Asia Singapore Private Limited', '9 applications Posted 27 Oct 2025 Closed on 26 Nov 2025', 'Applications have closed for this job', 'Log in to Apply', "You'll need to log in with Singpass to verify your identity.", 'Roles & Responsibilities: design, develop and maintain embedded firmware for broadband communications ICs.', ].join('\n'), applyControls: ['Log in to Apply'], }); if (closedMycareersfuture.result === 'expired') { pass('Closed postings with "Applications have closed" banner are detected'); } else { fail(`Closed mycareersfuture posting misclassified as ${closedMycareersfuture.result}`); } const cloudflareChallenge = classifyLiveness({ status: 403, finalUrl: 'https://www.pracuj.pl/praca/sap-consultant,oferta,1004870954', bodyText: 'www.pracuj.pl\nJust a moment...\nPerforming security verification\nThis website uses a security service to protect against malicious bots.\nRay ID: a06489bab8bc4cd7\nPerformance and Security by Cloudflare', applyControls: [], }); if (cloudflareChallenge.result === 'uncertain' && cloudflareChallenge.code === 'bot_challenge') { pass('Cloudflare anti-bot challenge pages are uncertain, not expired'); } else { fail(`Cloudflare challenge misclassified as ${cloudflareChallenge.result} (${cloudflareChallenge.code})`); } const blocked403 = classifyLiveness({ status: 403, finalUrl: 'https://www.pracuj.pl/praca/sap-consultant,oferta,1004870954', bodyText: 'Access denied', applyControls: [], }); if (blocked403.result === 'uncertain' && blocked403.code === 'access_blocked') { pass('HTTP 403 is treated as access-blocked (uncertain), not expired'); } else { fail(`HTTP 403 misclassified as ${blocked403.result} (${blocked403.code})`); } const activePolishPosting = classifyLiveness({ status: 200, finalUrl: 'https://www.pracuj.pl/praca/administrator-sap-utilities-warszawa,oferta,1004870954', bodyText: 'Administrator SAP Utilities. Connectis_. Siedziba firmy: Chmielna 71, Warszawa. '.repeat(6), applyControls: ['Aplikuj Aplikuj na ogłoszenie'], }); if (activePolishPosting.result === 'active') { pass('Polish "Aplikuj" apply control marks a loaded posting active'); } else { fail(`Polish apply control not recognized: ${activePolishPosting.result} (${activePolishPosting.code})`); } // Liveness API rung (liveness-api.mjs) — the zero-token ATS first rung. We test the // pure URL→API resolution + SSRF guard; the network fetch is conservative by // construction (only 404/410→expired, 200→active, else null→Playwright fallback). const { resolveAtsApi, classifyAshbyBoard, checkLivenessViaApi } = await import(pathToFileURL(join(ROOT, 'liveness-api.mjs')).href); const ghApi = resolveAtsApi('https://boards.greenhouse.io/acme/jobs/4567890'); if (ghApi?.ats === 'greenhouse' && ghApi.apiUrl === 'https://boards-api.greenhouse.io/v1/boards/acme/jobs/4567890') { pass('resolveAtsApi maps a Greenhouse posting to its per-job API URL'); } else { fail(`Greenhouse API URL wrong: ${JSON.stringify(ghApi)}`); } const lvApi = resolveAtsApi('https://jobs.lever.co/acme/abc-123-def'); if (lvApi?.ats === 'lever' && lvApi.apiUrl === 'https://api.lever.co/v0/postings/acme/abc-123-def') { pass('resolveAtsApi maps a Lever posting to its per-job API URL'); } else { fail(`Lever API URL wrong: ${JSON.stringify(lvApi)}`); } if (resolveAtsApi('https://example.com/jobs/123') === null) { pass('resolveAtsApi returns null for non-ATS URLs (→ Playwright fallback)'); } else { fail('resolveAtsApi should return null for an unknown host'); } if (resolveAtsApi('https://boards.greenhouse.io/acme/jobs/not-a-number') === null && resolveAtsApi('http://boards.greenhouse.io/acme/jobs/123') === null) { pass('resolveAtsApi rejects non-numeric Greenhouse ids and non-https (SSRF guard)'); } else { fail('resolveAtsApi guard failed (bad id or http accepted)'); } // Ashby: org-level board endpoint. Ashby pages are JS-rendered, so the browser/ // static rung sees only nav/footer and false-reports live postings as expired — // the API rung must resolve the org board and confirm the specific job id. const AS_UUID = '00fd8024-7804-4278-a38b-c9d60d929dbb'; const asApi = resolveAtsApi(`https://jobs.ashbyhq.com/deepgram/${AS_UUID}`); if (asApi?.ats === 'ashby' && asApi.apiUrl === 'https://api.ashbyhq.com/posting-api/job-board/deepgram' && asApi.parts?.jobId === AS_UUID && typeof asApi.interpret === 'function') { pass('resolveAtsApi maps an Ashby posting to its org job-board API URL'); } else { fail(`Ashby API URL wrong: ${JSON.stringify(asApi)}`); } // The /application apply-link variant must resolve to the same org + job id. const asApply = resolveAtsApi(`https://jobs.ashbyhq.com/deepgram/${AS_UUID}/application`); if (asApply?.ats === 'ashby' && asApply.parts?.org === 'deepgram' && asApply.parts?.jobId === AS_UUID) { pass('resolveAtsApi handles the Ashby /application apply-link variant'); } else { fail(`Ashby /application variant not resolved: ${JSON.stringify(asApply)}`); } // A bare board root (no job id) isn't a specific posting → null → Playwright. if (resolveAtsApi('https://jobs.ashbyhq.com/deepgram') === null) { pass('resolveAtsApi returns null for an Ashby board root (no job id)'); } else { fail('resolveAtsApi should not treat an Ashby board root as a posting'); } // classifyAshbyBoard — pure per-job liveness from the board payload. const asListed = classifyAshbyBoard({ jobs: [{ id: AS_UUID, isListed: true }] }, AS_UUID); const asAbsent = classifyAshbyBoard({ jobs: [{ id: 'other-id', isListed: true }] }, AS_UUID); const asUnlisted = classifyAshbyBoard({ jobs: [{ id: AS_UUID, isListed: false }] }, AS_UUID); const asBadShape = classifyAshbyBoard({ notJobs: [] }, AS_UUID); if (asListed?.result === 'active' && asAbsent?.result === 'expired' && asUnlisted?.result === 'expired' && asBadShape === null) { pass('classifyAshbyBoard: listed→active, absent/unlisted→expired, bad shape→null'); } else { fail(`classifyAshbyBoard wrong: listed=${JSON.stringify(asListed)} absent=${JSON.stringify(asAbsent)} unlisted=${JSON.stringify(asUnlisted)} badShape=${JSON.stringify(asBadShape)}`); } // checkLivenessViaApi — the fetch/Response orchestration around the pure helpers: // a 200 with an org-level `interpret` (Ashby) is awaited and parsed, a per-job 200 // (Greenhouse) is live as-is, 404 is expired, and a rejected fetch (network error, // or an aborted timeout — same code path) is inconclusive → null. Mock global.fetch // so no network is hit; restore it in finally. const origFetch = globalThis.fetch; try { globalThis.fetch = async () => ({ status: 200, json: async () => ({ jobs: [{ id: AS_UUID, isListed: true }] }) }); const cvAshbyLive = await checkLivenessViaApi(`https://jobs.ashbyhq.com/deepgram/${AS_UUID}`); globalThis.fetch = async () => ({ status: 200, json: async () => ({ jobs: [] }) }); const cvAshbyGone = await checkLivenessViaApi(`https://jobs.ashbyhq.com/deepgram/${AS_UUID}`); // 200 but a malformed board (no `jobs` array): interpret returns null, so the // orchestration must fall through to null (→ Playwright), not a false verdict. globalThis.fetch = async () => ({ status: 200, json: async () => ({}) }); const cvAshbyMalformed = await checkLivenessViaApi(`https://jobs.ashbyhq.com/deepgram/${AS_UUID}`); globalThis.fetch = async () => ({ status: 200 }); const cvGhLive = await checkLivenessViaApi('https://boards.greenhouse.io/acme/jobs/4567890'); globalThis.fetch = async () => ({ status: 404 }); const cvGone = await checkLivenessViaApi('https://boards.greenhouse.io/acme/jobs/4567890'); globalThis.fetch = async () => { throw new Error('network down'); }; const cvErr = await checkLivenessViaApi('https://boards.greenhouse.io/acme/jobs/4567890'); if (cvAshbyLive?.result === 'active' && cvAshbyLive?.code === 'ashby_api_ok' && cvAshbyGone?.result === 'expired' && cvAshbyGone?.code === 'ashby_api_unlisted' && cvAshbyMalformed === null && cvGhLive?.result === 'active' && cvGone?.result === 'expired' && cvErr === null) { pass('checkLivenessViaApi: 200→interpret (Ashby), malformed→null, greenhouse 200→active, 404→expired, fetch error→null'); } else { fail(`checkLivenessViaApi wrong: ashbyLive=${JSON.stringify(cvAshbyLive)} ashbyGone=${JSON.stringify(cvAshbyGone)} malformed=${JSON.stringify(cvAshbyMalformed)} ghLive=${JSON.stringify(cvGhLive)} gone=${JSON.stringify(cvGone)} err=${JSON.stringify(cvErr)}`); } } finally { globalThis.fetch = origFetch; } // Headed-fallback-on-challenge path (liveness-browser.mjs). Fake Playwright // pages script the goto/evaluate calls so we can exercise the wrapper without // launching a browser. checkUrlLiveness reads body text first, apply controls // second — the fake returns them in that order. const { checkUrlLivenessWithFallback, isChallengeResult, jitteredDelayMs } = await import(pathToFileURL(join(ROOT, 'liveness-browser.mjs')).href); const disabled = jitteredDelayMs(0) === 0 && jitteredDelayMs(-1) === 0; let inRange = true; for (let i = 0; i < 200; i += 1) { const d = jitteredDelayMs(5000); if (d < 5000 || d >= 10000) { inRange = false; break; } } if (disabled && inRange) { pass('jitteredDelayMs returns 0 when disabled and stays in [base, 2*base)'); } else { fail(`jitteredDelayMs out of spec (disabled=${disabled}, inRange=${inRange})`); } const fakePage = ({ status, finalUrl, bodyText, applyControls }) => { let evalCall = 0; return { async goto() { return { status: () => status }; }, async waitForTimeout() {}, url() { return finalUrl; }, async evaluate() { evalCall += 1; return evalCall === 1 ? bodyText : applyControls; }, }; }; const URL = 'https://www.pracuj.pl/praca/sap-consultant,oferta,1004870954'; const challengePage = () => fakePage({ status: 403, finalUrl: URL, bodyText: 'Just a moment... Performing security verification. Ray ID: abc123. Cloudflare.', applyControls: [], }); const livePage = () => fakePage({ status: 200, finalUrl: URL, bodyText: 'Administrator SAP Utilities. '.repeat(20), applyControls: ['Apply for this job'], }); if (isChallengeResult({ result: 'uncertain', code: 'bot_challenge' }) && isChallengeResult({ result: 'uncertain', code: 'access_blocked' }) && !isChallengeResult({ result: 'expired', code: 'http_gone' }) && !isChallengeResult({ result: 'active', code: 'apply_control_visible' })) { pass('isChallengeResult flags only bot_challenge/access_blocked uncertains'); } else { fail('isChallengeResult misclassified a result'); } const fellBackToActive = await checkUrlLivenessWithFallback(challengePage(), URL, { getHeadedPage: async () => livePage(), }); if (fellBackToActive.result === 'active') { pass('Headed fallback recovers a challenge-blocked page as active'); } else { fail(`Headed fallback did not recover page: ${fellBackToActive.result} (${fellBackToActive.code})`); } const noProvider = await checkUrlLivenessWithFallback(challengePage(), URL, {}); if (noProvider.result === 'uncertain' && noProvider.code === 'bot_challenge') { pass('No fallback provider keeps the original challenge result'); } else { fail(`Missing provider changed result to ${noProvider.result} (${noProvider.code})`); } const stillBlocked = await checkUrlLivenessWithFallback(challengePage(), URL, { getHeadedPage: async () => challengePage(), }); if (stillBlocked.result === 'uncertain' && stillBlocked.code === 'bot_challenge' && /headed retry also blocked/.test(stillBlocked.reason)) { pass('Persistent challenge stays uncertain after headed retry (never upgraded to expired)'); } else { fail(`Persistent challenge mishandled: ${stillBlocked.result} (${stillBlocked.code})`); } const noHeadedAvailable = await checkUrlLivenessWithFallback(challengePage(), URL, { getHeadedPage: async () => null, // headed launch failed (no display) }); if (noHeadedAvailable.result === 'uncertain' && noHeadedAvailable.code === 'bot_challenge') { pass('Headless-only environment degrades to original challenge result'); } else { fail(`No-display degrade path wrong: ${noHeadedAvailable.result} (${noHeadedAvailable.code})`); } // SSRF guard — `rejectPrivateOrInvalid` has to refuse every URL whose host // resolves to loopback / private / link-local space. The earlier guard only // matched literal IPv4 patterns and bracketless IPv6, so several Chromium- // routable bypasses (0.0.0.0, [::], [::1] (bracketed), [::ffff:127.0.0.1], // localhost.) slipped through. These cases keep that regression covered. const { rejectPrivateOrInvalid } = await import( pathToFileURL(join(ROOT, 'liveness-browser.mjs')).href ); const blockCases = [ ['http://0.0.0.0/admin', 'IPv4 all-zeros (Linux routes to loopback)'], ['http://[::]/', 'IPv6 all-zeros (Linux routes to loopback)'], ['http://[::1]/', 'IPv6 loopback (brackets included in url.hostname)'], ['http://[::ffff:127.0.0.1]/', 'IPv4-mapped IPv6 loopback (dotted form)'], ['http://[::ffff:7f00:1]/', 'IPv4-mapped IPv6 loopback (hex form)'], ['http://[::ffff:169.254.169.254]/', 'IPv4-mapped IPv6 link-local (cloud metadata)'], ['http://[fc00::1]/', 'IPv6 ULA (private)'], ['http://[fe80::1]/', 'IPv6 link-local'], ['http://localhost./', 'FQDN-trailing-dot localhost'], ['http://localhost.localdomain/', 'localhost.localdomain alias'], ['http://169.254.169.254/latest/meta-data/', 'cloud metadata IPv4 link-local'], ['http://10.0.0.5/', 'IPv4 RFC1918'], ]; let blockMissed = 0; for (const [url, label] of blockCases) { const verdict = rejectPrivateOrInvalid(url); if (verdict?.code !== 'blocked_host') { fail(`SSRF guard missed ${label}: ${url} → ${verdict ? verdict.code : 'allowed'}`); blockMissed += 1; } } if (blockMissed === 0) pass(`SSRF guard blocks ${blockCases.length} known bypass vectors`); const allowCases = [ 'https://boards.greenhouse.io/example/jobs/123', 'https://jobs.lever.co/example/abc-def', 'https://example.com/careers/role', 'https://www.pracuj.pl/praca/role,oferta,1234567', ]; let allowDenied = 0; for (const url of allowCases) { if (rejectPrivateOrInvalid(url) !== null) { fail(`SSRF guard false-positive on legitimate ATS URL: ${url}`); allowDenied += 1; } } if (allowDenied === 0) pass('SSRF guard lets legitimate ATS URLs through'); const protoCase = rejectPrivateOrInvalid('file:///etc/passwd'); if (protoCase?.code === 'unsupported_protocol') { pass('SSRF guard rejects unsupported protocol'); } else { fail(`SSRF guard let unsupported protocol through: ${protoCase?.code ?? 'allowed'}`); } } catch (e) { fail(`Liveness classification tests crashed: ${e.message}`); } // ── 4. DASHBOARD BUILD ────────────────────────────────────────── if (!QUICK) { console.log('\n4. Dashboard build'); let hasGo = false; try { execSync('go version', { stdio: 'ignore' }); hasGo = true; } catch {} if (!hasGo) { warn('Dashboard build skipped — go compiler not in env'); } else { const isWindows = process.platform === 'win32'; const dashboardBuildTmp = mkdtempSync(join(tmpdir(), 'career-dashboard-build-')); const outPath = join(dashboardBuildTmp, isWindows ? 'career-dashboard-test.exe' : 'career-dashboard-test'); const goEnv = { ...process.env }; if (isWindows && !goEnv.GOCACHE) { goEnv.GOCACHE = join(tmpdir(), 'career-ops-go-build-cache'); } if (goEnv.GOCACHE) { try { mkdirSync(goEnv.GOCACHE, { recursive: true }); } catch (e) {} } const goBuild = run('go', ['build', '-o', outPath, '.'], { cwd: join(ROOT, 'dashboard'), env: goEnv, stdio: ['pipe', 'pipe', 'pipe'], timeout: 60000, }); if (goBuild !== null) { pass('Dashboard compiles'); try { rmSync(outPath, { force: true }); } catch (e) {} } else { fail('Dashboard build failed'); } try { rmSync(dashboardBuildTmp, { recursive: true, force: true }); } catch (e) {} } } else { console.log('\n4. Dashboard build (skipped --quick)'); } // ── 5. DATA CONTRACT ──────────────────────────────────────────── console.log('\n5. Data contract validation'); // Check system files exist const systemFiles = [ 'CLAUDE.md', 'CODEX.md', 'OPENCODE.md', 'VERSION', 'DATA_CONTRACT.md', 'docs/CODEX.md', 'modes/_shared.md', 'modes/_profile.template.md', 'modes/oferta.md', 'modes/pdf.md', 'modes/scan.md', 'modes/heuristics/recruiter-side.md', 'templates/states.yml', 'templates/cv-template.html', '.claude/skills/career-ops/SKILL.md', '.opencode/skills/career-ops/SKILL.md', '.qwen/skills/career-ops/SKILL.md', '.antigravitycli/skills/career-ops/SKILL.md', '.grok/skills/career-ops/SKILL.md', ]; for (const f of systemFiles) { if (fileExists(f)) { pass(`System file exists: ${f}`); } else { fail(`Missing system file: ${f}`); } } // Check user files are NOT tracked (gitignored) const userFiles = [ 'config/profile.yml', 'modes/_profile.md', 'portals.yml', ]; for (const f of userFiles) { const tracked = run('git', ['ls-files', f]); if (tracked === '') { pass(`User file gitignored: ${f}`); } else if (tracked === null) { pass(`User file gitignored: ${f}`); } else { fail(`User file IS tracked (should be gitignored): ${f}`); } } const batchRunnerSource = readFile('batch/batch-runner.sh'); const minScoreSkipIndex = batchRunnerSource.indexOf('update_state "$id" "$url" "skipped"'); const minScoreReturnIndex = batchRunnerSource.indexOf('return 0', minScoreSkipIndex); const completedStateIndex = batchRunnerSource.indexOf('update_state "$id" "$url" "completed"', minScoreSkipIndex); if ( minScoreSkipIndex !== -1 && minScoreReturnIndex !== -1 && completedStateIndex !== -1 && minScoreSkipIndex < minScoreReturnIndex && minScoreReturnIndex < completedStateIndex ) { pass('Batch min-score gate returns before completed state update'); } else { fail('Batch min-score gate can fall through to completed state update'); } if (/if \[\[ "\$status" == "completed" \|\| "\$status" == "skipped" \]\]/.test(batchRunnerSource)) { pass('Batch resume treats min-score skipped offers as terminal'); } else { fail('Batch resume can reprocess min-score skipped offers'); } if (/local total=0 completed=0 skipped=0 failed=0 pending=0/.test(batchRunnerSource) && /skipped\) skipped=\$\(\(skipped \+ 1\)\)/.test(batchRunnerSource) && /Completed: \$completed \| Skipped: \$skipped \| Failed: \$failed \| Pending: \$pending/.test(batchRunnerSource)) { pass('Batch summary reports skipped offers separately from pending'); } else { fail('Batch summary can misreport skipped offers as pending'); } if (!/\bbc\b/.test(batchRunnerSource)) { pass('Batch runner does not depend on bc for score arithmetic'); } else { fail('Batch runner still depends on bc for score arithmetic'); } if ( !/awk "BEGIN\{[^"]*\$MIN_SCORE/.test(batchRunnerSource) && !/awk "BEGIN\{[^"]*\$score/.test(batchRunnerSource) && !/awk "BEGIN\{[^"]*\$sscore/.test(batchRunnerSource) && /awk -v score="\$score" -v min="\$MIN_SCORE"/.test(batchRunnerSource) ) { pass('Batch runner passes score values to awk via -v'); } else { fail('Batch runner interpolates score values into awk programs'); } // ── 6. PERSONAL DATA LEAK CHECK ───────────────────────────────── console.log('\n6. Personal data leak check'); const leakPatterns = [ 'Santiago', 'santifer.io', 'Santifer iRepair', 'Zinkee', 'ALMAS', 'hi@santifer.io', '688921377', '/Users/santifer/', ]; const scanExtensions = ['md', 'yml', 'html', 'mjs', 'sh', 'go', 'json']; const allowedFiles = [ // English README + localized translations (all legitimately credit Santiago) 'README.md', 'README.ar.md', 'README.da.md', 'README.de.md', 'README.es.md', 'README.fr.md', 'README.ja.md', 'README.ko-KR.md', 'README.pl.md', 'README.pt-BR.md', 'README.ru.md', 'README.cn.md', 'README.ua.md', 'README.zh-TW.md', // Standard project files 'LICENSE', 'CITATION.cff', 'CONTRIBUTING.md', 'CHANGELOG.md', 'TRADEMARK.md', 'package.json', '.github/FUNDING.yml', 'CLAUDE.md', 'AGENTS.md', 'go.mod', 'test-all.mjs', '.claude-plugin/marketplace.json', '.claude-plugin/plugin.json', // Community / governance files (added in v1.3.0, all legitimately reference the maintainer) 'CODE_OF_CONDUCT.md', 'GOVERNANCE.md', 'SECURITY.md', 'SUPPORT.md', '.github/SECURITY.md', // Dashboard credit string 'dashboard/internal/ui/screens/pipeline.go', 'dashboard/internal/ui/screens/progress.go', ]; // Build pathspec for git grep — only scan tracked files matching these // extensions. This is what `grep -rn` was trying to do, but git-aware: // untracked files (debate artifacts, AI tool scratch, local plans/) and // gitignored files can't trigger false positives because they were never // going to reach a commit anyway. const grepPathspec = scanExtensions.map(e => `'*.${e}'`).join(' '); let leakFound = false; for (const pattern of leakPatterns) { const result = run( `git grep -n "${pattern}" -- ${grepPathspec} 2>/dev/null` ); if (result) { for (const line of result.split('\n')) { const file = line.split(':')[0]; if (allowedFiles.some(a => file.includes(a))) continue; if (file.includes('dashboard/go.mod')) continue; warn(`Possible personal data in ${file}: "${pattern}"`); leakFound = true; } } } if (!leakFound) { pass('No personal data leaks outside allowed files'); } // ── 7. ABSOLUTE PATH CHECK ────────────────────────────────────── console.log('\n7. Absolute path check'); // Same git grep approach: only scans tracked files. Untracked AI tool // outputs, local debate artifacts, etc. can't false-positive here. const absPathResult = run( `git grep -n "/Users/" -- '*.mjs' '*.sh' '*.md' '*.go' '*.yml' 2>/dev/null | grep -v README.md | grep -v LICENSE | grep -v CLAUDE.md | grep -v test-all.mjs` ); if (!absPathResult) { pass('No absolute paths in code files'); } else { for (const line of absPathResult.split('\n').filter(Boolean)) { fail(`Absolute path: ${line.slice(0, 100)}`); } } // ── 7b. PDF RENDER WAIT CONDITION ─────────────────────────────── console.log('\n7b. PDF render wait condition'); const generatePdfScript = readFile('generate-pdf.mjs'); if (/waitUntil:\s*['"]load['"]/.test(generatePdfScript)) { pass('generate-pdf waits for load before rendering'); } else { fail('generate-pdf does not wait for load before rendering'); } if (!/waitUntil:\s*['"]networkidle['"]/.test(generatePdfScript)) { pass('generate-pdf does not wait for networkidle'); } else { fail('generate-pdf still waits for networkidle'); } function extractRenderHtmlToPdfOptions(source) { const call = /renderHtmlToPdf\s*\(\s*html\s*,\s*outputPath\s*,/g.exec(source); if (!call) return ''; const objectStart = source.indexOf('{', call.index + call[0].length); if (objectStart === -1) return ''; let depth = 0; let quote = ''; let escaped = false; for (let i = objectStart; i < source.length; i += 1) { const ch = source[i]; if (quote) { if (escaped) escaped = false; else if (ch === '\\') escaped = true; else if (ch === quote) quote = ''; continue; } if (ch === '"' || ch === "'" || ch === '`') { quote = ch; continue; } if (ch === '{') depth += 1; else if (ch === '}') { depth -= 1; if (depth === 0) return source.slice(objectStart + 1, i); } } return ''; } const renderHtmlToPdfOptions = extractRenderHtmlToPdfOptions(generatePdfScript); if (renderHtmlToPdfOptions && /\breportNum\b/.test(renderHtmlToPdfOptions) && /\binputPath\b/.test(renderHtmlToPdfOptions)) { pass('generate-pdf threads reportNum/inputPath into renderHtmlToPdf'); } else { fail('generate-pdf does not pass reportNum/inputPath into renderHtmlToPdf'); } const nestedRenderOptions = extractRenderHtmlToPdfOptions('return renderHtmlToPdf(html, outputPath, { format, metadata: { reportNum, inputPath } });'); if (/\breportNum\b/.test(nestedRenderOptions) && /\binputPath\b/.test(nestedRenderOptions)) { pass('generate-pdf renderHtmlToPdf option matcher handles nested object literals'); } else { fail('generate-pdf renderHtmlToPdf option matcher fails on nested object literals'); } if (generatePdfScript.includes('opts.reportNum') && generatePdfScript.includes('opts.inputPath')) { pass('renderHtmlToPdf reads manifest metadata from opts'); } else { fail('renderHtmlToPdf does not read manifest metadata from opts'); } try { const { repoRelativeManifestPath, injectPrintPageCss } = await import(pathToFileURL(join(ROOT, 'generate-pdf.mjs')).href); const insideHtmlPath = join(ROOT, 'templates', 'cv-template.html'); const outsideHtmlPath = join(dirname(ROOT), 'outside-cv-template.html'); if (repoRelativeManifestPath(insideHtmlPath) === 'templates/cv-template.html') { pass('PDF manifest records repo-local source HTML paths'); } else { fail('PDF manifest does not normalize repo-local source HTML paths'); } if (repoRelativeManifestPath('') === '' && repoRelativeManifestPath(outsideHtmlPath) === '') { pass('PDF manifest leaves HTML column blank when source HTML is missing or outside the repo'); } else { fail('PDF manifest mishandles missing or external source HTML paths'); } const injectedPageCss = injectPrintPageCss('
Beta & Co | Staff SWE | New York, NY | https://beta.io/jobs
'; const parsedHtml = parseHnComment(htmlFmt, ''); if (parsedHtml && parsedHtml.company === 'Beta & Co') { pass('parseHnComment decodes HTML entities (company name)'); } else { fail(`parseHnComment HTML entity decode: ${JSON.stringify(parsedHtml?.company)}`); } if (parsedHtml && parsedHtml.url === 'https://beta.io/jobs') { pass('parseHnComment extracts href URL from anchor tags'); } else { fail(`parseHnComment anchor URL: ${JSON.stringify(parsedHtml?.url)}`); } // parseHnComment ─paragraph body must not bleed into location field // Real HN posts often have "Company | Role | Location
Body text..." where the // second
paragraph (job description) runs on without a 4th pipe segment. // The parser must convert block tags to newlines so parts[2] stays clean. const bleedFmt = '
Linear | Product Engineer | Remote
We are hiring at https://linear.app/careers/pe-2025';
const parsedBleed = parseHnComment(bleedFmt, 'https://news.ycombinator.com/item?id=1');
if (parsedBleed && parsedBleed.location === 'Remote') {
pass('parseHnComment location does not bleed body paragraph text (block tag newline fix)');
} else {
fail(`parseHnComment location bleed: ${JSON.stringify(parsedBleed?.location)}`);
}
if (parsedBleed && parsedBleed.url === 'https://linear.app/careers/pe-2025') {
pass('parseHnComment finds URL in body paragraph when absent from header line');
} else {
fail(`parseHnComment body-paragraph URL: ${JSON.stringify(parsedBleed?.url)}`);
}
// parseHnComment ─ deleted / empty comments return null
if (parseHnComment('', '') === null && parseHnComment(null, '') === null) {
pass('parseHnComment returns null for empty / null input');
} else {
fail('parseHnComment should return null for empty/null input');
}
// provider.fetch() — integration with mock ctx
const FAKE_THREAD_ID = '42424242';
const FAKE_THREAD_URL = `https://news.ycombinator.com/item?id=${FAKE_THREAD_ID}`;
const fakeSearchResp = {
hits: [{ objectID: FAKE_THREAD_ID, title: 'Ask HN: Who is hiring? (June 2025)' }],
};
const fakeItemResp = {
id: FAKE_THREAD_ID,
children: [
{
objectID: 'c1',
text: 'Startup XYZ | Backend Engineer | San Francisco | https://xyz.io/careers',
created_at: '2025-06-01T10:00:00Z',
},
{ objectID: 'c2', deleted: true, text: '' }, // deleted — should be skipped
{ objectID: 'c3', text: '' }, // empty — should be skipped
{
objectID: 'c4',
text: 'Freelance gig, no URL here, DM me.', // no URL — falls back to thread URL
created_at: '2025-06-01T11:00:00Z',
},
],
};
let searchFetched = false;
let itemFetched = false;
const mockCtx = {
async fetchJson(url, _opts) {
if (url.includes('search_by_date')) { searchFetched = true; return fakeSearchResp; }
if (url.includes(`/items/${FAKE_THREAD_ID}`)) { itemFetched = true; return fakeItemResp; }
throw new Error(`hackernews mock: unexpected fetch ${url}`);
},
};
const jobs = await hn.fetch({ name: 'HN Hiring', provider: 'hackernews' }, mockCtx);
if (searchFetched && itemFetched) {
pass('hackernews.fetch() calls search API then items API');
} else {
fail(`hackernews.fetch() API calls: search=${searchFetched} item=${itemFetched}`);
}
if (jobs.length === 2) {
pass('hackernews.fetch() returns 2 jobs (skips deleted + empty comments)');
} else {
fail(`hackernews.fetch() returned ${jobs.length} jobs (expected 2)`);
}
if (jobs[0]?.company === 'Startup XYZ' && jobs[0]?.location === 'San Francisco') {
pass('hackernews.fetch() maps pipe-delimited company and location');
} else {
fail(`hackernews.fetch() row 0: ${JSON.stringify(jobs[0])}`);
}
if (jobs[0]?.url === 'https://xyz.io/careers') {
pass('hackernews.fetch() maps job URL from comment text');
} else {
fail(`hackernews.fetch() row 0 url: ${JSON.stringify(jobs[0]?.url)}`);
}
if (jobs[0]?.postedAt === Date.parse('2025-06-01T10:00:00Z')) {
pass('hackernews.fetch() parses created_at to postedAt epoch ms');
} else {
fail(`hackernews.fetch() postedAt: ${JSON.stringify(jobs[0]?.postedAt)}`);
}
if (jobs[1]?.url === FAKE_THREAD_URL) {
pass('hackernews.fetch() falls back to thread URL for comments with no link');
} else {
fail(`hackernews.fetch() fallback url: ${JSON.stringify(jobs[1]?.url)}`);
}
// provider.fetch() — throws when no thread found
let threw = false;
try {
await hn.fetch({ name: 'HN' }, {
async fetchJson() { return { hits: [] }; },
});
} catch (e) {
threw = true;
}
if (threw) {
pass('hackernews.fetch() throws when "Who is hiring?" thread not found');
} else {
fail('hackernews.fetch() should throw when no matching thread found');
}
} catch (e) {
fail(`hackernews provider tests crashed: ${e.message}`);
}
// -- 40. Provider - himalayas --------------------------------------------
console.log('\n40. Provider - himalayas');
try {
const himalayasModule = await import(pathToFileURL(join(ROOT, 'providers/himalayas.mjs')).href);
const himalayas = himalayasModule.default;
const { parseHimalayasResponse } = himalayasModule;
if (himalayas.id === 'himalayas') pass('himalayas.id is "himalayas"');
else fail(`himalayas.id is ${JSON.stringify(himalayas.id)}`);
const hit = himalayas.detect({ name: 'Himalayas', provider: 'himalayas' });
if (hit && hit.url === 'https://himalayas.app/jobs/api?limit=50') {
pass('himalayas.detect() claims explicit provider config');
} else {
fail(`himalayas.detect() returned ${JSON.stringify(hit)}`);
}
if (himalayas.detect({ name: 'Remote Board', provider: 'remotive' }) === null) {
pass('himalayas.detect() ignores other provider ids');
} else {
fail('himalayas.detect() should only claim provider: himalayas');
}
const sample = {
jobs: [
{
title: ' Staff AI Engineer ',
companyName: ' Acme Labs ',
companySlug: 'acme-labs',
locationRestrictions: ['Worldwide', 'Europe'],
pubDate: 1782538666,
applicationLink: 'https://himalayas.app/companies/acme-labs/jobs/staff-ai-engineer',
guid: 'https://himalayas.app/companies/acme-labs/jobs/staff-ai-engineer-guid',
},
{
title: 'Product Manager',
companyName: 'Fallback Co',
companySlug: 'fallback-co',
locationRestrictions: [],
pubDate: '2026-01-02T09:00:00Z',
applicationLink: '',
guid: 'https://himalayas.app/companies/fallback-co/jobs/product-manager',
},
{
title: 'Missing Link Role',
companyName: 'Dropped Co',
locationRestrictions: ['United States'],
},
{
title: 'Off Host Role',
companyName: 'Bad Co',
locationRestrictions: ['Remote'],
applicationLink: 'https://example.com/companies/bad/jobs/off-host',
},
{
title: 'HTTP Role',
companyName: 'Bad Scheme Co',
locationRestrictions: ['Remote'],
applicationLink: 'http://himalayas.app/companies/bad/jobs/http-role',
},
{
title: ' ',
companyName: 'Blank Title Co',
locationRestrictions: ['Remote'],
applicationLink: 'https://himalayas.app/companies/blank/jobs/blank-title',
},
],
};
const jobs = parseHimalayasResponse(sample);
if (jobs.length === 2) pass('parseHimalayasResponse keeps 2 jobs (drops missing/off-host/http/blank-title rows)');
else fail(`parseHimalayasResponse returned ${jobs.length} jobs (expected 2)`);
if (jobs[0]?.title === 'Staff AI Engineer' && jobs[0]?.company === 'Acme Labs') {
pass('parseHimalayasResponse trims title and companyName');
} else {
fail(`row 0 title/company = ${JSON.stringify({ title: jobs[0]?.title, company: jobs[0]?.company })}`);
}
if (jobs[0]?.location === 'Worldwide, Europe') {
pass('parseHimalayasResponse joins locationRestrictions');
} else {
fail(`row 0 location = ${JSON.stringify(jobs[0]?.location)}`);
}
if (jobs[0]?.url === 'https://himalayas.app/companies/acme-labs/jobs/staff-ai-engineer') {
pass('parseHimalayasResponse maps applicationLink to url');
} else {
fail(`row 0 url = ${JSON.stringify(jobs[0]?.url)}`);
}
if (jobs[0]?.postedAt === 1782538666 * 1000) {
pass('parseHimalayasResponse converts epoch seconds pubDate -> postedAt ms');
} else {
fail(`row 0 postedAt = ${JSON.stringify(jobs[0]?.postedAt)}`);
}
if (jobs[1]?.url === 'https://himalayas.app/companies/fallback-co/jobs/product-manager') {
pass('parseHimalayasResponse falls back to guid when applicationLink is missing');
} else {
fail(`row 1 url = ${JSON.stringify(jobs[1]?.url)}`);
}
if (jobs[1]?.postedAt === Date.parse('2026-01-02T09:00:00Z')) {
pass('parseHimalayasResponse parses string pubDate -> postedAt');
} else {
fail(`row 1 postedAt = ${JSON.stringify(jobs[1]?.postedAt)}`);
}
if (parseHimalayasResponse({}).length === 0 && parseHimalayasResponse(null).length === 0) {
pass('parseHimalayasResponse empty / non-object payload -> empty result (no crash)');
} else {
fail('parseHimalayasResponse invalid payload should yield empty result');
}
let capturedUrl = null;
let capturedOpts = null;
const fetched = await himalayas.fetch(
{ name: 'Himalayas', provider: 'himalayas' },
{ fetchJson: async (url, opts) => { capturedUrl = url; capturedOpts = opts; return sample; } },
);
if (capturedUrl === 'https://himalayas.app/jobs/api?limit=50') {
pass('himalayas.fetch() requests the pinned API URL');
} else {
fail(`himalayas.fetch() requested ${JSON.stringify(capturedUrl)}`);
}
if (capturedOpts && capturedOpts.redirect === 'error') {
pass('himalayas.fetch() passes redirect:"error" to fetchJson');
} else {
fail(`himalayas.fetch() should pass redirect:"error", got: ${JSON.stringify(capturedOpts)}`);
}
if (fetched[0]?.company === 'Acme Labs' && fetched[0]?.title === 'Staff AI Engineer') {
pass('provider: himalayas config returns normalized jobs');
} else {
fail(`himalayas.fetch() normalized row = ${JSON.stringify(fetched[0])}`);
}
} catch (e) {
fail(`himalayas provider tests crashed: ${e.message}`);
}
// ── 41. Provider — jobicy ───────────────────────────────────────
console.log('\n41. Provider — jobicy');
try {
const jobicy = (await import(pathToFileURL(join(ROOT, 'providers/jobicy.mjs')).href)).default;
const { parseJobicyResponse } = await import(pathToFileURL(join(ROOT, 'providers/jobicy.mjs')).href);
if (jobicy.id === 'jobicy') pass('jobicy.id is "jobicy"');
else fail(`jobicy.id is ${JSON.stringify(jobicy.id)}`);
const hit = jobicy.detect({ name: 'Jobicy Board', provider: 'jobicy' });
if (hit && hit.url === 'https://jobicy.com/api/v2/remote-jobs?count=50') {
pass('jobicy.detect() claims explicit provider config');
} else {
fail(`jobicy.detect() returned ${JSON.stringify(hit)}`);
}
if (jobicy.detect({ name: 'Remote Board', provider: 'remoteok' }) === null) {
pass('jobicy.detect() ignores other provider ids');
} else {
fail('jobicy.detect() should only claim provider: jobicy');
}
const sample = {
jobs: [
{
jobTitle: 'Senior AI Engineer',
companyName: 'Acme Corp',
jobGeo: 'Worldwide',
url: 'https://jobicy.com/jobs/senior-ai-engineer',
pubDate: '2026-06-27T10:00:00',
},
{
jobTitle: 'Staff Backend Developer',
companyName: 'Globex',
jobGeo: 'Europe',
url: 'https://jobicy.com/jobs/staff-backend-developer',
pubDate: '2026-06-25T12:00:00Z',
},
{
jobTitle: 'Role With Missing URL',
companyName: 'Incomplete',
jobGeo: 'USA',
pubDate: '2026-06-24T08:00:00Z',
},
{
jobTitle: 'Role With Invalid URL',
companyName: 'Invalid',
url: 'not-a-valid-url',
jobGeo: 'USA',
},
{
jobTitle: '',
companyName: 'Empty Title',
url: 'https://jobicy.com/jobs/empty-title',
jobGeo: 'USA',
}
]
};
const jobs = parseJobicyResponse(sample, 'Jobicy Board');
if (jobs.length === 2) pass('parseJobicyResponse keeps 2 jobs (drops missing/invalid url and empty title)');
else fail(`parseJobicyResponse returned ${jobs.length} jobs (expected 2)`);
if (jobs[0]?.company === 'Acme Corp' && jobs[0]?.title === 'Senior AI Engineer') {
pass('parseJobicyResponse maps jobTitle -> title, companyName -> company');
} else {
fail(`row 0 title/company = ${JSON.stringify({ title: jobs[0]?.title, company: jobs[0]?.company })}`);
}
if (jobs[0]?.url === 'https://jobicy.com/jobs/senior-ai-engineer') {
pass('parseJobicyResponse maps url to url');
} else {
fail(`row 0 url = ${JSON.stringify(jobs[0]?.url)}`);
}
if (jobs[0]?.location === 'Worldwide') {
pass('parseJobicyResponse maps jobGeo to location');
} else {
fail(`row 0 location = ${JSON.stringify(jobs[0]?.location)}`);
}
if (jobs[0]?.postedAt === Date.parse('2026-06-27T10:00:00')) {
pass('parseJobicyResponse parses pubDate -> postedAt');
} else {
fail(`row 0 postedAt = ${JSON.stringify(jobs[0]?.postedAt)}`);
}
if (jobs[1]?.company === 'Globex' && jobs[1]?.title === 'Staff Backend Developer') {
pass('parseJobicyResponse parses second job correctly');
} else {
fail(`row 1 = ${JSON.stringify(jobs[1])}`);
}
if (parseJobicyResponse('', 'X').length === 0 && parseJobicyResponse(null, 'X').length === 0) {
pass('parseJobicyResponse empty / non-object payload -> empty result (no crash)');
} else {
fail('parseJobicyResponse empty / non-object payload should yield empty result');
}
let capturedUrl = null;
let capturedOpts = null;
const fetched = await jobicy.fetch(
{ name: 'Jobicy Board', provider: 'jobicy' },
{ fetchJson: async (url, opts) => { capturedUrl = url; capturedOpts = opts; return sample; } },
);
if (capturedUrl === 'https://jobicy.com/api/v2/remote-jobs?count=50') {
pass('jobicy.fetch() requests the pinned JSON feed URL');
} else {
fail(`jobicy.fetch() requested ${JSON.stringify(capturedUrl)}`);
}
if (capturedOpts && capturedOpts.redirect === 'error') {
pass('jobicy.fetch() passes redirect:"error" to fetchJson');
} else {
fail(`jobicy.fetch() should pass redirect:"error", got: ${JSON.stringify(capturedOpts)}`);
}
if (fetched[0]?.company === 'Acme Corp' && fetched[0]?.title === 'Senior AI Engineer') {
pass('provider: jobicy config returns normalized jobs');
} else {
fail(`jobicy.fetch() normalized row = ${JSON.stringify(fetched[0])}`);
}
} catch (e) {
fail(`jobicy provider tests crashed: ${e.message}`);
}
// ── 42. PROVIDERS — JustJoin.it ───────────────────────────────────────────
console.log('\n42. Provider — justjoin');
try {
const jj = (await import(pathToFileURL(join(ROOT, 'providers/justjoin.mjs')).href)).default;
const { parseJustJoinResponse } = await import(pathToFileURL(join(ROOT, 'providers/justjoin.mjs')).href);
if (jj.id === 'justjoin') pass('justjoin.id is "justjoin"');
else fail(`justjoin.id is ${JSON.stringify(jj.id)}`);
if (jj.detect({ name: 'JustJoin', careers_url: 'https://justjoin.it/job-offers/all-locations' })?.url) {
pass('justjoin.detect() matches job-offers URL');
} else {
fail('justjoin.detect() should match justjoin.it job-offers URL');
}
if (jj.detect({ name: 'X', careers_url: 'https://evil.example/justjoin.it/job-offers' }) === null) {
pass('justjoin.detect() rejects path-spoofed URLs');
} else {
fail('justjoin.detect() must reject path-spoofed URLs');
}
if (jj.detect({ name: 'X', api: 'https://justjoin.it/api/candidate-api/offers/count' }) === null) {
pass('justjoin.detect() rejects non-offers API paths');
} else {
fail('justjoin.detect() must reject non-offers API paths');
}
const fakeResponse = {
data: [
{
slug: 'acme-senior-dev-warsaw-javascript',
title: 'Senior Developer',
companyName: 'Acme',
workplaceType: 'remote',
locations: [{ city: 'Warszawa' }],
publishedAt: '2026-06-12T10:00:00.000Z',
},
{ slug: '', title: 'Missing Slug', companyName: 'Broken' },
null,
],
meta: { next: { cursor: null } },
};
const parsed = parseJustJoinResponse(fakeResponse);
if (parsed.length === 1) pass('justjoin parser filters malformed rows');
else fail(`justjoin parser returned ${parsed.length} rows, expected 1`);
if (parsed[0].title === 'Senior Developer' && parsed[0].url === 'https://justjoin.it/job-offer/acme-senior-dev-warsaw-javascript') {
pass('justjoin parser maps title and URL');
} else {
fail(`justjoin parser mapped title/url incorrectly: ${JSON.stringify(parsed[0])}`);
}
if (parsed[0].company === 'Acme' && parsed[0].location === 'remote, Warszawa' && typeof parsed[0].postedAt === 'number') {
pass('justjoin parser maps company, location, and postedAt');
} else {
fail(`justjoin parser mapped fields incorrectly: ${JSON.stringify(parsed[0])}`);
}
let capturedUrl = '';
let capturedOpts = null;
const fetched = await jj.fetch(
{ name: 'JustJoin', careers_url: 'https://justjoin.it/job-offers/all-locations', max_pages: 1 },
{
transport: 'http',
fetchJson: async (url, opts) => {
capturedUrl = url;
capturedOpts = opts;
return fakeResponse;
},
fetchText: async () => '',
},
);
if (fetched.length === 1 && capturedUrl.startsWith('https://justjoin.it/api/candidate-api/offers?')) {
pass('justjoin.fetch() uses candidate API endpoint');
} else {
fail(`justjoin.fetch() endpoint/result wrong: ${capturedUrl} ${JSON.stringify(fetched)}`);
}
if (capturedOpts && capturedOpts.redirect === 'error') pass('justjoin.fetch() passes redirect:"error"');
else fail(`justjoin.fetch() should pass redirect:"error", got ${JSON.stringify(capturedOpts)}`);
let ssrfRejected = false;
try {
await jj.fetch(
{ name: 'Evil', careers_url: 'https://evil.example/job-offers/all-locations' },
{
transport: 'http',
fetchJson: async () => { throw new Error('SSRF! should not reach here'); },
fetchText: async () => '',
},
);
} catch (e) {
if (e.message.includes('trusted justjoin.it')) ssrfRejected = true;
}
if (ssrfRejected) pass('justjoin.fetch() rejects untrusted host');
else fail('justjoin.fetch() should reject untrusted host');
let badShape = false;
try {
parseJustJoinResponse({ jobs: [] });
} catch (e) {
if (e.message.includes('unexpected API response')) badShape = true;
}
if (badShape) pass('justjoin parser throws on bad response shape');
else fail('justjoin parser should throw on bad response shape');
} catch (e) {
fail(`justjoin provider tests crashed: ${e.message}`);
}
// ── 43. PROVIDERS — NoFluffJobs ───────────────────────────────────────────
console.log('\n43. Provider — nofluffjobs');
try {
const nfj = (await import(pathToFileURL(join(ROOT, 'providers/nofluffjobs.mjs')).href)).default;
const { parseNoFluffJobsResponse } = await import(pathToFileURL(join(ROOT, 'providers/nofluffjobs.mjs')).href);
if (nfj.id === 'nofluffjobs') pass('nofluffjobs.id is "nofluffjobs"');
else fail(`nofluffjobs.id is ${JSON.stringify(nfj.id)}`);
if (nfj.detect({ name: 'NoFluff', careers_url: 'https://nofluffjobs.com/pl' })?.url) {
pass('nofluffjobs.detect() matches nofluffjobs.com URL');
} else {
fail('nofluffjobs.detect() should match nofluffjobs.com URL');
}
if (nfj.detect({ name: 'X', careers_url: 'https://evil.example/nofluffjobs.com/pl' }) === null) {
pass('nofluffjobs.detect() rejects path-spoofed URLs');
} else {
fail('nofluffjobs.detect() must reject path-spoofed URLs');
}
const fakeResponse = {
postings: [
{
title: 'Frontend Engineer',
name: 'ExampleCo',
url: 'frontend-engineer-remote',
posted: 1781270000000,
fullyRemote: true,
location: { places: [{ city: 'Kraków' }] },
},
{ title: '', name: 'Broken', url: 'missing-title' },
7,
],
totalPages: 1,
};
const parsed = parseNoFluffJobsResponse(fakeResponse);
if (parsed.length === 1) pass('nofluffjobs parser filters malformed rows');
else fail(`nofluffjobs parser returned ${parsed.length} rows, expected 1`);
if (parsed[0].title === 'Frontend Engineer' && parsed[0].url === 'https://nofluffjobs.com/pl/job/frontend-engineer-remote') {
pass('nofluffjobs parser maps title and URL');
} else {
fail(`nofluffjobs parser mapped title/url incorrectly: ${JSON.stringify(parsed[0])}`);
}
if (parsed[0].company === 'ExampleCo' && parsed[0].location === 'Remote, Kraków' && parsed[0].postedAt === 1781270000000) {
pass('nofluffjobs parser maps company, location, and postedAt');
} else {
fail(`nofluffjobs parser mapped fields incorrectly: ${JSON.stringify(parsed[0])}`);
}
let capturedUrl = '';
let capturedOpts = null;
const fetched = await nfj.fetch(
{ name: 'NoFluffJobs', careers_url: 'https://nofluffjobs.com/pl', max_pages: 1 },
{
transport: 'http',
fetchJson: async (url, opts) => {
capturedUrl = url;
capturedOpts = opts;
return fakeResponse;
},
fetchText: async () => '',
},
);
if (fetched.length === 1 && capturedUrl.startsWith('https://nofluffjobs.com/api/search/posting?')) {
pass('nofluffjobs.fetch() uses search posting API endpoint');
} else {
fail(`nofluffjobs.fetch() endpoint/result wrong: ${capturedUrl} ${JSON.stringify(fetched)}`);
}
if (capturedOpts && capturedOpts.method === 'POST' && capturedOpts.redirect === 'error') {
pass('nofluffjobs.fetch() uses POST and redirect:"error"');
} else {
fail(`nofluffjobs.fetch() should use POST and redirect:"error", got ${JSON.stringify(capturedOpts)}`);
}
let ssrfRejected = false;
try {
await nfj.fetch({ name: 'Evil', careers_url: 'https://evil.example/pl' }, { transport: 'http', fetchJson: async () => fakeResponse, fetchText: async () => '' });
} catch (e) {
if (e.message.includes('trusted nofluffjobs.com')) ssrfRejected = true;
}
if (ssrfRejected) pass('nofluffjobs.fetch() rejects untrusted host');
else fail('nofluffjobs.fetch() should reject untrusted host');
let badShape = false;
try {
parseNoFluffJobsResponse({ jobs: [] });
} catch (e) {
if (e.message.includes('unexpected API response')) badShape = true;
}
if (badShape) pass('nofluffjobs parser throws on bad response shape');
else fail('nofluffjobs parser should throw on bad response shape');
} catch (e) {
fail(`nofluffjobs provider tests crashed: ${e.message}`);
}
// ── 44. openrouter-runner — portals drift guard ─────────────────
console.log('\n44. openrouter-runner — portals drift guard');
try {
const { parsePortals } = await import(pathToFileURL(join(ROOT, 'openrouter-runner.mjs')).href);
const exampleYaml = readFileSync(join(ROOT, 'templates/portals.example.yml'), 'utf-8');
const { companies, titleMatches } = parsePortals(exampleYaml);
// The no-CLI runner must read the SAME canonical portals schema as scan.mjs
// (tracked_companies[].api + title_filter.positive/negative). If the schema
// drifts and the runner stops matching, this fails loudly — instead of the
// runner silently scanning zero companies (the exact bug this guard prevents).
if (companies.length > 0) pass(`runner parsePortals extracts ${companies.length} api-companies from the canonical portals schema`);
else fail('runner parsePortals extracted 0 companies from templates/portals.example.yml — schema drift');
if (companies.length > 0 && companies.every(c => c.name && c.api)) pass('each extracted company has a name and a JSON api endpoint');
else fail(`runner companies missing name/api: ${JSON.stringify(companies.slice(0, 3))}`);
if (titleMatches('AI Engineer') && !titleMatches('Forklift Operator')) {
pass('runner titleMatches honors title_filter.positive/negative from the canonical schema');
} else {
fail(`runner titleMatches drift: "AI Engineer"=${titleMatches('AI Engineer')} "Forklift Operator"=${titleMatches('Forklift Operator')}`);
}
} catch (e) {
fail(`openrouter-runner portals drift guard crashed: ${e.message}`);
}
// ── 45. SCAN COOLDOWN FILTER ──────────────────────────────────
console.log('\n45. Scan cooldown filter');
try {
const { addDays, buildCooldownFilter, shouldDedupScanHistoryRow } = await import(pathToFileURL(join(ROOT, 'scan.mjs')).href);
// addDays tests
if (addDays('2026-06-24', 180) === '2026-12-21') {
pass('addDays computes date correctly (180 days)');
} else {
fail(`addDays expected 2026-12-21 but got ${addDays('2026-06-24', 180)}`);
}
// shouldDedupScanHistoryRow tests
const activeCo = shouldDedupScanHistoryRow({ firstSeen: '2026-06-24', status: 'cooldown:CompanyA:2026-12-21' }, { today: '2026-06-25' });
const expiredCo = shouldDedupScanHistoryRow({ firstSeen: '2026-06-24', status: 'cooldown:CompanyA:2026-12-21' }, { today: '2026-12-22' });
if (activeCo === true && expiredCo === false) {
pass('shouldDedupScanHistoryRow dedups active cooldowns and lets expired ones through');
} else {
fail(`shouldDedupScanHistoryRow wrong: activeCo=${activeCo}, expiredCo=${expiredCo}`);
}
// buildCooldownFilter tests
const windows = {
CompanyA: {
same_role_days: 180,
cross_role_bucket: 'all_EM_roles',
applied_to: ['Senior Software Engineer'],
last_apply_date: '2026-06-01',
}
};
const filterToday = '2026-06-15'; // within 180 days from 2026-06-01 (cooldownUntil = 2026-11-28)
const filterExpired = '2026-12-01'; // expired
const filterBoundary = '2026-11-28'; // exactly cooldownUntil
const cooldownFilterActive = buildCooldownFilter(windows, filterToday);
const cooldownFilterExpired = buildCooldownFilter(windows, filterExpired);
const cooldownFilterBoundary = buildCooldownFilter(windows, filterBoundary);
// Exact/substring role match test
const jobSameRole = { company: 'Company A', title: 'Senior Software Engineer' };
const jobSubRole = { company: 'CompanyA Corp', title: 'Lead Senior Software Engineer' };
const jobOtherRole = { company: 'Company A', title: 'Staff QA Engineer' };
const jobCrossRole = { company: 'Company A', title: 'Engineering Manager' };
if (cooldownFilterActive(jobSameRole).skip === true &&
cooldownFilterActive(jobSubRole).skip === true &&
cooldownFilterActive(jobOtherRole).skip === false &&
cooldownFilterActive(jobCrossRole).skip === true) {
pass('cooldownFilter active skips same role, substring role, and cross role bucket matches');
} else {
fail(`cooldownFilter active: sameRole=${cooldownFilterActive(jobSameRole).skip}, subRole=${cooldownFilterActive(jobSubRole).skip}, otherRole=${cooldownFilterActive(jobOtherRole).skip}, crossRole=${cooldownFilterActive(jobCrossRole).skip}`);
}
if (cooldownFilterExpired(jobSameRole).skip === false) {
pass('cooldownFilter does not skip when cooldown window has expired');
} else {
fail('cooldownFilter skipped job after expiration');
}
// Boundary day test
if (cooldownFilterBoundary(jobSameRole).skip === false) {
pass('cooldownFilter does not skip on boundary day (today === cooldownUntil)');
} else {
fail('cooldownFilter skipped job on boundary day');
}
// Lookalike company test
const jobLookalikeCompany = { company: 'CompanyAlpha', title: 'Senior Software Engineer' };
if (cooldownFilterActive(jobLookalikeCompany).skip === false) {
pass('cooldownFilter does not match lookalike company (CompanyAlpha vs CompanyA)');
} else {
fail('cooldownFilter matched lookalike company');
}
} catch (e) {
fail(`cooldown filter tests crashed: ${e.message}`);
}
// ── 46. Provider — jobspresso ──────────────────────────────────────
console.log('\nXX. Provider — jobspresso');
try {
const {
default: jobspresso,
parseJobspressoFeed,
} = await import(pathToFileURL(join(ROOT, 'providers/jobspresso.mjs')).href);
if (jobspresso.id === 'jobspresso') {
pass('jobspresso.id is "jobspresso"');
} else {
fail(`jobspresso.id is "${jobspresso.id}"`);
}
if (
jobspresso.detect({ provider: 'jobspresso' })?.url ===
'https://jobspresso.co/?feed=job_feed'
) {
pass('jobspresso.detect() claims explicit provider config');
} else {
fail('jobspresso.detect() failed');
}
if (jobspresso.detect({ provider: 'other' }) === null) {
pass('jobspresso.detect() ignores other provider ids');
} else {
fail('jobspresso.detect() should ignore other providers');
}
const xml = `