feat(config): simplify required headscale config

This commit is contained in:
Aarnav Tale
2026-06-22 15:40:47 -04:00
parent dc32427cff
commit 10055541cc
10 changed files with 395 additions and 310 deletions
+84 -1
View File
@@ -18,7 +18,7 @@ describe("Headscale config loader", () => {
await rm(dir, { recursive: true, force: true });
});
test("tolerates unknown and version-specific keys while reading known defaults", async () => {
test("tolerates unknown Headscale keys while reading known defaults", async () => {
const path = join(dir, "config.yaml");
await writeFile(
path,
@@ -44,6 +44,42 @@ describe("Headscale config loader", () => {
});
});
test("falls back for invalid consumed values without rejecting the whole config", async () => {
const path = join(dir, "config.yaml");
await writeFile(
path,
[
"server_url: http://localhost:8080",
"dns:",
" magic_dns: maybe",
" base_domain: 1234",
" override_local_dns: nope",
" nameservers:",
" global: 1.1.1.1",
" split:",
" example.com: 1.1.1.1",
" search_domains: example.com",
"oidc:",
" issuer: https://issuer.example.com",
" allowed_domains: example.com",
].join("\n"),
);
const config = await loadHeadscaleConfig(path);
expect(config.readable()).toBe(true);
expect(config.getDNSConfig()).toMatchObject({
magicDns: true,
baseDomain: "",
nameservers: [],
splitDns: {},
searchDomains: [],
overrideDns: true,
});
expect(config.getOIDCConfig()).toMatchObject({
allowedDomains: [],
});
});
test("patches only requested paths and does not write effective defaults", async () => {
const path = join(dir, "config.yaml");
await writeFile(
@@ -67,6 +103,53 @@ describe("Headscale config loader", () => {
});
});
test("patches quoted split DNS domains", async () => {
const path = join(dir, "config.yaml");
await writeFile(
path,
["server_url: http://localhost:8080", "dns:", " nameservers:", " split: {}"].join("\n"),
);
const config = await loadHeadscaleConfig(path);
await config.patch([{ path: 'dns.nameservers.split."corp.example.com"', value: ["1.1.1.1"] }]);
const written = parse(await readFile(path, "utf8"));
expect(written.dns.nameservers.split).toEqual({
"corp.example.com": ["1.1.1.1"],
});
});
test("prefers extra records JSON over inline YAML records", async () => {
const path = join(dir, "config.yaml");
const recordsPath = join(dir, "extra-records.json");
await writeFile(recordsPath, JSON.stringify([{ name: "json", type: "A", value: "1.1.1.1" }]));
await writeFile(
path,
[
"server_url: http://localhost:8080",
"dns:",
" extra_records_path: " + recordsPath,
" extra_records:",
" - name: yaml",
" type: A",
" value: 2.2.2.2",
].join("\n"),
);
const config = await loadHeadscaleConfig(path);
expect(config.dnsRecords()).toEqual([{ name: "json", type: "A", value: "1.1.1.1" }]);
await config.addDNS({ name: "new", type: "A", value: "3.3.3.3" });
expect(JSON.parse(await readFile(recordsPath, "utf8"))).toEqual([
{ name: "json", type: "A", value: "1.1.1.1" },
{ name: "new", type: "A", value: "3.3.3.3" },
]);
expect(parse(await readFile(path, "utf8")).dns.extra_records).toEqual([
{ name: "yaml", type: "A", value: "2.2.2.2" },
]);
});
test("reads OIDC restrictions as empty arrays when unset", async () => {
const path = join(dir, "config.yaml");
await writeFile(