import { describe, expect, it } from 'vitest'; import { REDACTED_KTX_CREDENTIAL_VALUE } from '../../../src/context/core/redaction.js'; import { redactKtxCredentialEnvelope, redactKtxCredentialValue, redactKtxScanMetadata, redactKtxScanReport, redactKtxScanWarning, } from '../../../src/context/scan/credentials.js'; import type { KtxCredentialEnvelope, KtxScanReport, KtxScanWarning } from '../../../src/context/scan/types.js'; describe('KTX scan credential redaction', () => { it('keeps credential references inspectable', () => { const envReference: KtxCredentialEnvelope = { kind: 'env', name: 'DATABASE_URL' }; const fileReference: KtxCredentialEnvelope = { kind: 'file', path: '~/.config/ktx/warehouse' }; expect(redactKtxCredentialEnvelope(envReference)).toEqual(envReference); expect(redactKtxCredentialEnvelope(fileReference)).toEqual(fileReference); }); it('redacts resolved credential envelope values recursively', () => { expect( redactKtxCredentialEnvelope({ kind: 'resolved', source: 'host', values: { username: 'readonly', password: 'secret-password', // pragma: allowlist secret nested: { api_key: 'phx_123', // pragma: allowlist secret warehouse: 'compute_wh', }, headers: [{ authorizationToken: 'token-value' }, { label: 'safe' }], }, }), ).toEqual({ kind: 'resolved', source: 'host', redacted: true, values: { username: 'readonly', password: REDACTED_KTX_CREDENTIAL_VALUE, nested: { api_key: REDACTED_KTX_CREDENTIAL_VALUE, warehouse: 'compute_wh', }, headers: [{ authorizationToken: REDACTED_KTX_CREDENTIAL_VALUE }, { label: 'safe' }], }, }); }); it('redacts scan metadata fields that commonly contain secrets', () => { expect( redactKtxScanMetadata({ driver: 'postgres', url: 'postgres://user:pass@example.test/db', // pragma: allowlist secret serviceAccountJson: { client_email: 'reader@example.test', private_key: 'pem-value', // pragma: allowlist secret }, safeCount: 3, }), ).toEqual({ driver: 'postgres', url: REDACTED_KTX_CREDENTIAL_VALUE, serviceAccountJson: { client_email: 'reader@example.test', private_key: REDACTED_KTX_CREDENTIAL_VALUE, }, safeCount: 3, }); }); it('redacts scan warning messages and metadata without hiding safe context', () => { const warning: KtxScanWarning = { code: 'sampling_failed', message: 'sample failed for postgres://reader:secret@example.test/db', // pragma: allowlist secret recoverable: true, metadata: { table: 'orders', url: 'postgres://reader:secret@example.test/db', // pragma: allowlist secret nested: { api_key: 'sk_test_123', // pragma: allowlist secret schema: 'public', }, }, }; expect(redactKtxScanWarning(warning)).toEqual({ code: 'sampling_failed', message: 'sample failed for postgres://reader:@example.test/db', recoverable: true, metadata: { table: 'orders', url: REDACTED_KTX_CREDENTIAL_VALUE, nested: { api_key: REDACTED_KTX_CREDENTIAL_VALUE, schema: 'public', }, }, }); }); it('redacts scan report warning metadata recursively', () => { const report: KtxScanReport = { connectionId: 'warehouse', driver: 'postgres', syncId: 'sync-1', runId: 'run-1', trigger: 'cli', mode: 'structural', dryRun: false, artifactPaths: { rawSourcesDir: 'raw-sources/warehouse/live-database/sync-1', reportPath: 'raw-sources/warehouse/live-database/sync-1/scan-report.json', manifestShards: [], enrichmentArtifacts: [], }, diffSummary: { tablesAdded: 0, tablesModified: 0, tablesDeleted: 0, tablesUnchanged: 0, columnsAdded: 0, columnsModified: 0, columnsDeleted: 0, }, manifestShardsWritten: 0, structuralSyncStats: { tablesCreated: 0, tablesUpdated: 0, tablesDeleted: 0, columnsCreated: 0, columnsUpdated: 0, columnsDeleted: 0, }, enrichment: { dataDictionary: 'skipped', tableDescriptions: 'skipped', columnDescriptions: 'skipped', embeddings: 'skipped', deterministicRelationships: 'skipped', llmRelationshipValidation: 'skipped', statisticalValidation: 'skipped', }, capabilityGaps: [], warnings: [ { code: 'credential_redacted', message: 'metadata redacted', recoverable: true, metadata: { credentials_json: '{"private_key":"pem-value"}', // pragma: allowlist secret safeCount: 2, }, }, ], relationships: { accepted: 0, review: 0, rejected: 0, skipped: 0 }, enrichmentState: { resumedStages: [], completedStages: [], failedStages: [], }, createdAt: '2026-04-29T00:00:00.000Z', }; const redacted = redactKtxScanReport(report); expect(redacted.warnings[0]?.metadata).toEqual({ credentials_json: REDACTED_KTX_CREDENTIAL_VALUE, safeCount: 2, }); expect(report.warnings[0]?.metadata).toEqual({ credentials_json: '{"private_key":"pem-value"}', // pragma: allowlist secret safeCount: 2, }); }); it('redacts standalone primitive credential values only when the field key is sensitive', () => { expect(redactKtxCredentialValue('password', 'abc')).toBe(REDACTED_KTX_CREDENTIAL_VALUE); expect(redactKtxCredentialValue('schema', 'public')).toBe('public'); }); });