fix(storage): redact credentials in driver errors + advisory lock (FED-M1-10) (#479)
Some checks failed
ci/woodpecker/push/ci Pipeline failed
ci/woodpecker/push/publish Pipeline failed

This commit was merged in pull request #479.
This commit is contained in:
2026-04-20 02:02:57 +00:00
parent 1e2b8ac8de
commit dc4afee848
6 changed files with 261 additions and 70 deletions

View File

@@ -0,0 +1,62 @@
import { describe, it, expect } from 'vitest';
import { redactErrMsg } from './redact-error.js';
describe('redactErrMsg', () => {
it('redacts user:password from a postgres:// URL embedded in an error message', () => {
const msg = 'connect ECONNREFUSED postgres://admin:s3cr3t@db.example.com:5432/mosaic';
expect(redactErrMsg(msg)).toBe(
'connect ECONNREFUSED postgres://***@db.example.com:5432/mosaic',
);
});
it('redacts user:password from a postgresql:// URL', () => {
const msg = 'connection failed: postgresql://myuser:mypass@localhost:5432/testdb';
expect(redactErrMsg(msg)).toBe('connection failed: postgresql://***@localhost:5432/testdb');
});
it('handles URLs with no password (user only) — still redacts userinfo', () => {
const msg = 'error postgres://justuser@host:5432/db';
expect(redactErrMsg(msg)).toBe('error postgres://***@host:5432/db');
});
it('returns the original message unchanged when no connection URL is present', () => {
const msg = 'connection timed out after 5 seconds';
expect(redactErrMsg(msg)).toBe('connection timed out after 5 seconds');
});
it('is case-insensitive for the scheme (scheme is normalized to lowercase in output)', () => {
// The regex replacement uses a lowercase literal, so the matched scheme is
// replaced with the lowercase form regardless of the original casing.
const msg = 'POSTGRES://admin:pass@host:5432/db';
expect(redactErrMsg(msg)).toBe('postgres://***@host:5432/db');
});
it('redacts multiple URLs in a single message', () => {
const msg = 'src postgres://u:p@host1/db1 dst postgresql://v:q@host2/db2';
expect(redactErrMsg(msg)).toBe('src postgres://***@host1/db1 dst postgresql://***@host2/db2');
});
it('does not alter a message with a postgres URL that has no userinfo', () => {
// No userinfo component — pattern does not match, message unchanged.
const msg = 'error at postgres://host:5432/db';
expect(redactErrMsg(msg)).toBe('error at postgres://host:5432/db');
});
it('redacts user:password from a redis:// URL', () => {
const msg = 'connect ECONNREFUSED redis://user:pass@host:6379';
expect(redactErrMsg(msg)).toBe('connect ECONNREFUSED redis://***@host:6379');
});
it('redacts user:password from a rediss:// URL (TLS)', () => {
const msg = 'connect ECONNREFUSED rediss://user:pass@host:6379';
expect(redactErrMsg(msg)).toBe('connect ECONNREFUSED rediss://***@host:6379');
});
it('redacts both a postgres URL and a redis URL in the same message', () => {
const msg =
'primary postgres://admin:s3cr3t@db:5432/mosaic cache redis://cacheuser:cachepass@cache:6379';
expect(redactErrMsg(msg)).toBe(
'primary postgres://***@db:5432/mosaic cache redis://***@cache:6379',
);
});
});