fix: harden workspace registry config validation
This commit is contained in:
+29
-3
@@ -41,6 +41,33 @@ function absoluteRegistryPath(value: string, label: string): string {
|
|||||||
return pathValue;
|
return pathValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function refSafeGitBranch(value: string): string {
|
||||||
|
const branch = requiredRegistryValue(value, "branch");
|
||||||
|
if (
|
||||||
|
branch === "@"
|
||||||
|
|| branch.startsWith("-")
|
||||||
|
|| branch.startsWith("/")
|
||||||
|
|| branch.endsWith("/")
|
||||||
|
|| branch.endsWith(".")
|
||||||
|
|| branch.includes("..")
|
||||||
|
|| branch.includes("@{")
|
||||||
|
|| branch.includes("//")
|
||||||
|
|| branch.split("/").some((component) => component.startsWith(".") || component.endsWith(".lock"))
|
||||||
|
|| /[\p{Cc} ~^:?*\[\\]/u.test(branch)
|
||||||
|
) {
|
||||||
|
throw new Error("workspace registry branch configuration is invalid");
|
||||||
|
}
|
||||||
|
return branch;
|
||||||
|
}
|
||||||
|
|
||||||
|
function safeInstallationId(value: string): string {
|
||||||
|
const installationId = requiredRegistryValue(value, "installation ID");
|
||||||
|
if (/\p{Cc}/u.test(installationId)) {
|
||||||
|
throw new Error("workspace registry installation ID configuration is invalid");
|
||||||
|
}
|
||||||
|
return installationId;
|
||||||
|
}
|
||||||
|
|
||||||
function positiveImportLimit(value: string | undefined, fallback: number): number {
|
function positiveImportLimit(value: string | undefined, fallback: number): number {
|
||||||
const limit = Number(value ?? fallback);
|
const limit = Number(value ?? fallback);
|
||||||
if (!Number.isSafeInteger(limit) || limit <= 0) {
|
if (!Number.isSafeInteger(limit) || limit <= 0) {
|
||||||
@@ -119,10 +146,9 @@ export function loadConfig(env: Record<string, string | undefined>): AppConfig {
|
|||||||
env.THT_WORKSPACE_REGISTRY_ROOT ?? "/data/workspace-registry",
|
env.THT_WORKSPACE_REGISTRY_ROOT ?? "/data/workspace-registry",
|
||||||
"root",
|
"root",
|
||||||
);
|
);
|
||||||
const registryBranch = requiredRegistryValue(env.THT_WORKSPACE_GIT_BRANCH ?? "main", "branch");
|
const registryBranch = refSafeGitBranch(env.THT_WORKSPACE_GIT_BRANCH ?? "main");
|
||||||
const installationId = requiredRegistryValue(
|
const installationId = safeInstallationId(
|
||||||
env.THT_WORKSPACE_INSTALLATION_ID ?? "local",
|
env.THT_WORKSPACE_INSTALLATION_ID ?? "local",
|
||||||
"installation ID",
|
|
||||||
);
|
);
|
||||||
const remoteUrl = env.THT_WORKSPACE_GIT_REMOTE === undefined
|
const remoteUrl = env.THT_WORKSPACE_GIT_REMOTE === undefined
|
||||||
? undefined
|
? undefined
|
||||||
|
|||||||
@@ -46,3 +46,19 @@ test("rejects unsafe registry branch, installation ID, and secret roots", () =>
|
|||||||
expect(() => loadConfig({ THT_WORKSPACE_SECRET_ROOTS: "/run/secrets,relative" }))
|
expect(() => loadConfig({ THT_WORKSPACE_SECRET_ROOTS: "/run/secrets,relative" }))
|
||||||
.toThrow(/secret/i);
|
.toThrow(/secret/i);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("rejects ref-unsafe Git branches", () => {
|
||||||
|
for (const branch of ["topic..bad", "--upload-pack=/tmp/x", "release/.hidden", "release.lock"]) {
|
||||||
|
expect(() => loadConfig({ THT_WORKSPACE_GIT_BRANCH: branch })).toThrow(/branch/i);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("rejects control characters in installation IDs", () => {
|
||||||
|
for (const codePoint of [...Array(0x20).keys(), ...Array(0x21).keys()].map((code, index) => (
|
||||||
|
index < 0x20 ? code : code + 0x7f
|
||||||
|
))) {
|
||||||
|
expect(() => loadConfig({
|
||||||
|
THT_WORKSPACE_INSTALLATION_ID: `server-psd-1${String.fromCodePoint(codePoint)}`,
|
||||||
|
})).toThrow(/installation/i);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user