fix: make Codex hooks transactional
This commit is contained in:
1 parent
6a7fdb7595
commit
a9adba1fc1
19 files changed
+2525
-1114
No files matched your search
@@ -16,6 +16,7 @@ export function generateGuardScript(
|
||||
'use strict';
|
||||
|
||||
// Elydora agent guard for ${agentName}. Generated by @elydora/sdk.
|
||||
const crypto = require('node:crypto');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const os = require('node:os');
|
||||
@@ -55,9 +56,13 @@ function blockAgent(status) {
|
||||
function readStatusCache() {
|
||||
let raw;
|
||||
try {
|
||||
raw = fs.readFileSync(STATUS_CACHE_PATH, 'utf-8');
|
||||
raw = readProtectedFile(
|
||||
STATUS_CACHE_PATH,
|
||||
'Status cache',
|
||||
MAX_PROTECTED_CONFIG_BYTES,
|
||||
).toString('utf-8');
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') return undefined;
|
||||
if (hasRuntimeErrorCode(error, 'ENOENT')) return undefined;
|
||||
throw new Error('Failed to read status cache: ' + error.message);
|
||||
}
|
||||
let cache;
|
||||
@@ -75,26 +80,10 @@ function readStatusCache() {
|
||||
}
|
||||
|
||||
function writeStatusCache(status) {
|
||||
const temporaryPath = STATUS_CACHE_PATH + '.' + process.pid + '.tmp';
|
||||
try {
|
||||
fs.writeFileSync(temporaryPath, JSON.stringify({
|
||||
status,
|
||||
cached_at: Date.now(),
|
||||
}), { encoding: 'utf-8', mode: 0o600, flag: 'wx' });
|
||||
try {
|
||||
fs.renameSync(temporaryPath, STATUS_CACHE_PATH);
|
||||
} catch (error) {
|
||||
if (process.platform !== 'win32' || !['EEXIST', 'EPERM'].includes(error.code)) throw error;
|
||||
try { fs.unlinkSync(STATUS_CACHE_PATH); } catch (unlinkError) {
|
||||
if (unlinkError.code !== 'ENOENT') throw unlinkError;
|
||||
}
|
||||
fs.renameSync(temporaryPath, STATUS_CACHE_PATH);
|
||||
}
|
||||
} finally {
|
||||
try { fs.unlinkSync(temporaryPath); } catch (error) {
|
||||
if (error.code !== 'ENOENT') throw error;
|
||||
}
|
||||
}
|
||||
writeProtectedJson(STATUS_CACHE_PATH, 'Status cache', {
|
||||
status,
|
||||
cached_at: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
async function readInput() {
|
||||
@@ -103,12 +92,14 @@ async function readInput() {
|
||||
const raw = Buffer.concat(chunks).toString('utf-8').trim();
|
||||
if (!raw) {
|
||||
if (FAIL_CLOSED) throw new Error('Hook input is empty');
|
||||
process.stderr.write('[Elydora guard] Hook input is empty; enforcement continued in fail-open mode.\\n');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
JSON.parse(raw);
|
||||
} catch (error) {
|
||||
if (FAIL_CLOSED) throw new Error('Hook input is invalid JSON: ' + error.message);
|
||||
process.stderr.write('[Elydora guard] Hook input is invalid JSON; enforcement continued in fail-open mode: ' + error.message + '\\n');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user