mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-02 23:14:33 +01:00
test(fixtures): leak scan skips Capy's git shim log in fixture homes (#3860)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
322906ab2b
commit
0542230e63
6 files changed
+34
-5
No files matched your search
@@ -1,5 +1,13 @@
|
||||
# Changelog
|
||||
|
||||
## [1.92.80.0] - 2026-11-02
|
||||
|
||||
**On a Capy machine, the git fixture tests no longer fail locally because of Capy's git shim log.** Capy's `/usr/bin/git` shim appends to `$HOME/.capy/git-shim.log`, so each fixture home that ran git during its template build ended up with a log naming the template. The leak scan in `test/helpers/git-fixture-template.ts` flagged it, and 34 tests in `test/train-backstop.test.ts`, `test/restamp-mentions.test.ts` and `test/pregate-user-policy.test.ts` failed on every Capy lane, though they passed on the remote gate.
|
||||
|
||||
### Tests
|
||||
- `templateReferences` skips `.capy/git-shim.log`. Nothing reads that file back, and every other file is still scanned.
|
||||
- `test/git-fixture-template.test.ts` plants the shim log in a template's `home/.capy/` (the copy succeeds), and plants `home/.capy/state.json` as a control (the copy still throws).
|
||||
|
||||
## [1.92.79.0] - 2026-11-02
|
||||
|
||||
**/plan-tune no longer reports a mismatch between your stated and observed preferences when it has no observed answers behind it (#3436).** `--check-mismatch` compared a declared value against an inferred value that had never moved from its 0.5 starting point, so a strong declaration with no matching answers printed `scope_appetite: declared 0.9 vs inferred 0.5 (gap 0.4)` even though no logged answer touched that dimension.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# gstack digest v1.92.79.0 — regenerate/re-copy after upgrading gstack
|
||||
# gstack digest v1.92.80.0 — regenerate/re-copy after upgrading gstack
|
||||
|
||||
Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed
|
||||
for agent hosts without a full skill install. The full skills add workflows,
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gstack",
|
||||
"version": "1.92.79",
|
||||
"version": "1.92.80",
|
||||
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
|
||||
@@ -71,6 +71,23 @@ describe('git fixture template', () => {
|
||||
expect(() => leaky.copy()).toThrow(/still references its template [^\n]*\n.*config/);
|
||||
});
|
||||
|
||||
test("Capy's git shim log in a fixture home (home/.capy/git-shim.log) is not a leak; any other file naming the template still is", () => {
|
||||
const plant = (rel: string) => gitFixtureTemplate({ prefix: 'gstack-fixture-template-shim-', build: (root) => {
|
||||
const meta = build(root);
|
||||
fs.mkdirSync(path.dirname(path.join(root, rel)), { recursive: true });
|
||||
fs.writeFileSync(path.join(root, rel), '# capy git shim v2: ts cwd ppid parent verb\n2026-11-02T02:15:30Z\t' + path.join(root, 'work') + '\t1\tbun\tcat-file\n');
|
||||
return meta;
|
||||
}, rebind: (copy, tpl) => rebindGitDir(path.join(copy, 'work', '.git'), tpl, copy) });
|
||||
const shim = plant(path.join('home', '.capy', 'git-shim.log'));
|
||||
const other = plant(path.join('home', '.capy', 'state.json'));
|
||||
try {
|
||||
const c = shim.copy();
|
||||
roots.push(c.root);
|
||||
expect(git(path.join(c.root, 'work'), 'remote', 'get-url', 'origin')).toBe(path.join(c.root, 'origin.git'));
|
||||
expect(() => other.copy()).toThrow(/still references its template [^\n]*\n.*state\.json/);
|
||||
} finally { shim.dispose(); other.dispose(); }
|
||||
});
|
||||
|
||||
test('native, forward-slash, backslash-escaped and Git Bash spellings are each rewritten, and each one left behind is found', () => {
|
||||
const to = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-fixture-spellings-'));
|
||||
roots.push(to);
|
||||
|
||||
@@ -52,7 +52,11 @@ export function rebindGitDir(gitDir: string, from: string, to: string): void {
|
||||
}
|
||||
}
|
||||
|
||||
/** Files and symlinks under dir (and the template's meta value) that still name templateRoot; zlib-compressed object storage is skipped. */
|
||||
/**
|
||||
* Files and symlinks under dir (and the template's meta value) that still name templateRoot. Skipped: zlib-compressed object
|
||||
* storage, and the log Capy's /usr/bin/git shim appends to in whatever HOME it runs under (.capy/git-shim.log), which names
|
||||
* the template whenever a fixture home ran git during build; nothing reads it back.
|
||||
*/
|
||||
export function templateReferences(dir: string, templateRoot: string, meta?: unknown): string[] {
|
||||
const needles = pathSpellings(templateRoot).map(s => Buffer.from(s));
|
||||
const names = (buf: Buffer) => needles.some(n => buf.includes(n));
|
||||
@@ -62,7 +66,7 @@ export function templateReferences(dir: string, templateRoot: string, meta?: unk
|
||||
const p = path.join(d, entry.name);
|
||||
if (entry.isSymbolicLink()) { if (names(Buffer.from(fs.readlinkSync(p)))) hits.push(p); }
|
||||
else if (entry.isDirectory()) { if (!(path.basename(d) === 'objects' && /^(pack|[0-9a-f]{2})$/.test(entry.name))) walk(p); }
|
||||
else if (entry.isFile() && names(fs.readFileSync(p))) hits.push(p);
|
||||
else if (entry.isFile() && !(entry.name === 'git-shim.log' && path.basename(d) === '.capy') && names(fs.readFileSync(p))) hits.push(p);
|
||||
}
|
||||
};
|
||||
walk(dir);
|
||||
|
||||
Reference in new issue
Block a user