mirror of
https://github.com/garrytan/gbrain.git
synced 2026-08-14 00:48:18 +00:00
Non-string values interpolated into the template literal printed '[object Object]' (e.g. provider_base_urls). Objects now render via JSON.stringify; objects under a sensitive key redact to '***' like their string counterparts. Co-authored-by: Garry Tan <garrytan@gmail.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Garry Tan
Claude Opus 5
parent
ad7114f0ad
commit
f84bfb57f2
@@ -46,7 +46,14 @@ export async function runConfig(engine: BrainEngine, args: string[]) {
|
||||
}
|
||||
console.log('GBrain config:');
|
||||
for (const [k, v] of Object.entries(config)) {
|
||||
const display = typeof v === 'string' ? redactConfigValue(k, v) : v;
|
||||
// #575: objects interpolated into the template literal printed
|
||||
// `[object Object]` — render them as JSON instead. Sensitive keys
|
||||
// stay redacted whether the value is a string or an object.
|
||||
const display = typeof v === 'string'
|
||||
? redactConfigValue(k, v)
|
||||
: v !== null && typeof v === 'object'
|
||||
? (isSensitiveConfigKey(k) ? '***' : JSON.stringify(v))
|
||||
: v;
|
||||
console.log(` ${k}: ${display}`);
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* #575 — `gbrain config show` printed `[object Object]` for object-valued
|
||||
* config fields (e.g. `provider_base_urls`) because non-string values were
|
||||
* interpolated straight into a template literal.
|
||||
*
|
||||
* Behavioral pin: object values render as JSON; object values under a
|
||||
* sensitive key stay redacted; scalars keep their existing rendering.
|
||||
*/
|
||||
import { describe, test, expect } from 'bun:test';
|
||||
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'fs';
|
||||
import { tmpdir } from 'os';
|
||||
import { join } from 'path';
|
||||
import { withEnv } from './helpers/with-env.ts';
|
||||
import { runConfig } from '../src/commands/config.ts';
|
||||
import type { BrainEngine } from '../src/core/engine.ts';
|
||||
|
||||
describe('config show object-valued fields (#575)', () => {
|
||||
test('provider_base_urls renders as JSON, not [object Object]', async () => {
|
||||
const tmpHome = mkdtempSync(join(tmpdir(), 'gbrain-cfgshow-'));
|
||||
try {
|
||||
mkdirSync(join(tmpHome, '.gbrain'), { recursive: true });
|
||||
writeFileSync(join(tmpHome, '.gbrain', 'config.json'), JSON.stringify({
|
||||
engine: 'pglite',
|
||||
database_path: join(tmpHome, '.gbrain', 'brain'),
|
||||
provider_base_urls: { ollama: 'http://localhost:11434' },
|
||||
some_nested_secret: { api_key: 'sk-super-secret' },
|
||||
}, null, 2));
|
||||
|
||||
const outLines: string[] = [];
|
||||
const origLog = console.log;
|
||||
console.log = (...args: unknown[]) => { outLines.push(args.map(String).join(' ')); };
|
||||
try {
|
||||
await withEnv({ GBRAIN_HOME: tmpHome, DATABASE_URL: undefined }, async () => {
|
||||
await runConfig({} as unknown as BrainEngine, ['show']);
|
||||
});
|
||||
} finally {
|
||||
console.log = origLog;
|
||||
}
|
||||
|
||||
const out = outLines.join('\n');
|
||||
expect(out).not.toContain('[object Object]');
|
||||
const urlLine = outLines.find(l => l.includes('provider_base_urls'));
|
||||
expect(urlLine).toBeDefined();
|
||||
expect(urlLine!).toContain('http://localhost:11434');
|
||||
// Objects under a sensitive key must NOT leak their contents.
|
||||
const secretLine = outLines.find(l => l.includes('some_nested_secret'));
|
||||
expect(secretLine).toBeDefined();
|
||||
expect(secretLine!).not.toContain('sk-super-secret');
|
||||
} finally {
|
||||
rmSync(tmpHome, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user