mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-16 18:05:31 +02:00
* feat(cso): add verified audits and replayable repair bundles * fix(cso): harden qualification and setup boundaries * fix(cso): assemble security canaries at runtime * fix(cso): bound release proof and maintenance work Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(cso): require complete evaluation reports Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(cso): replay expired snapshots from supplied source Co-Authored-By: OpenAI Codex <noreply@openai.com> * test(cso): synchronize DNS cancellation assertion Co-Authored-By: OpenAI Codex <noreply@openai.com> * chore(ship): exempt repository owner from liveness proof Co-Authored-By: OpenAI Codex <noreply@openai.com> * test(cso): make recheck retention overlap deterministic Co-Authored-By: OpenAI Codex <noreply@openai.com> * chore: bump version and changelog (v1.85.0.0) Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(cso): pass native release gates Co-Authored-By: OpenAI Codex <noreply@openai.com> * chore: move release to v1.86.0.0 Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(cso): resolve rechecks by finding Co-Authored-By: OpenAI Codex <noreply@openai.com> * chore: move release to v1.87.0.0 Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(cso): pass macOS and Windows release gates Normalize BSD wc output, compare Windows paths by filesystem identity, preserve portable snapshot race coverage, and narrow POSIX-only Windows fixtures. Co-Authored-By: OpenAI Codex <noreply@openai.com> * fix(cso): harden native verification gates * fix(cso): refine Windows native diagnostics * test(cso): isolate Windows Git startup failure * test(cso): stabilize Windows native diagnostics * fix(cso): support hardened Git on Windows * fix(cso): close final verification gaps * test(cso): bound cold Docker fixture setup * fix(cso): restore cross-platform free-suite gates --------- Co-authored-by: OpenAI Codex <noreply@openai.com>
17 lines
1.9 KiB
TypeScript
17 lines
1.9 KiB
TypeScript
import * as fs from 'node:fs';
|
|
import { CsoError } from './contracts';
|
|
|
|
/** Read one caller-supplied control file without following or blocking on a raced special file. */
|
|
export function readBoundedStable(path:string,max:number,label:string):Buffer{
|
|
let named:fs.Stats,fd:number|undefined;try{named=fs.lstatSync(path);}catch{throw new CsoError('MISSING_INPUT',`${label} does not exist`);}
|
|
if(named.isSymbolicLink()||!named.isFile()||named.nlink!==1||named.size>max)throw new CsoError('MISSING_INPUT',`${label} must be one bounded regular file`);
|
|
try{
|
|
fd=fs.openSync(path,fs.constants.O_RDONLY|(fs.constants.O_NOFOLLOW??0)|(fs.constants.O_NONBLOCK??0));const opened=fs.fstatSync(fd);
|
|
if(!opened.isFile()||opened.nlink!==1||opened.dev!==named.dev||opened.ino!==named.ino||opened.mode!==named.mode||opened.size!==named.size)throw new CsoError('SNAPSHOT_RACE',`${label} changed before it could be read`);
|
|
const data=Buffer.alloc(max+1);let bytes=0,count=0;while(bytes<data.length&&(count=fs.readSync(fd,data,bytes,data.length-bytes,null))>0)bytes+=count;
|
|
const after=fs.fstatSync(fd),current=fs.lstatSync(path);if(bytes>max)throw new CsoError('MISSING_INPUT',`${label} exceeds the ${max}-byte limit`);
|
|
if(!current.isFile()||current.isSymbolicLink()||current.nlink!==1||current.dev!==opened.dev||current.ino!==opened.ino||current.mode!==opened.mode||after.size!==opened.size||after.mtimeMs!==opened.mtimeMs||after.ctimeMs!==opened.ctimeMs)throw new CsoError('SNAPSHOT_RACE',`${label} changed while it was read`);
|
|
return data.subarray(0,bytes);
|
|
}catch(error){if(error instanceof CsoError)throw error;const code=(error as NodeJS.ErrnoException).code;if(['ELOOP','ENOENT','ENOTDIR','ENXIO'].includes(code??''))throw new CsoError('SNAPSHOT_RACE',`${label} changed before it could be opened`);throw new CsoError('MISSING_INPUT',`${label} is missing or unreadable`);}finally{if(fd!==undefined)fs.closeSync(fd);}
|
|
}
|