mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-05 16:34:00 +01:00
* feat(release-gate): gate main every 8 hours and feed the stable release (inert until adopted) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs(release-gate): exit codes match the bin Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(release-gate): blobless checkout and free-only workflow classification Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: pre-landing review fixes (finish an open gate before a new head; neutral check for an unfinished gate) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: pre-landing review fixes, pass 2 (the workflow reads main head itself; an open gate on stable or older than three cadences) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: Step 11 review fixes (no paid dispatch without the record on origin; held or failed leaves the gate job green) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(release-gate): re-pin the key to 1.95.0.0 above main; move assertInsideRoot to lib/path-containment.ts to keep ship-policy.ts under 800 lines Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test(release-gate): type the narrow fixture rows (test typecheck ratchet) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(release-gate): charge the trial reservation for a null or missing bisect prefix cost so the cap holds across rounds Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs(capy-install): wrapper 4 follows the update channel (Step 14.5 audit) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test(pregate-selection): mark the fixture wrapper bump as a deliberate old literal Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test(pregate-selection): put the literal marker on its own comment line Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test(release-gate-workflow): run policy steps with Git Bash argument conversion off, as on the Linux runners (windows-scoped-shard) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: release gate evidence and hold in releases.md, release_gate row in the policy key table (Step 14.5 audit) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs(ship-policy): defer the release_gate key-table row to the adoption PR (named documentation risk, GSTA-258) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
24 lines
1023 B
TypeScript
24 lines
1023 B
TypeScript
/** Containment of a repository-relative write path (moved from lib/ship-policy.ts, which re-exports it, to keep that module under its size ratchet). */
|
|
import * as fs from 'node:fs';
|
|
import * as path from 'node:path';
|
|
|
|
/**
|
|
* A working-tree path a stamp may write: inside `root` after realpath (a
|
|
* symlink out of the repository is refused even when the glob matched).
|
|
*/
|
|
export function assertInsideRoot(root: string, rel: string): string | null {
|
|
const realRoot = fs.realpathSync(root);
|
|
const abs = path.resolve(realRoot, rel);
|
|
if (abs !== realRoot && !abs.startsWith(realRoot + path.sep)) return `${rel} resolves outside ${root}`;
|
|
let probe = abs;
|
|
while (!fs.existsSync(probe)) {
|
|
const parent = path.dirname(probe);
|
|
if (parent === probe) break;
|
|
probe = parent;
|
|
}
|
|
let real: string;
|
|
try { real = fs.realpathSync(probe); } catch { return null; }
|
|
if (real !== realRoot && !real.startsWith(realRoot + path.sep)) return `${rel} resolves through a symlink to outside ${root}`;
|
|
return null;
|
|
}
|