From 5b95eb187423395eece169200fce1b8d9d201715 Mon Sep 17 00:00:00 2001 From: William Valentin Date: Mon, 23 Feb 2026 17:10:53 -0800 Subject: [PATCH] fix(audit): expand tilde paths for audit log output --- src/audit/logger.test.ts | 49 ++++++++++++++++++++++++++++++++++++++++ src/audit/logger.ts | 19 ++++++++++++---- 2 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 src/audit/logger.test.ts diff --git a/src/audit/logger.test.ts b/src/audit/logger.test.ts new file mode 100644 index 0000000..3c22e74 --- /dev/null +++ b/src/audit/logger.test.ts @@ -0,0 +1,49 @@ +import { existsSync, mkdtempSync, readFileSync, rmSync } from 'fs'; +import { homedir, tmpdir } from 'os'; +import { join, resolve } from 'path'; +import { describe, expect, it } from 'vitest'; +import { AuditLogger } from './logger.js'; + +describe('AuditLogger', () => { + it('expands ~ in audit path before writing logs', async () => { + const previousHome = process.env.HOME; + const tempHome = mkdtempSync(join(tmpdir(), 'flynn-audit-home-')); + process.env.HOME = tempHome; + + try { + // Sanity-check this process sees the temp home. + expect(homedir()).toBe(tempHome); + + const logger = new AuditLogger({ + enabled: true, + path: '~/.local/share/flynn/audit.log', + max_size_mb: 10, + keep_days: 30, + levels: { + tools: 'debug', + sessions: 'debug', + automation: 'debug', + }, + }); + + logger.systemStart('test-component'); + await logger.close(); + await new Promise((resolvePromise) => setTimeout(resolvePromise, 25)); + + const loggerPath = (logger as unknown as { config: { path: string } }).config.path; + const expectedPath = resolve(tempHome, '.local/share/flynn/audit.log'); + expect(loggerPath).toBe(expectedPath); + expect(existsSync(expectedPath)).toBe(true); + const content = readFileSync(expectedPath, 'utf-8'); + expect(content).toContain('"event_type":"system.start"'); + expect(content).toContain('"component":"test-component"'); + } finally { + if (previousHome === undefined) { + delete process.env.HOME; + } else { + process.env.HOME = previousHome; + } + rmSync(tempHome, { recursive: true, force: true }); + } + }); +}); diff --git a/src/audit/logger.ts b/src/audit/logger.ts index e0fd065..a6d8f35 100644 --- a/src/audit/logger.ts +++ b/src/audit/logger.ts @@ -1,5 +1,6 @@ import { createWriteStream, existsSync, mkdirSync } from 'fs'; -import { dirname } from 'path'; +import { dirname, resolve } from 'path'; +import { homedir } from 'os'; import type { AuditEvent, AuditConfig, @@ -41,8 +42,11 @@ export class AuditLogger { private rotator: AuditRotator; constructor(config: AuditConfig) { - this.config = config; - this.rotator = new AuditRotator(config); + this.config = { + ...config, + path: expandPath(config.path), + }; + this.rotator = new AuditRotator(this.config); if (!this.config.enabled) { return; @@ -50,7 +54,7 @@ export class AuditLogger { this.ensureLogDirectory(); this.rotator.checkRotation(); - this.writeStream = createWriteStream(config.path, { flags: 'a' }); + this.writeStream = createWriteStream(this.config.path, { flags: 'a' }); } private ensureLogDirectory(): void { @@ -357,3 +361,10 @@ export class AuditLogger { } } } + +function expandPath(p: string): string { + if (p.startsWith('~/') || p === '~') { + return resolve(homedir(), p.slice(2)); + } + return resolve(p); +}