Parse the config input once

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Henry Mercer
2026-10-02 14:29:22 +01:00
parent e869836b5a
commit 113b18e688
8 changed files with 175 additions and 90 deletions

View File

@@ -626,6 +626,16 @@ test("mergeDefaultSetupAndUserConfigs - warns about invalid keys from Default Se
]);
});
/** Parses `contents` as a configuration without validating it. */
function parseUnvalidatedConfig(contents: string): dbConfig.UserConfig {
return dbConfig.parseUserConfig(
getRunnerLogger(true),
"test",
contents,
false,
);
}
test("matchesDefaultSetupConfigSchema - returns true for configurations that only use Default Setup properties", (t) => {
for (const contents of [
[
@@ -637,7 +647,12 @@ test("matchesDefaultSetupConfigSchema - returns true for configurations that onl
"threat-models: [ local ]",
"{}",
]) {
t.true(dbConfig.matchesDefaultSetupConfigSchema(contents), contents);
t.true(
dbConfig.matchesDefaultSetupConfigSchema(
parseUnvalidatedConfig(contents),
),
contents,
);
}
});
@@ -647,7 +662,12 @@ test("matchesDefaultSetupConfigSchema - returns false for configurations that us
"paths-ignore: [ tests ]",
"default-setup: { org: { model-packs: [], queries: [] } }",
]) {
t.false(dbConfig.matchesDefaultSetupConfigSchema(contents), contents);
t.false(
dbConfig.matchesDefaultSetupConfigSchema(
parseUnvalidatedConfig(contents),
),
contents,
);
}
});
@@ -656,12 +676,22 @@ test("matchesDefaultSetupConfigSchema - returns false for invalid Default Setup
"threat-models: local",
"default-setup: { org: { model-packs: [ 1 ] } }",
]) {
t.false(dbConfig.matchesDefaultSetupConfigSchema(contents), contents);
t.false(
dbConfig.matchesDefaultSetupConfigSchema(
parseUnvalidatedConfig(contents),
),
contents,
);
}
});
test("matchesDefaultSetupConfigSchema - returns false for contents that aren't a YAML object", (t) => {
for (const contents of ["threat-models: [", "- threat-models", "local", ""]) {
t.false(dbConfig.matchesDefaultSetupConfigSchema(contents), contents);
test("matchesDefaultSetupConfigSchema - returns false for configurations that aren't mappings", (t) => {
for (const contents of ["- threat-models", "local", "null"]) {
t.false(
dbConfig.matchesDefaultSetupConfigSchema(
parseUnvalidatedConfig(contents),
),
contents,
);
}
});

View File

@@ -106,24 +106,16 @@ function checkDefaultSetupConfig(
}
/**
* Returns whether `contents` is a YAML mapping that only sets the properties that Default Setup
* uses, which are threat models and model packs, to valid values. Returns `false` otherwise,
* including if `contents` isn't valid YAML.
* Returns whether `config` is a mapping that only sets the properties that Default Setup sets in
* the `config` input, to valid values.
*/
export function matchesDefaultSetupConfigSchema(contents: string): boolean {
let config: unknown;
try {
config = yaml.load(contents);
} catch (error) {
if (error instanceof yaml.YAMLException) {
return false;
}
throw error;
}
export function matchesDefaultSetupConfigSchema(config: UserConfig): boolean {
// Unless validation is enabled, `parseUserConfig` doesn't check that the YAML is a mapping.
if (!json.isObject(config)) {
return false;
}
const result = checkDefaultSetupConfig(config);
const result = checkDefaultSetupConfig(config as json.UnvalidatedObject<any>);
// `valid` doesn't account for unknown properties.
return result.valid && result.unknownKeys.length === 0;
}