mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 15:51:26 +00:00
PUT /services/{id}/variables replaced every row, and GET masks secrets as
******** — echoing the fetched list back would have overwritten real
secrets with asterisks. The backend now keeps the stored value when a
submitted secret still carries the mask.
Service detail gains a Variables section: add/edit/remove rows, secret
toggle, bulk .env paste (comments, export prefix, quoted values), and
inline validation for empty/invalid/duplicate keys. Parser and validator
live in variable-utils.ts with unit coverage.
Generated OpenAPI types drive the new updateServiceVariables client call.
ROADMAP: Variables UX marked done; per-environment values are already
structural — each environment owns its service instances.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
41 lines
1.3 KiB
TypeScript
41 lines
1.3 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { parseDotenv, validateVariableRows } from './variable-utils';
|
|
|
|
describe('parseDotenv', () => {
|
|
it('parses KEY=VAL lines and skips blanks/comments', () => {
|
|
const rows = parseDotenv('A=1\n\n# comment\nB=two\n');
|
|
expect(rows).toEqual([
|
|
{ key: 'A', value: '1', isSecret: false },
|
|
{ key: 'B', value: 'two', isSecret: false },
|
|
]);
|
|
});
|
|
|
|
it('strips export prefix and quotes, keeps = inside values', () => {
|
|
const rows = parseDotenv('export A="x=y"\nB=\' spaced \'\nC=plain\n');
|
|
expect(rows.map((r) => [r.key, r.value])).toEqual([
|
|
['A', 'x=y'],
|
|
['B', ' spaced '],
|
|
['C', 'plain'],
|
|
]);
|
|
});
|
|
|
|
it('ignores malformed lines without a key', () => {
|
|
expect(parseDotenv('=novalue\njusttext\n')).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe('validateVariableRows', () => {
|
|
it('flags empty, invalid, and duplicate keys', () => {
|
|
const errors = validateVariableRows([
|
|
{ key: 'OK', value: '1', isSecret: false },
|
|
{ key: '', value: 'x', isSecret: false },
|
|
{ key: '9BAD', value: 'x', isSecret: false },
|
|
{ key: 'OK', value: '2', isSecret: false },
|
|
]);
|
|
expect(errors[0]).toBeUndefined();
|
|
expect(errors[1]).toBe('Key is required');
|
|
expect(errors[2]).toContain('Letters, digits');
|
|
expect(errors[3]).toBe('Duplicate key');
|
|
});
|
|
});
|