Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -104,17 +104,26 @@ export class ConfigExtractor {
/** Read a key and mark it as consumed. Also checks the camelCase/snake_case alias. */
get<T = any>(key: string, defaultValue?: T): T {
this.consumed.add(key);
let value: any;
if (key in this.config) {
return this.config[key] as T;
}
const alias = SNAKE_TO_CAMEL[key] ?? CAMEL_TO_SNAKE[key];
if (alias) {
this.consumed.add(alias);
if (alias in this.config) {
return this.config[alias] as T;
value = this.config[key];
} else {
const alias = SNAKE_TO_CAMEL[key] ?? CAMEL_TO_SNAKE[key];
if (alias) {
this.consumed.add(alias);
if (alias in this.config) {
value = this.config[alias];
}
}
}
return defaultValue as T;
if (value === undefined) {
return defaultValue as T;
}
// Auto-convert string → boolean when the expected type is boolean
if (typeof defaultValue === 'boolean' && typeof value === 'string') {
return (value.toLowerCase() === 'true') as unknown as T;
}
return value as T;
}

/** Check if a key exists (also checks alias). */
Expand Down Expand Up @@ -624,7 +633,7 @@ export const convertLdapEnvConfig = (envKey: string, entry: EnvProviderEntry): C
const searchFilter = ext.get<string>('search_filter', '(uid={{username}})');
const groupSearchBase = ext.get<string>('group_search_base', '');
const groupSearchFilter = ext.get<string>('group_search_filter', '');
const allowSelfSigned = ext.get<any>('allow_self_signed', false);
const allowSelfSigned = ext.get<boolean>('allow_self_signed', false);

// Promoted fields (previously in extra_conf, now first-class)
const searchAttributes = ext.get<string[] | null>('search_attributes', null);
Expand Down Expand Up @@ -677,7 +686,7 @@ export const convertLdapEnvConfig = (envKey: string, entry: EnvProviderEntry): C
search_filter: searchFilter,
group_base: groupSearchBase,
group_filter: groupSearchFilter,
allow_self_signed: allowSelfSigned === true || allowSelfSigned === 'true',
allow_self_signed: allowSelfSigned,
search_attributes: searchAttributes,
username_field: usernameField,
password_field: passwordField,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,60 @@ describe('ConfigExtractor', () => {
const ext = new ConfigExtractor({ a: 1, b: 2 });
expect(ext.getUnconsumedEntries()).toStrictEqual([['a', 1], ['b', 2]]);
});

// --- String → boolean auto-conversion ---

it('should convert string "true" to boolean true when defaultValue is boolean', () => {
const ext = new ConfigExtractor({ flag: 'true' });
expect(ext.get<boolean>('flag', false)).toBe(true);
});

it('should convert string "True" to boolean true (case-insensitive)', () => {
const ext = new ConfigExtractor({ flag: 'True' });
expect(ext.get<boolean>('flag', false)).toBe(true);
});

it('should convert string "TRUE" to boolean true (case-insensitive)', () => {
const ext = new ConfigExtractor({ flag: 'TRUE' });
expect(ext.get<boolean>('flag', false)).toBe(true);
});

it('should convert string "false" to boolean false when defaultValue is boolean', () => {
const ext = new ConfigExtractor({ flag: 'false' });
expect(ext.get<boolean>('flag', true)).toBe(false);
});

it('should convert string "False" to boolean false (case-insensitive)', () => {
const ext = new ConfigExtractor({ flag: 'False' });
expect(ext.get<boolean>('flag', true)).toBe(false);
});

it('should convert string "FALSE" to boolean false (case-insensitive)', () => {
const ext = new ConfigExtractor({ flag: 'FALSE' });
expect(ext.get<boolean>('flag', true)).toBe(false);
});

it('should convert any non-"true" string to false when defaultValue is boolean', () => {
const ext = new ConfigExtractor({ flag: 'yes' });
expect(ext.get<boolean>('flag', true)).toBe(false);
});

it('should NOT convert string when defaultValue is not boolean', () => {
const ext = new ConfigExtractor({ val: 'true' });
expect(ext.get<string>('val', 'fallback')).toBe('true');
});

it('should NOT convert string when no defaultValue is provided', () => {
const ext = new ConfigExtractor({ val: 'true' });
expect(ext.get('val')).toBe('true');
});

it('should return boolean value as-is when value is already boolean', () => {
const ext = new ConfigExtractor({ flag: true });
expect(ext.get<boolean>('flag', false)).toBe(true);
const ext2 = new ConfigExtractor({ flag: false });
expect(ext2.get<boolean>('flag', true)).toBe(false);
});
});

// ==========================================================================
Expand Down