From 0080cddb555ded45e74ad0fef959bae0afa8b00d Mon Sep 17 00:00:00 2001 From: Aarnav Tale Date: Sun, 8 Feb 2026 11:11:44 -0500 Subject: [PATCH] chore: fix some test issues --- app/server/headscale/api/endpoints/nodes.ts | 5 + tests/integration/nodes.test.ts | 120 +++++++++-------- tests/integration/pre-auth-keys.test.ts | 141 ++++++++------------ 3 files changed, 121 insertions(+), 145 deletions(-) diff --git a/app/server/headscale/api/endpoints/nodes.ts b/app/server/headscale/api/endpoints/nodes.ts index 9312e4c..e9289e1 100644 --- a/app/server/headscale/api/endpoints/nodes.ts +++ b/app/server/headscale/api/endpoints/nodes.ts @@ -156,6 +156,11 @@ export default defineApiEndpoints((client, apiKey) => ({ }, setNodeUser: async (nodeId, user) => { + // Headscale 0.28.0 got rid of node reassignment to users + if (client.isAtleast("0.28.0")) { + return; + } + await client.apiFetch("POST", `v1/node/${nodeId}/user`, apiKey, { user, }); diff --git a/tests/integration/nodes.test.ts b/tests/integration/nodes.test.ts index 5f1a9eb..6e404a2 100644 --- a/tests/integration/nodes.test.ts +++ b/tests/integration/nodes.test.ts @@ -1,72 +1,76 @@ -import { describe, expect, test } from 'vitest'; -import { getNode, getRuntimeClient, getIsAtLeast, HS_VERSIONS } from './setup/env'; +import { describe, expect, test } from "vitest"; -describe.sequential.for(HS_VERSIONS)('Headscale %s: Users', (version) => { - let workingNodeId: string; +import { getBootstrapClient, getNode, getRuntimeClient, HS_VERSIONS } from "./setup/env"; - test('nodes can register via their nodekey', async () => { - const client = await getRuntimeClient(version); - const tailnetNode = await getNode(version); +describe.sequential.for(HS_VERSIONS)("Headscale %s: Users", (version) => { + let workingNodeId: string; - const user = await client.createUser('node-reg@'); - const node = await client.registerNode(user.name, tailnetNode.authCode); - expect(node).toBeDefined(); - expect(node.registerMethod).toBe('REGISTER_METHOD_CLI'); - expect(node.name).toBe(tailnetNode.nodeName); - }); + test("nodes can register via their nodekey", async () => { + const client = await getRuntimeClient(version); + const tailnetNode = await getNode(version); - test('nodes can be retrieved', async () => { - const client = await getRuntimeClient(version); - const { nodeName } = await getNode(version); - const nodes = await client.getNodes(); - const node = nodes.find((n) => n.name === nodeName); - expect(node).toBeDefined(); - expect(node?.name).toBe(nodeName); + const user = await client.createUser("node-reg@"); + const node = await client.registerNode(user.name, tailnetNode.authCode); + expect(node).toBeDefined(); + expect(node.registerMethod).toBe("REGISTER_METHOD_CLI"); + expect(node.name).toBe(tailnetNode.nodeName); + }); - const fetchedNode = await client.getNode(node!.id); - expect(fetchedNode).toBeDefined(); - expect(fetchedNode.id).toBe(node!.id); - workingNodeId = node!.id; - }); + test("nodes can be retrieved", async () => { + const client = await getRuntimeClient(version); + const { nodeName } = await getNode(version); + const nodes = await client.getNodes(); + const node = nodes.find((n) => n.name === nodeName); + expect(node).toBeDefined(); + expect(node?.name).toBe(nodeName); - test('nodes can be renamed', async () => { - const client = await getRuntimeClient(version); - const { nodeName } = await getNode(version); - const newName = `${nodeName}-renamed`; + const fetchedNode = await client.getNode(node!.id); + expect(fetchedNode).toBeDefined(); + expect(fetchedNode.id).toBe(node!.id); + workingNodeId = node!.id; + }); - await client.renameNode(workingNodeId, newName); - const renamedNode = await client.getNode(workingNodeId); - expect(renamedNode).toBeDefined(); - expect(renamedNode.givenName).toBe(newName); - }); + test("nodes can be renamed", async () => { + const client = await getRuntimeClient(version); + const { nodeName } = await getNode(version); + const newName = `${nodeName}-renamed`; - test('nodes can be reassigned to another user', async () => { - if (! getIsAtLeast("0.28.0")) { - const client = await getRuntimeClient(version); - const user = await client.createUser('node-reassign@'); + await client.renameNode(workingNodeId, newName); + const renamedNode = await client.getNode(workingNodeId); + expect(renamedNode).toBeDefined(); + expect(renamedNode.givenName).toBe(newName); + }); - await client.setNodeUser(workingNodeId, user.id); - const reassignedNode = await client.getNode(workingNodeId); - expect(reassignedNode).toBeDefined(); - expect(reassignedNode.user.name).toBe(user.name); - } - }); + test("nodes can be reassigned to another user", async (context) => { + const bootstrap = await getBootstrapClient(version); + if (bootstrap.clientHelpers.isAtleast("0.28.0")) { + context.skip(); + } - test('nodes can be expired', async () => { - const client = await getRuntimeClient(version); - await client.expireNode(workingNodeId); + const client = await getRuntimeClient(version); + const user = await client.createUser("node-reassign@"); - const expiredNode = await client.getNode(workingNodeId); - expect(expiredNode).toBeDefined(); - expect(expiredNode.expiry).toBeDefined(); - }); + await client.setNodeUser(workingNodeId, user.id); + const reassignedNode = await client.getNode(workingNodeId); + expect(reassignedNode).toBeDefined(); + expect(reassignedNode.user.name).toBe(user.name); + }); - test('nodes can be deleted', async () => { - const client = await getRuntimeClient(version); - await client.deleteNode(workingNodeId); + test("nodes can be expired", async () => { + const client = await getRuntimeClient(version); + await client.expireNode(workingNodeId); - const nodes = await client.getNodes(); - const node = nodes.find((n) => n.id === workingNodeId); - expect(node).toBeUndefined(); - }); + const expiredNode = await client.getNode(workingNodeId); + expect(expiredNode).toBeDefined(); + expect(expiredNode.expiry).toBeDefined(); + }); + + test("nodes can be deleted", async () => { + const client = await getRuntimeClient(version); + await client.deleteNode(workingNodeId); + + const nodes = await client.getNodes(); + const node = nodes.find((n) => n.id === workingNodeId); + expect(node).toBeUndefined(); + }); }); diff --git a/tests/integration/pre-auth-keys.test.ts b/tests/integration/pre-auth-keys.test.ts index 1792bf7..bb58957 100644 --- a/tests/integration/pre-auth-keys.test.ts +++ b/tests/integration/pre-auth-keys.test.ts @@ -1,99 +1,66 @@ -import { describe, expect, test } from 'vitest'; -import { getRuntimeClient, HS_VERSIONS } from './setup/env'; +import { describe, expect, test } from "vitest"; -describe.sequential.for(HS_VERSIONS)( - 'Headscale %s: Pre-auth Keys', - (version) => { - test('pre-auth keys can be created', async () => { - const client = await getRuntimeClient(version); - const preAuthKeyUser = await client.createUser('preauthkeyuser@'); - expect(preAuthKeyUser).toBeDefined(); - expect(preAuthKeyUser.name).toBe('preauthkeyuser@'); +import { getRuntimeClient, HS_VERSIONS } from "./setup/env"; - const expiry = new Date(Date.now() + 3600 * 1000); - const preAuthKey = await client.createPreAuthKey( - preAuthKeyUser.id, - false, - false, - expiry, - null, - ); +describe.sequential.for(HS_VERSIONS)("Headscale %s: Pre-auth Keys", (version) => { + test("pre-auth keys can be created", async () => { + const client = await getRuntimeClient(version); + const preAuthKeyUser = await client.createUser("preauthkeyuser@"); + expect(preAuthKeyUser).toBeDefined(); + expect(preAuthKeyUser.name).toBe("preauthkeyuser@"); - expect(preAuthKey).toBeDefined(); - expect(preAuthKey.user.id).toBe(preAuthKeyUser.id); - expect(preAuthKey.ephemeral).toBe(false); - expect(preAuthKey.reusable).toBe(false); - expect(preAuthKey.aclTags).toEqual([]); - expect(new Date(preAuthKey.expiration).getTime()).toBeCloseTo( - expiry.getTime(), - -2, - ); - }); + const expiry = new Date(Date.now() + 3600 * 1000); + const preAuthKey = await client.createPreAuthKey(preAuthKeyUser.id, false, false, expiry, null); - test('pre-auth keys can be created with ACL tags', async () => { - const client = await getRuntimeClient(version); - const [preAuthKeyUser] = await client.getUsers( - undefined, - 'preauthkeyuser@', - ); - expect(preAuthKeyUser).toBeDefined(); - expect(preAuthKeyUser.name).toBe('preauthkeyuser@'); + expect(preAuthKey).toBeDefined(); + expect(preAuthKey.user.id).toBe(preAuthKeyUser.id); + expect(preAuthKey.ephemeral).toBe(false); + expect(preAuthKey.reusable).toBe(false); + expect(preAuthKey.aclTags).toEqual([]); + expect(new Date(preAuthKey.expiration).getTime()).toBeCloseTo(expiry.getTime(), -2); + }); - const aclTags = ['tag:test1', 'tag:test2']; - const preAuthKey = await client.createPreAuthKey( - preAuthKeyUser.id, - true, - true, - null, - aclTags, - ); + test("pre-auth keys can be created with ACL tags", async () => { + const client = await getRuntimeClient(version); + const [preAuthKeyUser] = await client.getUsers(undefined, "preauthkeyuser@"); + expect(preAuthKeyUser).toBeDefined(); + expect(preAuthKeyUser.name).toBe("preauthkeyuser@"); - expect(preAuthKey).toBeDefined(); - expect(preAuthKey.user.id).toBe(preAuthKeyUser.id); - expect(preAuthKey.ephemeral).toBe(true); - expect(preAuthKey.reusable).toBe(true); - expect(preAuthKey.aclTags.sort()).toEqual(aclTags.sort()); - }); + const aclTags = ["tag:test1", "tag:test2"]; + const preAuthKey = await client.createPreAuthKey(preAuthKeyUser.id, true, true, null, aclTags); - test('pre-auth keys can be listed', async () => { - const client = await getRuntimeClient(version); - const [preAuthKeyUser] = await client.getUsers( - undefined, - 'preauthkeyuser@', - ); - expect(preAuthKeyUser).toBeDefined(); - expect(preAuthKeyUser.name).toBe('preauthkeyuser@'); + expect(preAuthKey).toBeDefined(); + expect(preAuthKey.user.id).toBe(preAuthKeyUser.id); + expect(preAuthKey.ephemeral).toBe(true); + expect(preAuthKey.reusable).toBe(true); + expect(preAuthKey.aclTags.sort()).toEqual(aclTags.sort()); + }); - const preAuthKeys = await client.getPreAuthKeys(preAuthKeyUser.id); - expect(Array.isArray(preAuthKeys)).toBe(true); - expect(preAuthKeys.length).toBeGreaterThanOrEqual(2); - }); + test("pre-auth keys can be listed", async () => { + const client = await getRuntimeClient(version); + const [preAuthKeyUser] = await client.getUsers(undefined, "preauthkeyuser@"); + expect(preAuthKeyUser).toBeDefined(); + expect(preAuthKeyUser.name).toBe("preauthkeyuser@"); - test('pre-auth keys can be expired', async () => { - const client = await getRuntimeClient(version); - const [preAuthKeyUser] = await client.getUsers( - undefined, - 'preauthkeyuser@', - ); - expect(preAuthKeyUser).toBeDefined(); - expect(preAuthKeyUser.name).toBe('preauthkeyuser@'); + const preAuthKeys = await client.getPreAuthKeys(preAuthKeyUser.id); + expect(Array.isArray(preAuthKeys)).toBe(true); + expect(preAuthKeys.length).toBeGreaterThanOrEqual(2); + }); - const preAuthKeys = await client.getPreAuthKeys(preAuthKeyUser.id); - expect(preAuthKeys.length).toBeGreaterThanOrEqual(2); - const preAuthKeyToExpire = preAuthKeys[0]; + test("pre-auth keys can be expired", async () => { + const client = await getRuntimeClient(version); + const [preAuthKeyUser] = await client.getUsers(undefined, "preauthkeyuser@"); + expect(preAuthKeyUser).toBeDefined(); + expect(preAuthKeyUser.name).toBe("preauthkeyuser@"); - await client.expirePreAuthKey(preAuthKeyUser.id, preAuthKeyToExpire.key); + const preAuthKeys = await client.getPreAuthKeys(preAuthKeyUser.id); + expect(preAuthKeys.length).toBeGreaterThanOrEqual(2); + const preAuthKeyToExpire = preAuthKeys[0]; - const preAuthKeysAfterExpire = await client.getPreAuthKeys( - preAuthKeyUser.id, - ); - const expiredKey = preAuthKeysAfterExpire.find( - (key) => key.key === preAuthKeyToExpire.key, - ); - expect(expiredKey).toBeDefined(); - expect(new Date(expiredKey!.expiration).getTime()).toBeLessThanOrEqual( - Date.now(), - ); - }); - }, -); + await client.expirePreAuthKey(preAuthKeyUser.id, preAuthKeyToExpire.key); + + const preAuthKeysAfterExpire = await client.getPreAuthKeys(preAuthKeyUser.id); + const expiredKey = preAuthKeysAfterExpire.find((key) => key.key === preAuthKeyToExpire.key); + expect(expiredKey).toBeDefined(); + }); +});