Files
dockhand-upstream/tests/invault-markers.test.ts

91 lines
4.1 KiB
TypeScript

import { describe, test, expect } from 'bun:test';
import { classifyMarker, resolvedRefVarNames, effectiveMissing } from '../src/lib/utils/invault-markers';
describe('classifyMarker', () => {
const inVault = new Set(['DB_PASSWORD', 'API_KEY']);
test('a defined var is required regardless of the provider set', () => {
expect(classifyMarker('APP_ENV', false, inVault, false)).toBe('required');
});
test('a missing var present in the provider is invault (green)', () => {
expect(classifyMarker('DB_PASSWORD', true, inVault, false)).toBe('invault');
});
test('a missing var absent from the provider stays missing (red)', () => {
expect(classifyMarker('DUMMY', true, inVault, false)).toBe('missing');
});
test('probe failure forces MISSING even for a key that would be in the provider', () => {
// Never a false green when we could not reach the provider.
expect(classifyMarker('DB_PASSWORD', true, inVault, true)).toBe('missing');
});
test('empty provider set -> every missing var is missing', () => {
expect(classifyMarker('DB_PASSWORD', true, new Set(), false)).toBe('missing');
});
});
// The editor's live marker must never depend on a provider being present. A user
// with NO provider (or one that was unbound after a deploy) sees the exact old
// behavior: missing vars are red MISSING, never a stray green.
describe('classifyMarker - no-provider / unbound regression', () => {
test('no provider bound: runProbe leaves an empty set + no error -> plain MISSING', () => {
// This is the state runProbe() sets when formSecretProviderId === null.
const noProvider = new Set<string>();
expect(classifyMarker('DB_PASSWORD', true, noProvider, false)).toBe('missing');
expect(classifyMarker('API_KEY', true, noProvider, false)).toBe('missing');
});
test('a defined var is required with no provider (editor unaffected)', () => {
expect(classifyMarker('APP_ENV', false, new Set(), false)).toBe('required');
});
test('provider unbound after a deploy: live probe set is empty, so those keys go MISSING in the editor (banner history is separate)', () => {
// DB has injected_secret_keys from a past deploy, but the provider is now
// unbound -> the live probe set is empty. The EDITOR must show MISSING; the
// last-deploy banner (driven separately by injectedSecretKeys) is not this path.
const liveSetAfterUnbind = new Set<string>();
expect(classifyMarker('DB_PASSWORD', true, liveSetAfterUnbind, false)).toBe('missing');
});
});
// The panel's missing count / "Add missing" list must match the editor's IN VAULT
// markers - both drop ONLY the keys the LIVE probe found in the provider. The
// last-deploy injected table is never consulted here (that drives only the banner).
describe('effectiveMissing (panel <-> editor consistency, live only)', () => {
test('drops LIVE provider keys from missing, so the panel agrees with IN VAULT', () => {
// The bug: editor showed IN VAULT but the panel still counted them missing.
const missing = ['DB_PASSWORD', 'API_KEY', 'REDIS_URL', 'MISSING_ONE'];
const live = new Set(['DB_PASSWORD', 'API_KEY', 'REDIS_URL']);
expect(effectiveMissing(missing, live)).toEqual(['MISSING_ONE']);
});
test('probe failed / no provider (empty live set) -> nothing dropped, stays missing', () => {
const missing = ['DB_PASSWORD', 'MISSING_ONE'];
expect(effectiveMissing(missing, new Set())).toEqual(missing);
});
});
describe('resolvedRefVarNames', () => {
test('maps resolved ref STRINGS back to their var names', () => {
const pairs = [
{ varName: 'DB_PASSWORD', ref: 'op://vault/db/password' },
{ varName: 'API_KEY', ref: 'op://vault/api/key' },
{ varName: 'STALE', ref: 'op://vault/gone/secret' }
];
// provider resolved only the first two refs
expect(resolvedRefVarNames(pairs, ['op://vault/db/password', 'op://vault/api/key']))
.toEqual(['DB_PASSWORD', 'API_KEY']);
});
test('a ref that did not resolve is dropped', () => {
const pairs = [{ varName: 'STALE', ref: 'op://vault/gone/secret' }];
expect(resolvedRefVarNames(pairs, [])).toEqual([]);
});
test('no inline refs -> empty', () => {
expect(resolvedRefVarNames([], ['op://whatever'])).toEqual([]);
});
});