diff --git a/src/gatewayOwnership.ts b/src/gatewayOwnership.ts index 3c12d1409..2cc266e31 100644 --- a/src/gatewayOwnership.ts +++ b/src/gatewayOwnership.ts @@ -96,7 +96,7 @@ export async function acquireGatewayOwnership(input: { const alive = existing.hostname !== os.hostname() || isProcessAlive(existing.pid); if (alive) { throw new Error( - `Gateway ownership already held by ${existing.ownerId} on ${existing.hostname} (pid ${existing.pid}). Stop that instance or wait for lease expiry.` + `Gateway ownership already held by another instance (id: ${existing.ownerId}). Stop that instance or wait for lease expiry.` ); } } diff --git a/tests/test_gateway_ownership_disclosure.test.ts b/tests/test_gateway_ownership_disclosure.test.ts new file mode 100644 index 000000000..e9df52d7d --- /dev/null +++ b/tests/test_gateway_ownership_disclosure.test.ts @@ -0,0 +1,29 @@ +import { describe, it, expect } from 'vitest'; + +function buildOwnershipError(ownerId: string, hostname: string, pid: number): string { + return `Gateway ownership already held by another instance (id: ${ownerId}). Stop that instance or wait for lease expiry.`; +} + +describe('gatewayOwnership error message', () => { + it('does not include hostname in error', () => { + const msg = buildOwnershipError('host123:12345', 'host123', 12345); + expect(msg).not.toContain('host123'); + }); + it('does not include PID in error', () => { + const msg = buildOwnershipError('myhost:9999', 'myhost', 9999); + expect(msg).not.toMatch(/\bpid\b/i); + expect(msg).not.toContain('9999'); + }); + it('includes ownerId opaquely', () => { + const msg = buildOwnershipError('abc:1234', 'abc', 1234); + expect(msg).toContain('abc:1234'); + }); + it('includes lease expiry guidance', () => { + const msg = buildOwnershipError('x:1', 'x', 1); + expect(msg).toContain('lease expiry'); + }); + it('error message is a plain string', () => { + const msg = buildOwnershipError('a:1', 'a', 1); + expect(typeof msg).toBe('string'); + }); +});