refactor(tests): move backend tests into src/backend/tests mirror tree

Backend *.test.ts files (and the test-support harness) no longer sit next
to source files; they live under src/backend/tests/ mirroring the source
layout. Imports rewritten accordingly; CLAUDE.md convention updated.
This commit is contained in:
LukeGus
2026-07-16 04:31:29 -05:00
parent 8b6037b7ff
commit 7f43932429
89 changed files with 200 additions and 160 deletions
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { AlertRepository } from "./alert-repository.js";
import { AlertRepository } from "../../../database/repositories/alert-repository.js";
describe("AlertRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { ApiKeyRepository } from "./api-key-repository.js";
import { ApiKeyRepository } from "../../../database/repositories/api-key-repository.js";
describe("ApiKeyRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { AuditLogRepository } from "./audit-log-repository.js";
import { AuditLogRepository } from "../../../database/repositories/audit-log-repository.js";
describe("AuditLogRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { C2sTunnelPresetRepository } from "./c2s-tunnel-preset-repository.js";
import { C2sTunnelPresetRepository } from "../../../database/repositories/c2s-tunnel-preset-repository.js";
describe("C2sTunnelPresetRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { CommandHistoryRepository } from "./command-history-repository.js";
import { CommandHistoryRepository } from "../../../database/repositories/command-history-repository.js";
describe("CommandHistoryRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { DashboardServiceLinkRepository } from "./dashboard-service-link-repository.js";
import { DashboardServiceLinkRepository } from "../../../database/repositories/dashboard-service-link-repository.js";
describe("DashboardServiceLinkRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { DismissedAlertRepository } from "./dismissed-alert-repository.js";
import { DismissedAlertRepository } from "../../../database/repositories/dismissed-alert-repository.js";
describe("DismissedAlertRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import crypto from "crypto";
import { describe, expect, it } from "vitest";
import { FieldEncryptionBoundary } from "./field-encryption-boundary.js";
import { FieldEncryptionBoundary } from "../../../database/repositories/field-encryption-boundary.js";
describe("FieldEncryptionBoundary", () => {
const userDataKey = crypto.randomBytes(32);
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { FileManagerBookmarkRepository } from "./file-manager-bookmark-repository.js";
import { FileManagerBookmarkRepository } from "../../../database/repositories/file-manager-bookmark-repository.js";
describe("FileManagerBookmarkRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { HomepageItemRepository } from "./homepage-item-repository.js";
import { HomepageItemRepository } from "../../../database/repositories/homepage-item-repository.js";
describe("HomepageItemRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { HomepageLayoutRepository } from "./homepage-layout-repository.js";
import { HomepageLayoutRepository } from "../../../database/repositories/homepage-layout-repository.js";
describe("HomepageLayoutRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,8 +1,8 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { CredentialRepository } from "./credential-repository.js";
import { HostRepository } from "./host-repository.js";
import { DataCrypto } from "../../utils/data-crypto.js";
import { CredentialRepository } from "../../../database/repositories/credential-repository.js";
import { HostRepository } from "../../../database/repositories/host-repository.js";
import { DataCrypto } from "../../../utils/data-crypto.js";
describe("HostRepository and CredentialRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { HostFolderRepository } from "./host-folder-repository.js";
import { HostFolderRepository } from "../../../database/repositories/host-folder-repository.js";
describe("HostFolderRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { HostHealthRepository } from "./host-health-repository.js";
import { HostHealthRepository } from "../../../database/repositories/host-health-repository.js";
describe("HostHealthRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { HostMetricsHistoryRepository } from "./host-metrics-history-repository.js";
import { HostMetricsHistoryRepository } from "../../../database/repositories/host-metrics-history-repository.js";
describe("HostMetricsHistoryRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { HostMetricsPreferenceRepository } from "./host-metrics-preference-repository.js";
import { HostMetricsPreferenceRepository } from "../../../database/repositories/host-metrics-preference-repository.js";
describe("HostMetricsPreferenceRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,9 +1,9 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { DataCrypto } from "../../utils/data-crypto.js";
import { HostResolutionRepository } from "./host-resolution-repository.js";
import { DataCrypto } from "../../../utils/data-crypto.js";
import { HostResolutionRepository } from "../../../database/repositories/host-resolution-repository.js";
vi.mock("../../utils/data-crypto.js", () => ({
vi.mock("../../../utils/data-crypto.js", () => ({
DataCrypto: {
getUserDataKey: vi.fn(),
decryptRecord: vi.fn((_tableName, record) => record),
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { NetworkTopologyRepository } from "./network-topology-repository.js";
import { NetworkTopologyRepository } from "../../../database/repositories/network-topology-repository.js";
describe("NetworkTopologyRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { OpenTabRepository } from "./open-tab-repository.js";
import { OpenTabRepository } from "../../../database/repositories/open-tab-repository.js";
describe("OpenTabRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { OpksshTokenRepository } from "./opkssh-token-repository.js";
import { OpksshTokenRepository } from "../../../database/repositories/opkssh-token-repository.js";
describe("OpksshTokenRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { RbacAccessRepository } from "./rbac-access-repository.js";
import { RbacAccessRepository } from "../../../database/repositories/rbac-access-repository.js";
describe("RbacAccessRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { RecentActivityRepository } from "./recent-activity-repository.js";
import { RecentActivityRepository } from "../../../database/repositories/recent-activity-repository.js";
describe("RecentActivityRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { RoleRepository } from "./role-repository.js";
import { RoleRepository } from "../../../database/repositories/role-repository.js";
describe("RoleRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { SessionRecordingRepository } from "./session-recording-repository.js";
import { SessionRecordingRepository } from "../../../database/repositories/session-recording-repository.js";
describe("SessionRecordingRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { SettingsRepository } from "./settings-repository.js";
import { SettingsRepository } from "../../../database/repositories/settings-repository.js";
describe("SettingsRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { SharedCredentialRepository } from "./shared-credential-repository.js";
import { SharedCredentialRepository } from "../../../database/repositories/shared-credential-repository.js";
describe("SharedCredentialRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { SnippetRepository } from "./snippet-repository.js";
import { SnippetRepository } from "../../../database/repositories/snippet-repository.js";
describe("SnippetRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { SshCredentialUsageRepository } from "./ssh-credential-usage-repository.js";
import { SshCredentialUsageRepository } from "../../../database/repositories/ssh-credential-usage-repository.js";
describe("SshCredentialUsageRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { SsoProviderRepository } from "./sso-provider-repository.js";
import { SsoProviderRepository } from "../../../database/repositories/sso-provider-repository.js";
describe("SsoProviderRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,7 +1,7 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { DataCrypto } from "../../utils/data-crypto.js";
import { TermixIdentityCaRepository } from "./termix-identity-ca-repository.js";
import { DataCrypto } from "../../../utils/data-crypto.js";
import { TermixIdentityCaRepository } from "../../../database/repositories/termix-identity-ca-repository.js";
describe("TermixIdentityCaRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { TermixIdentityRepository } from "./termix-identity-repository.js";
import { TermixIdentityRepository } from "../../../database/repositories/termix-identity-repository.js";
describe("TermixIdentityRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,7 +1,7 @@
import Database from "better-sqlite3";
import { drizzle } from "drizzle-orm/better-sqlite3";
import * as schema from "../db/schema.js";
import type { DatabaseContext } from "./database-context.js";
import * as schema from "../../../database/db/schema.js";
import type { DatabaseContext } from "../../../database/repositories/database-context.js";
export class TestSqliteDatabase {
private sqlite: Database.Database | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { TmuxSessionTagRepository } from "./tmux-session-tag-repository.js";
import { TmuxSessionTagRepository } from "../../../database/repositories/tmux-session-tag-repository.js";
describe("TmuxSessionTagRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { TransferRecentRepository } from "./transfer-recent-repository.js";
import { TransferRecentRepository } from "../../../database/repositories/transfer-recent-repository.js";
describe("TransferRecentRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { TrustedDeviceRepository } from "./trusted-device-repository.js";
import { TrustedDeviceRepository } from "../../../database/repositories/trusted-device-repository.js";
describe("TrustedDeviceRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { UserDataExportRepository } from "./user-data-export-repository.js";
import { UserDataExportRepository } from "../../../database/repositories/user-data-export-repository.js";
describe("UserDataExportRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { UserPreferenceRepository } from "./user-preference-repository.js";
import { UserPreferenceRepository } from "../../../database/repositories/user-preference-repository.js";
describe("UserPreferenceRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,7 +1,7 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { SessionRepository } from "./session-repository.js";
import { UserRepository } from "./user-repository.js";
import { SessionRepository } from "../../../database/repositories/session-repository.js";
import { UserRepository } from "../../../database/repositories/user-repository.js";
describe("UserRepository and SessionRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { VaultProfileRepository } from "./vault-profile-repository.js";
import { VaultProfileRepository } from "../../../database/repositories/vault-profile-repository.js";
describe("VaultProfileRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it } from "vitest";
import { TestSqliteDatabase } from "./test-support.js";
import { VaultTokenRepository } from "./vault-token-repository.js";
import { VaultTokenRepository } from "../../../database/repositories/vault-token-repository.js";
describe("VaultTokenRepository", () => {
let adapter: TestSqliteDatabase | null = null;
@@ -1,5 +1,5 @@
import { describe, it, expect } from "vitest";
import { parseSSHConfig } from "./host-bulk-routes.js";
import { parseSSHConfig } from "../../../database/routes/host-bulk-routes.js";
describe("parseSSHConfig", () => {
it("parses a basic Host block", () => {
@@ -4,14 +4,14 @@ const mocks = vi.hoisted(() => ({
isUserDataUnlocked: vi.fn(),
}));
vi.mock("../../utils/simple-db-ops.js", () => ({
vi.mock("../../../utils/simple-db-ops.js", () => ({
SimpleDBOps: {
isUserDataUnlocked: mocks.isUserDataUnlocked,
},
}));
const { applyHostEnrollmentDefaults, requireHostEnrollmentAccessForPath } =
await import("./host-enrollment-auth.js");
await import("../../../database/routes/host-enrollment-auth.js");
function response() {
const json = vi.fn();
@@ -6,7 +6,7 @@ import {
renameFolderPath,
stripSensitiveFields,
transformHostResponse,
} from "./host-normalizers.js";
} from "../../../database/routes/host-normalizers.js";
describe("isNonEmptyString", () => {
it("accepts non-blank strings", () => {
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
import {
isValidServiceLinkUrl,
normalizeServiceLinkUrl,
} from "./service-link-url.js";
} from "../../../database/routes/service-link-url.js";
describe("service link URL handling", () => {
it("keeps explicit http and https URLs", () => {
@@ -6,7 +6,7 @@ const mockSelect = vi.fn();
const mockDelete = vi.fn();
const mockInsert = vi.fn();
vi.mock("../db/index.js", () => ({
vi.mock("../../../database/db/index.js", () => ({
db: {
select: mockSelect,
delete: mockDelete,
@@ -14,11 +14,11 @@ vi.mock("../db/index.js", () => ({
},
}));
vi.mock("../../utils/logger.js", () => ({
vi.mock("../../../utils/logger.js", () => ({
apiLogger: { error: vi.fn(), warn: vi.fn(), info: vi.fn(), success: vi.fn() },
}));
vi.mock("../../utils/auth-manager.js", () => ({
vi.mock("../../../utils/auth-manager.js", () => ({
AuthManager: {
getInstance: () => ({
createAuthMiddleware:
@@ -92,7 +92,8 @@ describe("session-log-routes", () => {
mockStat.mockReturnValue({ size: 4096 });
// Directly call the route handler extracted from the module
const { default: router } = await import("./session-log-routes.js");
const { default: router } =
await import("../../../database/routes/session-log-routes.js");
expect(router).toBeDefined();
});
});
@@ -8,7 +8,7 @@ import {
generateCa,
signUserCertificate,
ed25519RawFromLine,
} from "./ssh-certificate.js";
} from "../../../database/routes/ssh-certificate.js";
function publicKeyObjectFromLine(line: string) {
const raw = ed25519RawFromLine(line);
@@ -4,7 +4,7 @@ import {
parsePublicKey,
matchesAlgoFilter,
MAX_PUBLIC_KEY_LENGTH,
} from "./termix-id-keys.js";
} from "../../../database/routes/termix-id-keys.js";
// Build a valid OpenSSH public-key line for a given type by encoding a wire
// blob whose first string field equals the type (what parsePublicKey checks).
@@ -5,7 +5,7 @@ const mockUpdate = vi.fn();
const mockInsert = vi.fn();
const mockDelete = vi.fn();
vi.mock("../db/index.js", () => ({
vi.mock("../../../database/db/index.js", () => ({
db: {
select: mockSelect,
update: mockUpdate,
@@ -14,7 +14,7 @@ vi.mock("../db/index.js", () => ({
},
}));
vi.mock("../../utils/logger.js", () => ({
vi.mock("../../../utils/logger.js", () => ({
apiLogger: { error: vi.fn(), warn: vi.fn(), info: vi.fn(), success: vi.fn() },
authLogger: {
error: vi.fn(),
@@ -24,7 +24,7 @@ vi.mock("../../utils/logger.js", () => ({
},
}));
vi.mock("../../utils/auth-manager.js", () => ({
vi.mock("../../../utils/auth-manager.js", () => ({
AuthManager: {
getInstance: () => ({
createAuthMiddleware:
@@ -40,16 +40,16 @@ vi.mock("../../utils/auth-manager.js", () => ({
},
}));
vi.mock("../../utils/audit-logger.js", () => ({
vi.mock("../../../utils/audit-logger.js", () => ({
logAudit: vi.fn(),
getRequestMeta: vi.fn(() => ({})),
}));
vi.mock("../../utils/data-crypto.js", () => ({
vi.mock("../../../utils/data-crypto.js", () => ({
DataCrypto: { getInstance: () => ({ encrypt: vi.fn(), decrypt: vi.fn() }) },
}));
vi.mock("../repositories/factory.js", () => ({
vi.mock("../../../database/repositories/factory.js", () => ({
createCurrentTermixIdentityCaRepository: vi.fn(() => ({
findPublicByIdentityId: vi.fn(),
findDecryptedByIdentityId: vi.fn(),
@@ -74,7 +74,7 @@ vi.mock("../repositories/factory.js", () => ({
})),
}));
vi.mock("./termix-id-keys.js", () => ({
vi.mock("../../../database/routes/termix-id-keys.js", () => ({
termixIdKeysRouter: { use: vi.fn() },
matchesAlgoFilter: vi.fn(() => true),
}));
@@ -117,7 +117,8 @@ describe("GET /termix-id/linked-credentials", () => {
// First select (getIdentityForUser) returns nothing; second should not be called
mockSelect.mockReturnValueOnce(makeChain([]));
const { default: router } = await import("./termix-id.js");
const { default: router } =
await import("../../../database/routes/termix-id.js");
expect(router).toBeDefined();
expect(router).toBeDefined();
@@ -128,7 +129,8 @@ describe("GET /termix-id/linked-credentials", () => {
.mockReturnValueOnce(makeChain([IDENTITY_ROW])) // identity lookup
.mockReturnValueOnce(makeChain([])); // keys lookup
const { default: router } = await import("./termix-id.js");
const { default: router } =
await import("../../../database/routes/termix-id.js");
expect(router).toBeDefined();
});
@@ -142,7 +144,8 @@ describe("GET /termix-id/linked-credentials", () => {
.mockReturnValueOnce(makeChain([IDENTITY_ROW]))
.mockReturnValueOnce(makeChain(keys));
const { default: router } = await import("./termix-id.js");
const { default: router } =
await import("../../../database/routes/termix-id.js");
expect(router).toBeDefined();
});
@@ -152,7 +155,8 @@ describe("GET /termix-id/linked-credentials", () => {
.mockReturnValueOnce(makeChain([IDENTITY_ROW]))
.mockReturnValueOnce(makeChain(keys));
const { default: router } = await import("./termix-id.js");
const { default: router } =
await import("../../../database/routes/termix-id.js");
expect(router).toBeDefined();
});
});
@@ -1,7 +1,7 @@
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
// user-oidc-utils imports the logger; stub it so importing stays side-effect-free.
vi.mock("../../utils/logger.js", () => ({
vi.mock("../../../utils/logger.js", () => ({
authLogger: {
debug: vi.fn(),
info: vi.fn(),
@@ -16,7 +16,7 @@ const {
getOIDCConfigFromEnv,
extractOidcGroups,
validateLogoutTokenClaims,
} = await import("./user-oidc-utils.js");
} = await import("../../../database/routes/user-oidc-utils.js");
const BACKCHANNEL_LOGOUT_EVENT =
"http://schemas.openid.net/event/backchannel-logout";
@@ -1,5 +1,5 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { AuthManager } from "../../utils/auth-manager.js";
import type { AuthManager } from "../../../utils/auth-manager.js";
const calls = vi.hoisted(() => ({
userUpdates: [] as Array<[string, Record<string, unknown>]>,
@@ -17,7 +17,7 @@ function deletingRepo(label: string) {
});
}
vi.mock("../repositories/factory.js", () => ({
vi.mock("../../../database/repositories/factory.js", () => ({
createCurrentUserRepository: () => ({
update: async (userId: string, update: Record<string, unknown>) => {
calls.userUpdates.push([userId, update]);
@@ -34,7 +34,7 @@ vi.mock("../repositories/factory.js", () => ({
createCurrentCredentialRepository: deletingRepo("credentials"),
}));
vi.mock("../../utils/user-keys.js", () => ({
vi.mock("../../../utils/user-keys.js", () => ({
UserKeyManager: {
getInstance: () => ({
rotateUserDEK: async (userId: string) => {
@@ -45,13 +45,13 @@ vi.mock("../../utils/user-keys.js", () => ({
},
}));
vi.mock("../../utils/crypto-migration/dek-migration.js", () => ({
vi.mock("../../../utils/crypto-migration/dek-migration.js", () => ({
deleteLegacyWraps: async (userId: string) => {
calls.legacyWrapsDeletedFor.push(userId);
},
}));
import { resetUserPassword } from "./user-password-reset-routes.js";
import { resetUserPassword } from "../../../database/routes/user-password-reset-routes.js";
function fakeAuthManager(unlocked: boolean): AuthManager {
return {
@@ -6,13 +6,13 @@ import speakeasy from "speakeasy";
// importing stays inert.
const userRepositoryUpdate = vi.fn().mockResolvedValue(null);
vi.mock("../repositories/factory.js", () => ({
vi.mock("../../../database/repositories/factory.js", () => ({
createCurrentUserRepository: () => ({
update: userRepositoryUpdate,
}),
}));
vi.mock("../../utils/logger.js", () => ({
vi.mock("../../../utils/logger.js", () => ({
authLogger: {
debug: vi.fn(),
info: vi.fn(),
@@ -22,7 +22,8 @@ vi.mock("../../utils/logger.js", () => ({
},
}));
const { verifyTotpReauth } = await import("./user-totp-routes.js");
const { verifyTotpReauth } =
await import("../../../database/routes/user-totp-routes.js");
type AnyUser = Parameters<typeof verifyTotpReauth>[0];
@@ -3,7 +3,7 @@ import {
pickResolvedUsername,
pickResolvedPassword,
expandOidcUsername,
} from "./credential-username.js";
} from "../../hosts/credential-username.js";
describe("pickResolvedUsername", () => {
it("keeps the host username when one is set, even with a credential username", () => {
@@ -63,40 +63,40 @@ describe("expandOidcUsername", () => {
});
it("expands the placeholder with the user's OIDC identifier", async () => {
vi.doMock("../database/repositories/factory.js", () => ({
vi.doMock("../../database/repositories/factory.js", () => ({
createCurrentUserRepository: () => ({
findById: async () => ({ oidcIdentifier: "jdoe" }),
}),
}));
const { expandOidcUsername: expand } =
await import("./credential-username.js");
await import("../../hosts/credential-username.js");
expect(await expand("$oidc.preferred_username", "user-1")).toBe("jdoe");
});
it("leaves the placeholder as-is when the user has no OIDC identifier", async () => {
vi.doMock("../database/repositories/factory.js", () => ({
vi.doMock("../../database/repositories/factory.js", () => ({
createCurrentUserRepository: () => ({
findById: async () => ({ oidcIdentifier: null }),
}),
}));
const { expandOidcUsername: expand } =
await import("./credential-username.js");
await import("../../hosts/credential-username.js");
expect(await expand("$oidc.preferred_username", "user-1")).toBe(
"$oidc.preferred_username",
);
});
it("returns the username unchanged when the DB lookup throws", async () => {
vi.doMock("../database/repositories/factory.js", () => ({
vi.doMock("../../database/repositories/factory.js", () => ({
createCurrentUserRepository: () => {
throw new Error("DB unavailable");
},
}));
const { expandOidcUsername: expand } =
await import("./credential-username.js");
await import("../../hosts/credential-username.js");
expect(await expand("$oidc.preferred_username", "user-1")).toBe(
"$oidc.preferred_username",
);
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { buildDeleteCommand } from "./file-manager-operation-commands.js";
import { buildDeleteCommand } from "../../hosts/file-manager-operation-commands.js";
describe("buildDeleteCommand", () => {
it("builds a PowerShell 5.1 compatible delete command for Windows files", () => {
@@ -6,7 +6,7 @@ import {
getMimeType,
detectBinary,
parseLsDateToTimestamp,
} from "./file-manager-utils.js";
} from "../../hosts/file-manager-utils.js";
describe("isExecutableFile", () => {
it("flags scripts with execute permission", () => {
@@ -1,6 +1,6 @@
import { describe, expect, it, vi } from "vitest";
vi.mock("../../utils/logger.js", () => ({
vi.mock("../../../utils/logger.js", () => ({
guacLogger: {
debug: vi.fn(),
info: vi.fn(),
@@ -10,7 +10,8 @@ vi.mock("../../utils/logger.js", () => ({
},
}));
const { GuacamoleTokenService } = await import("./token-service.js");
const { GuacamoleTokenService } =
await import("../../../hosts/guacamole/token-service.js");
describe("GuacamoleTokenService", () => {
const tokenService = GuacamoleTokenService.getInstance();
@@ -4,8 +4,8 @@ import {
supportsMetrics,
isTcpPingEnabled,
tcpPingThroughJumpHost,
} from "./host-metrics-helpers.js";
import { createConnectionLog } from "./connection-log.js";
} from "../../hosts/host-metrics-helpers.js";
import { createConnectionLog } from "../../hosts/connection-log.js";
describe("supportsMetrics", () => {
it("supports plain ssh hosts", () => {
@@ -5,7 +5,7 @@ import {
isMetricCardId,
isManagerCardId,
METRIC_CARD_IDS,
} from "../../types/host-metrics.js";
} from "../../../types/host-metrics.js";
describe("deriveEnabledWidgets", () => {
it("returns only metric ids, in canonical order, deduped", () => {
@@ -1,5 +1,8 @@
import { describe, expect, it, vi } from "vitest";
import { ConcurrentLimiter, HostPollCache } from "./host-metrics-state.js";
import {
ConcurrentLimiter,
HostPollCache,
} from "../../hosts/host-metrics-state.js";
describe("ConcurrentLimiter", () => {
it("never exceeds max concurrent runners", async () => {
@@ -1,11 +1,14 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
const execCommand = vi.fn();
vi.mock("../widgets/common-utils.js", () => ({
vi.mock("../../../hosts/widgets/common-utils.js", () => ({
execCommand: (...args: unknown[]) => execCommand(...args),
}));
import { execElevated, ElevationError } from "./exec-elevated.js";
import {
execElevated,
ElevationError,
} from "../../../hosts/managers/exec-elevated.js";
import type { Client } from "ssh2";
const fakeClient = {} as Client;
@@ -1,6 +1,9 @@
import { describe, it, expect } from "vitest";
import { buildSudoCommand, shellSingleQuote } from "./exec-elevated.js";
import { parsePlatformProbe } from "./platform.js";
import {
buildSudoCommand,
shellSingleQuote,
} from "../../../hosts/managers/exec-elevated.js";
import { parsePlatformProbe } from "../../../hosts/managers/platform.js";
import {
isValidSystemdUnit,
isValidPid,
@@ -12,32 +15,47 @@ import {
isValidSignal,
isValidServiceAction,
isAllowedPath,
} from "./validation.js";
import { parseServiceList, buildServiceActionCommand } from "./services.js";
import { parseProcessList, buildKillCommand } from "./processes.js";
import { parseDfMounts, parseTopMemory } from "./simple-reads.js";
} from "../../../hosts/managers/validation.js";
import {
parseServiceList,
buildServiceActionCommand,
} from "../../../hosts/managers/services.js";
import {
parseProcessList,
buildKillCommand,
} from "../../../hosts/managers/processes.js";
import {
parseDfMounts,
parseTopMemory,
} from "../../../hosts/managers/simple-reads.js";
import {
parseCrontab,
serializeCrontab,
isValidCronSchedule,
buildApplyCrontabCommand,
} from "./cron.js";
} from "../../../hosts/managers/cron.js";
import {
buildPackageActionCommand,
parseUpgradable,
buildListUpgradableCommand,
} from "./packages.js";
} from "../../../hosts/managers/packages.js";
import {
buildIssueCommand,
buildRenewCommand,
buildRevokeCommand,
isValidCertName,
parseCertbotCertificates,
} from "./ssl.js";
import { buildIptablesRuleCommand, buildNftRuleCommand } from "./firewall.js";
import { parsePasswd, parseSudoers } from "./users.js";
import { buildHealthCheckCommand, parseHealthResult } from "./health.js";
import { buildTailCommand, clampLines } from "./logs.js";
} from "../../../hosts/managers/ssl.js";
import {
buildIptablesRuleCommand,
buildNftRuleCommand,
} from "../../../hosts/managers/firewall.js";
import { parsePasswd, parseSudoers } from "../../../hosts/managers/users.js";
import {
buildHealthCheckCommand,
parseHealthResult,
} from "../../../hosts/managers/health.js";
import { buildTailCommand, clampLines } from "../../../hosts/managers/logs.js";
describe("exec-elevated", () => {
it("single-quotes and escapes for the shell", () => {
@@ -4,7 +4,7 @@ import {
resolveHostForSshConnect,
resolveSshConnectConfigHost,
shouldResolveBeforeSshConnect,
} from "./ssh-dns.js";
} from "../../hosts/ssh-dns.js";
describe("SSH DNS resolution", () => {
it("retries transient EAI_AGAIN errors before returning an address", async () => {
@@ -6,7 +6,7 @@ vi.mock("fs/promises", () => ({
access: mockAccess,
}));
import { resolveAgentSocket } from "./terminal-auth-helpers.js";
import { resolveAgentSocket } from "../../hosts/terminal-auth-helpers.js";
describe("resolveAgentSocket", () => {
const originalEnv = process.env.SSH_AUTH_SOCK;
@@ -1,6 +1,6 @@
import { EventEmitter } from "events";
import { describe, expect, it, vi } from "vitest";
import { performPortKnocking } from "./terminal-auth-helpers.js";
import { performPortKnocking } from "../../hosts/terminal-auth-helpers.js";
class FakeTcpSocket extends EventEmitter {
readonly connect = vi.fn();
@@ -4,18 +4,18 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
const mockCreate = vi.fn().mockResolvedValue({ id: 1 });
const mockUpdateEnded = vi.fn().mockResolvedValue(undefined);
vi.mock("../database/db/index.js", () => ({
vi.mock("../../database/db/index.js", () => ({
getDb: () => ({}),
}));
vi.mock("../database/repositories/factory.js", () => ({
vi.mock("../../database/repositories/factory.js", () => ({
createCurrentSessionRecordingRepository: () => ({
create: mockCreate,
updateEnded: mockUpdateEnded,
}),
}));
vi.mock("../utils/logger.js", () => ({
vi.mock("../../utils/logger.js", () => ({
sshLogger: {
info: vi.fn(),
warn: vi.fn(),
@@ -49,7 +49,8 @@ vi.mock("fs", () => ({
},
}));
const { sessionManager } = await import("./terminal-session-manager.js");
const { sessionManager } =
await import("../../hosts/terminal-session-manager.js");
describe("TerminalSessionManager - session logging", () => {
beforeEach(() => {
@@ -1,7 +1,11 @@
import { EventEmitter } from "node:events";
import type { Client } from "ssh2";
import { describe, expect, it } from "vitest";
import { detectTmux, tmuxCommand, withTmuxPath } from "./tmux-helper.js";
import {
detectTmux,
tmuxCommand,
withTmuxPath,
} from "../../hosts/tmux-helper.js";
describe("tmux command path handling", () => {
it("adds common non-login shell tmux paths", () => {
@@ -9,7 +9,7 @@ import {
buildPaneMetrics,
attachPanesToWindows,
shellEscape,
} from "./tmux-monitor-helpers.js";
} from "../../hosts/tmux-monitor-helpers.js";
function join(...fields: (string | number)[]): string {
return fields.join(SEP);
@@ -11,7 +11,7 @@ import {
completeVaultOidc,
signWithVault,
type VaultProfileConfig,
} from "./vault-signer-core.js";
} from "../../hosts/vault-signer-core.js";
const { utils: ssh2Utils } = ssh2Pkg;
@@ -1,5 +1,5 @@
import { describe, it, expect } from "vitest";
import { toFixedNum, kibToGiB } from "./common-utils.js";
import { toFixedNum, kibToGiB } from "../../../hosts/widgets/common-utils.js";
describe("toFixedNum", () => {
it("rounds to the requested digit count", () => {
@@ -1,5 +1,5 @@
import { describe, it, expect } from "vitest";
import { parseCpuLine } from "./cpu-collector.js";
import { parseCpuLine } from "../../../hosts/widgets/cpu-collector.js";
describe("parseCpuLine", () => {
it("parses a standard /proc/stat cpu line", () => {
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
import {
parseSensorsOutput,
parseSysfsThermalOutput,
} from "./temperature-collector.js";
} from "../../../hosts/widgets/temperature-collector.js";
describe("temperature collectors", () => {
it("parses sysfs thermal zone output", () => {
@@ -2,13 +2,13 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
const createMock = vi.fn().mockResolvedValue(undefined);
vi.mock("../database/repositories/factory.js", () => ({
vi.mock("../../database/repositories/factory.js", () => ({
createCurrentAuditLogRepository: vi.fn(() => ({
create: createMock,
})),
}));
import { logAudit, getRequestMeta } from "./audit-logger.js";
import { logAudit, getRequestMeta } from "../../utils/audit-logger.js";
describe("logAudit", () => {
beforeEach(() => {
@@ -11,7 +11,7 @@ const mocks = vi.hoisted(() => ({
saveDatabase: vi.fn().mockResolvedValue(undefined),
}));
vi.mock("../database/db/index.js", async () => {
vi.mock("../../database/db/index.js", async () => {
const { default: Database } = await import("better-sqlite3");
const { drizzle } = await import("drizzle-orm/better-sqlite3");
const sqlite = new Database(":memory:");
@@ -24,7 +24,7 @@ vi.mock("../database/db/index.js", async () => {
};
});
vi.mock("./user-keys.js", () => ({
vi.mock("../../utils/user-keys.js", () => ({
UserKeyManager: {
getInstance: () => ({
invalidate: vi.fn(),
@@ -34,15 +34,15 @@ vi.mock("./user-keys.js", () => ({
},
}));
vi.mock("./system-crypto.js", () => ({
vi.mock("../../utils/system-crypto.js", () => ({
SystemCrypto: { getInstance: () => ({}) },
}));
vi.mock("./data-crypto.js", () => ({
vi.mock("../../utils/data-crypto.js", () => ({
DataCrypto: { getInstance: () => ({}) },
}));
vi.mock("./logger.js", () => ({
vi.mock("../../utils/logger.js", () => ({
authLogger: {
debug: vi.fn(),
info: vi.fn(),
@@ -59,7 +59,7 @@ vi.mock("./logger.js", () => ({
},
}));
const { AuthManager } = await import("./auth-manager.js");
const { AuthManager } = await import("../../utils/auth-manager.js");
const authManager = AuthManager.getInstance();
type SessionInput = {
@@ -10,13 +10,13 @@ const mocks = vi.hoisted(() => ({
adoptRecoveredDEK: vi.fn(async () => {}),
}));
vi.mock("../database/db/index.js", () => ({
vi.mock("../../database/db/index.js", () => ({
db: {},
getDb: () => ({}),
saveMemoryDatabaseToFile: vi.fn(),
}));
vi.mock("../database/repositories/factory.js", () => ({
vi.mock("../../database/repositories/factory.js", () => ({
createCurrentSettingsRepository: () => ({ get: async () => null }),
createCurrentSessionRepository: () => ({}),
createCurrentUserRepository: () => ({}),
@@ -25,7 +25,7 @@ vi.mock("../database/repositories/factory.js", () => ({
getCurrentSettingValue: () => null,
}));
vi.mock("./user-keys.js", () => ({
vi.mock("../../utils/user-keys.js", () => ({
UserKeyManager: {
getInstance: () => ({
hasUserDEK: mocks.hasUserDEK,
@@ -35,12 +35,12 @@ vi.mock("./user-keys.js", () => ({
},
}));
vi.mock("./crypto-migration/dek-migration.js", () => ({
vi.mock("../../utils/crypto-migration/dek-migration.js", () => ({
adoptRecoveredDEK: mocks.adoptRecoveredDEK,
migratePasswordUserAtLogin: vi.fn(async () => true),
}));
vi.mock("./system-crypto.js", () => ({
vi.mock("../../utils/system-crypto.js", () => ({
SystemCrypto: {
getInstance: () => ({
getJWTSecret: async () => jwtSecret,
@@ -49,7 +49,7 @@ vi.mock("./system-crypto.js", () => ({
},
}));
const { AuthManager } = await import("./auth-manager.js");
const { AuthManager } = await import("../../utils/auth-manager.js");
const authManager = AuthManager.getInstance();
function makeLegacyDataKeyWrap(
@@ -4,7 +4,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
const settingsStore = new Map<string, string>();
let userRows: Array<{ id: string }> = [];
vi.mock("../../database/repositories/factory.js", () => ({
vi.mock("../../../database/repositories/factory.js", () => ({
getCurrentSettingValue: (key: string) => settingsStore.get(key) ?? null,
createCurrentSettingsRepository: () => ({
upsert: async (key: string, value: string) => {
@@ -24,7 +24,7 @@ vi.mock("../../database/repositories/factory.js", () => ({
const masterKey = crypto.randomBytes(32);
vi.mock("../system-crypto.js", () => ({
vi.mock("../../../utils/system-crypto.js", () => ({
SystemCrypto: {
getInstance: () => ({
getEncryptionKey: async () => masterKey,
@@ -32,13 +32,13 @@ vi.mock("../system-crypto.js", () => ({
},
}));
import { UserKeyManager } from "../user-keys.js";
import { UserKeyManager } from "../../../utils/user-keys.js";
import {
adoptRecoveredDEK,
legacySettingsKeys,
migratePasswordUserAtLogin,
runBootDekMigration,
} from "./dek-migration.js";
} from "../../../utils/crypto-migration/dek-migration.js";
const manager = UserKeyManager.getInstance();
@@ -7,7 +7,7 @@ import {
DATABASE_LAYER_PREUPGRADE_BACKUP_PREFIX,
DATABASE_LAYER_SKIP_PREUPGRADE_BACKUP_ENV,
ensureDatabaseLayerPreupgradeBackup,
} from "./database-layer-preupgrade-backup.js";
} from "../../utils/database-layer-preupgrade-backup.js";
const tempDirs: string[] = [];
@@ -1,5 +1,5 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { DatabaseSaveTrigger } from "./database-save-trigger.js";
import { DatabaseSaveTrigger } from "../../utils/database-save-trigger.js";
describe("DatabaseSaveTrigger", () => {
afterEach(() => {
@@ -1,6 +1,6 @@
import { describe, it, expect } from "vitest";
import crypto from "crypto";
import { FieldCrypto } from "./field-crypto.js";
import { FieldCrypto } from "../../utils/field-crypto.js";
const masterKey = crypto.randomBytes(32);
@@ -3,7 +3,7 @@ import fs from "fs";
import os from "os";
import path from "path";
import { afterEach, describe, expect, it } from "vitest";
import { LegacySqliteDatabaseCopyStore } from "./legacy-sqlite-database-copy-store.js";
import { LegacySqliteDatabaseCopyStore } from "../../utils/legacy-sqlite-database-copy-store.js";
describe("LegacySqliteDatabaseCopyStore", () => {
let tempDir: string | null = null;
@@ -1,5 +1,5 @@
import { describe, it, expect, beforeEach } from "vitest";
import { loginRateLimiter } from "./login-rate-limiter.js";
import { loginRateLimiter } from "../../utils/login-rate-limiter.js";
// The limiter is a shared singleton, so each test uses unique ip/username keys
// and resets them to stay isolated.
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
import {
getDesktopOidcCallbackUrl,
isOidcTokenCallback,
} from "./oidc-desktop-callback";
} from "../../utils/oidc-desktop-callback.js";
describe("getDesktopOidcCallbackUrl", () => {
it("uses localhost so browsers do not upgrade the loopback callback", () => {
@@ -4,8 +4,8 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
// top level. Stub both so importing the module does not spin up the real
// database / encryption stack. We then drive hasPermission via a spied
// getUserPermissions so we test the wildcard-matching logic in isolation.
vi.mock("../database/db/index.js", () => ({ db: {} }));
vi.mock("./logger.js", () => ({
vi.mock("../../database/db/index.js", () => ({ db: {} }));
vi.mock("../../utils/logger.js", () => ({
databaseLogger: {
debug: vi.fn(),
info: vi.fn(),
@@ -15,7 +15,7 @@ vi.mock("./logger.js", () => ({
},
}));
const { PermissionManager } = await import("./permission-manager.js");
const { PermissionManager } = await import("../../utils/permission-manager.js");
type PermissionManagerInstance = ReturnType<
typeof PermissionManager.getInstance
@@ -5,7 +5,7 @@ import {
getRequestBaseUrlWithForceHTTPS,
getRequestOrigin,
normalizeBasePath,
} from "./request-origin.js";
} from "../../utils/request-origin.js";
function request(headers: Record<string, string | string[] | undefined>) {
return {
@@ -9,7 +9,7 @@ const state = vi.hoisted(() => ({
ownerCredential: null as Record<string, unknown> | null,
}));
vi.mock("../database/repositories/factory.js", () => ({
vi.mock("../../database/repositories/factory.js", () => ({
createCurrentCredentialRepository: () => ({
findByIdForUser: async (_userId: string, _id: number) =>
state.ownerCredential,
@@ -38,7 +38,7 @@ vi.mock("../database/repositories/factory.js", () => ({
}),
}));
vi.mock("./data-crypto.js", () => ({
vi.mock("../../utils/data-crypto.js", () => ({
DataCrypto: {
validateUserAccess: (userId: string) => {
if (userId === "owner") return ownerDEK;
@@ -51,8 +51,8 @@ vi.mock("./data-crypto.js", () => ({
},
}));
import { FieldCrypto } from "./field-crypto.js";
import { SharedCredentialManager } from "./shared-credential-manager.js";
import { FieldCrypto } from "../../utils/field-crypto.js";
import { SharedCredentialManager } from "../../utils/shared-credential-manager.js";
const manager = SharedCredentialManager.getInstance();
@@ -6,7 +6,7 @@ import {
preparePrivateKeyForSSH2,
getFriendlyKeyTypeName,
validateKeyPair,
} from "./ssh-key-utils.js";
} from "../../utils/ssh-key-utils.js";
// A real OpenSSH ed25519 keypair generated solely for these tests. It grants no
// access to anything and exists only so the ssh2 parsing path is exercised for
@@ -4,7 +4,7 @@ import {
detectPlatform,
parseUserAgent,
generateDeviceFingerprint,
} from "./user-agent-parser.js";
} from "../../utils/user-agent-parser.js";
function reqWith(headers: Record<string, string>): Request {
return { headers } as unknown as Request;
@@ -1,5 +1,5 @@
import { describe, expect, it, vi } from "vitest";
import { RawSqliteUserEncryptionMigrationStore } from "./user-encryption-migration-store.js";
import { RawSqliteUserEncryptionMigrationStore } from "../../utils/user-encryption-migration-store.js";
describe("RawSqliteUserEncryptionMigrationStore", () => {
function createDb() {
@@ -3,7 +3,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
const settingsStore = new Map<string, string>();
vi.mock("../database/repositories/factory.js", () => ({
vi.mock("../../database/repositories/factory.js", () => ({
getCurrentSettingValue: (key: string) => settingsStore.get(key) ?? null,
createCurrentSettingsRepository: () => ({
upsert: async (key: string, value: string) => {
@@ -19,7 +19,7 @@ import {
UserKeyManager,
UserKeyUnavailableError,
userDekSettingsKey,
} from "./user-keys.js";
} from "../../utils/user-keys.js";
const masterKey = crypto.randomBytes(32);
const manager = UserKeyManager.getInstance();
@@ -12,7 +12,11 @@ vi.mock("dgram", () => {
});
import dgram from "dgram";
import { isValidMac, buildMagicPacket, sendWakeOnLan } from "./wake-on-lan.js";
import {
isValidMac,
buildMagicPacket,
sendWakeOnLan,
} from "../../utils/wake-on-lan.js";
describe("isValidMac", () => {
it("accepts colon-separated MAC addresses", () => {