mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-04 15:57:33 +01:00
* test: an exported live-brain URL must not reach a temp-HOME gbrain child (#3466) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(test): strip the variables that point gbrain at a live brain in the test preload (#3466) Co-authored-by: AndreIntelas <126392195+AndreIntelas@users.noreply.github.com> 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> Co-authored-by: AndreIntelas <126392195+AndreIntelas@users.noreply.github.com>
This commit is contained in:
6 files changed
+60
-3
No files matched your search
@@ -1,5 +1,15 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [1.93.13.0] - 2026-11-02
|
||||||
|
|
||||||
|
**gstack's own tests no longer write into a developer's real gbrain.** If you export `GBRAIN_DATABASE_URL` for your working brain and run gstack's test suite, tests that spawn bins with a temp `HOME` used to pass that URL straight through. With no gbrain config under the temp `HOME`, the real `gbrain` on your PATH then added `brain-sync-remote-*` sources and test pages to your live brain. From #3466 by @AndreIntelas.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- **The test preload (`test-setup.ts`) strips the variables gbrain uses to pick a brain** before any test module loads: `GBRAIN_DATABASE_URL`, `GBRAIN_DIRECT_DATABASE_URL`, `DATABASE_URL` and `GBRAIN_HOME`. It prints one line on stderr for each variable it strips. This covers `bun test <file>` and every shard of `bun run test`.
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
- `test/state-root-config-merge.test.ts`: a `bun test` run with all four variables exported spawns a child under a temp `HOME` that calls `buildGbrainEnv`, and the child sees none of them. It fails on main.
|
||||||
|
|
||||||
## [1.93.12.0] - 2026-11-02
|
## [1.93.12.0] - 2026-11-02
|
||||||
|
|
||||||
**The Opus 5.5 `lite` skills now keep the install's gbrain blocks, disabled skills and the Claims Need Evidence rule (GST-944).** The lite tree Capy publishes was rendered without the install's settings. On a machine with gbrain detected, Opus 5.5 sessions lost the brain context-load and save-results blocks that the full install serves, and skills turned off with `disabled_skills` showed up again in the lite router. `./setup --loadout lite` was not affected.
|
**The Opus 5.5 `lite` skills now keep the install's gbrain blocks, disabled skills and the Claims Need Evidence rule (GST-944).** The lite tree Capy publishes was rendered without the install's settings. On a machine with gbrain detected, Opus 5.5 sessions lost the brain context-load and save-results blocks that the full install serves, and skills turned off with `disabled_skills` showed up again in the lite router. `./setup --loadout lite` was not affected.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# gstack digest v1.93.12.0 — regenerate/re-copy after upgrading gstack
|
# gstack digest v1.93.13.0 — regenerate/re-copy after upgrading gstack
|
||||||
|
|
||||||
Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed
|
Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed
|
||||||
for agent hosts without a full skill install. The full skills add workflows,
|
for agent hosts without a full skill install. The full skills add workflows,
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "gstack",
|
"name": "gstack",
|
||||||
"version": "1.93.12",
|
"version": "1.93.13",
|
||||||
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
|
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -39,6 +39,15 @@ for (const name of ['GSTACK_STATE_ROOT', 'GSTACK_STATE_DIR']) {
|
|||||||
// an unattended Capy session it never set up. The shard engine strips the same
|
// an unattended Capy session it never set up. The shard engine strips the same
|
||||||
// list for the lanes; this reaches direct runs too.
|
// list for the lanes; this reaches direct runs too.
|
||||||
for (const name of CAPY_LAUNCH_MARKERS) delete process.env[name];
|
for (const name of CAPY_LAUNCH_MARKERS) delete process.env[name];
|
||||||
|
// The variables gbrain reads to pick a brain (#3466). Tests spawn bins with
|
||||||
|
// { ...process.env, HOME: <tmp> }; with no gbrain config under the temp HOME,
|
||||||
|
// buildGbrainEnv passes an exported URL through and a real gbrain on PATH
|
||||||
|
// writes test pages and sources into the developer's live brain.
|
||||||
|
for (const name of ['GBRAIN_DATABASE_URL', 'GBRAIN_DIRECT_DATABASE_URL', 'DATABASE_URL', 'GBRAIN_HOME']) {
|
||||||
|
if (process.env[name] === undefined) continue;
|
||||||
|
delete process.env[name];
|
||||||
|
process.stderr.write(`test-setup: stripped inherited ${name}; tests must not reach a live gbrain\n`);
|
||||||
|
}
|
||||||
process.env.GSTACK_TEST_LEGACY_ROOT = path.join(os.tmpdir(), `gstack-test-legacy-root-${process.pid}-${Date.now()}-unused`);
|
process.env.GSTACK_TEST_LEGACY_ROOT = path.join(os.tmpdir(), `gstack-test-legacy-root-${process.pid}-${Date.now()}-unused`);
|
||||||
// Workflow leases (bin/gstack-lease) default to the installation's git dir;
|
// Workflow leases (bin/gstack-lease) default to the installation's git dir;
|
||||||
// for the dev checkout under test that is this repo's .git, and a live test
|
// for the dev checkout under test that is this repo's .git, and a live test
|
||||||
|
|||||||
@@ -163,4 +163,42 @@ describe('test preload hermeticity', () => {
|
|||||||
expect(r.stderr).toContain('test-setup: stripped inherited GSTACK_STATE_DIR; tests isolate state via GSTACK_HOME');
|
expect(r.stderr).toContain('test-setup: stripped inherited GSTACK_STATE_DIR; tests isolate state via GSTACK_HOME');
|
||||||
expect(r.stderr.match(/test-setup: stripped/g)?.length).toBe(2);
|
expect(r.stderr.match(/test-setup: stripped/g)?.length).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('bun test strips an inherited live-brain URL, so a temp-HOME gbrain child never sees it (#3466)', () => {
|
||||||
|
const live = path.join(tmp, 'live-gbrain');
|
||||||
|
fs.mkdirSync(live, { recursive: true });
|
||||||
|
fs.writeFileSync(path.join(live, 'config.json'), JSON.stringify({ database_url: 'postgresql://live-config.invalid/brain' }));
|
||||||
|
const childHome = path.join(tmp, 'child-home');
|
||||||
|
fs.mkdirSync(childHome, { recursive: true });
|
||||||
|
const probe = path.join(tmp, 'brain-probe.test.ts');
|
||||||
|
fs.writeFileSync(probe, [
|
||||||
|
"import { test, expect } from 'bun:test';",
|
||||||
|
"import { spawnSync } from 'child_process';",
|
||||||
|
"test('probe', () => {",
|
||||||
|
" const script = \"const { buildGbrainEnv } = require(\" + JSON.stringify(" + JSON.stringify(path.join(ROOT, 'lib', 'gbrain-exec.ts')) + ") + \"); const e = buildGbrainEnv(); console.log(['GBRAIN_DATABASE_URL','GBRAIN_DIRECT_DATABASE_URL','DATABASE_URL','GBRAIN_HOME'].map(k => k + '=' + (e[k] ?? '<unset>')).join(' '));\";",
|
||||||
|
" const r = spawnSync(process.execPath, ['--no-env-file', '--config=/dev/null', '-e', script], {",
|
||||||
|
" env: { ...process.env, HOME: " + JSON.stringify(childHome) + " }, encoding: 'utf-8', timeout: 30_000,",
|
||||||
|
" });",
|
||||||
|
" expect(r.stdout.trim()).toBe('GBRAIN_DATABASE_URL=<unset> GBRAIN_DIRECT_DATABASE_URL=<unset> DATABASE_URL=<unset> GBRAIN_HOME=<unset>');",
|
||||||
|
"});",
|
||||||
|
].join('\n'));
|
||||||
|
const r = spawnSync('bun', ['test', '--preload', path.join(ROOT, 'test-setup.ts'), probe], {
|
||||||
|
cwd: tmp,
|
||||||
|
env: {
|
||||||
|
...env, GSTACK_HOME: resolved,
|
||||||
|
GBRAIN_DATABASE_URL: 'postgresql://live-brain.invalid/brain',
|
||||||
|
GBRAIN_DIRECT_DATABASE_URL: 'postgresql://live-brain.invalid/direct',
|
||||||
|
DATABASE_URL: 'postgresql://live-brain.invalid/fallback',
|
||||||
|
GBRAIN_HOME: live,
|
||||||
|
},
|
||||||
|
encoding: 'utf-8',
|
||||||
|
timeout: 60_000,
|
||||||
|
});
|
||||||
|
expect(r.stderr).not.toContain('live-brain.invalid');
|
||||||
|
expect(r.stderr).not.toContain('live-config.invalid');
|
||||||
|
expect(r.status).toBe(0);
|
||||||
|
for (const name of ['GBRAIN_DATABASE_URL', 'GBRAIN_DIRECT_DATABASE_URL', 'DATABASE_URL', 'GBRAIN_HOME']) {
|
||||||
|
expect(r.stderr).toContain(`test-setup: stripped inherited ${name}; tests must not reach a live gbrain`);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
Reference in new issue
Block a user