mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-22 08:38:08 +02:00
Setup wizard flow tweaks: - Add a reveal-tail password prompt (reveal-password-prompt.ts) that unmasks the last few characters of a typed/pasted secret, and wire it into the setup prompt adapter in place of clack's password(); adds the @clack/core dep. - Reorder wizard select options: surface "Paste a key" before the environment-variable option across embeddings/models/sources, promote Metabase/Notion in the source list, put Git URL before Local path, reorder the Notion crawl-mode choices, and relabel the sources "Done" action. Query-history filter picker output: - Collapse the per-template parse-failure lines into a single count in the setup output and route the full template-id list to --debug stderr. - Model parse failures as a structured parseFailedTemplateIds field instead of warning strings. - Add a privacy-safe query_history_filter_completed telemetry event (counts/enums only), mirrored into the Python daemon schema.
40 lines
1.5 KiB
TypeScript
40 lines
1.5 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { maskRevealingTail } from '../src/reveal-password-prompt.js';
|
|
|
|
const MASK = '▪';
|
|
|
|
describe('maskRevealingTail', () => {
|
|
it('reveals the last `tail` characters of a long value', () => {
|
|
const value = 'example-token-value-abcd';
|
|
const masked = maskRevealingTail(value, MASK, 4);
|
|
expect(masked).toBe(`${MASK.repeat(value.length - 4)}abcd`);
|
|
expect(masked.endsWith('abcd')).toBe(true);
|
|
});
|
|
|
|
it('keeps the same length as the input so cursor slicing stays aligned', () => {
|
|
for (const secret of ['', 'a', 'abcdefgh', 'abcdefghijklmnop']) {
|
|
expect(maskRevealingTail(secret, MASK, 4)).toHaveLength(secret.length);
|
|
}
|
|
});
|
|
|
|
it('fully masks secrets that are not longer than tail * 2', () => {
|
|
expect(maskRevealingTail('abcdefgh', MASK, 4)).toBe(MASK.repeat(8));
|
|
expect(maskRevealingTail('abcd', MASK, 4)).toBe(MASK.repeat(4));
|
|
expect(maskRevealingTail('ab', MASK, 4)).toBe(MASK.repeat(2));
|
|
});
|
|
|
|
it('reveals the tail once the secret crosses the tail * 2 boundary', () => {
|
|
// length 9 > 8 → reveal last 4, hide the first 5
|
|
expect(maskRevealingTail('abcdefghi', MASK, 4)).toBe(`${MASK.repeat(5)}fghi`);
|
|
});
|
|
|
|
it('fully masks an empty value', () => {
|
|
expect(maskRevealingTail('', MASK, 4)).toBe('');
|
|
});
|
|
|
|
it('honors a custom tail count', () => {
|
|
// tail 2 reveals only when length > 4
|
|
expect(maskRevealingTail('abcde', MASK, 2)).toBe(`${MASK.repeat(3)}de`);
|
|
expect(maskRevealingTail('abcd', MASK, 2)).toBe(MASK.repeat(4));
|
|
});
|
|
});
|