fix: robustness improvements — atomic writes, timeouts, shell injection, validation errors

- Atomic JSON writes (write-to-tmp + rename) prevent queue/log corruption
- Per-job (3min) and overall run (45min) timeouts prevent hangs
- execFileSync in ai_answer.mjs prevents shell injection with resume paths
- Validation error detection after form fill in Easy Apply modal
- Config-driven enabled_apply_types (from settings.json)
- isRequired() detects required/aria-required/label * patterns
- getLabel() strips trailing * from required field labels
- Actionable logging on failures ("Action: ..." messages)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 10:01:53 -08:00
parent a7ce119bde
commit e62756c6ca
6 changed files with 99 additions and 26 deletions

View File

@@ -3,7 +3,7 @@
* Handles jobs_queue.json read/write/update
* Uses in-memory cache to avoid redundant disk I/O within a run.
*/
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
import { readFileSync, writeFileSync, renameSync, existsSync, mkdirSync } from 'fs';
import { dirname, resolve } from 'path';
import { fileURLToPath } from 'url';
@@ -37,6 +37,17 @@ function ensureDir(path) {
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
}
/**
* Atomic write — writes to a temp file then renames.
* Prevents corruption if two processes write simultaneously or the process
* crashes mid-write. rename() is atomic on POSIX filesystems.
*/
function atomicWriteJSON(filePath, data) {
const tmp = filePath + '.tmp';
writeFileSync(tmp, JSON.stringify(data, null, 2));
renameSync(tmp, filePath);
}
// --- In-memory caches (populated on first read, invalidated on write) ---
let _queueCache = null;
let _logCache = null;
@@ -50,7 +61,7 @@ export function loadQueue() {
export function saveQueue(jobs) {
ensureDir(QUEUE_PATH);
writeFileSync(QUEUE_PATH, JSON.stringify(jobs, null, 2));
atomicWriteJSON(QUEUE_PATH, jobs);
_queueCache = jobs;
}
@@ -62,7 +73,8 @@ function loadLog() {
}
function saveLog(log) {
writeFileSync(LOG_PATH, JSON.stringify(log, null, 2));
ensureDir(LOG_PATH);
atomicWriteJSON(LOG_PATH, log);
_logCache = log;
}