fix(testkit): macOS compat + fix test 8c ordering (#24)

This commit is contained in:
2026-03-18 21:01:13 -04:00
parent ca94c0a9e5
commit 83a2ec19e2
59 changed files with 4458 additions and 454 deletions

View File

@@ -1,6 +1,9 @@
import { generateKeyPairSync } from "crypto";
import { db, bootstrapJobs } from "@workspace/db";
import { eq } from "drizzle-orm";
import { makeLogger } from "./logger.js";
const logger = makeLogger("provisioner");
const DO_API_BASE = "https://api.digitalocean.com/v2";
const TS_API_BASE = "https://api.tailscale.com/api/v2";
@@ -458,9 +461,7 @@ export class ProvisionerService {
this.tsTailnet = process.env.TAILSCALE_TAILNET ?? "";
this.stubMode = !this.doToken;
if (this.stubMode) {
console.warn(
"[ProvisionerService] No DO_API_TOKEN — running in STUB mode. Provisioning is simulated.",
);
logger.warn("no DO_API_TOKEN — running in STUB mode", { stub: true });
}
}
@@ -477,7 +478,7 @@ export class ProvisionerService {
}
} catch (err) {
const message = err instanceof Error ? err.message : "Provisioning failed";
console.error(`[ProvisionerService] Error for job ${bootstrapJobId}:`, message);
logger.error("provisioning failed", { bootstrapJobId, error: message });
await db
.update(bootstrapJobs)
.set({ state: "failed", errorMessage: message, updatedAt: new Date() })
@@ -486,7 +487,7 @@ export class ProvisionerService {
}
private async stubProvision(jobId: string): Promise<void> {
console.log(`[stub] Simulating provisioning for bootstrap job ${jobId}...`);
logger.info("stub provisioning started", { bootstrapJobId: jobId });
const { privateKey } = generateSshKeypair();
await new Promise((r) => setTimeout(r, 2000));
const fakeDropletId = String(Math.floor(Math.random() * 900_000_000 + 100_000_000));
@@ -502,11 +503,11 @@ export class ProvisionerService {
updatedAt: new Date(),
})
.where(eq(bootstrapJobs.id, jobId));
console.log(`[stub] Bootstrap job ${jobId} marked ready with fake credentials.`);
logger.info("stub provisioning complete", { bootstrapJobId: jobId });
}
private async realProvision(jobId: string): Promise<void> {
console.log(`[ProvisionerService] Provisioning real node for job ${jobId}...`);
logger.info("real provisioning started", { bootstrapJobId: jobId });
// 1. SSH keypair (pure node:crypto)
const { publicKey, privateKey } = generateSshKeypair();
@@ -525,7 +526,7 @@ export class ProvisionerService {
try {
tailscaleAuthKey = await getTailscaleAuthKey(this.tsApiKey, this.tsTailnet);
} catch (err) {
console.warn("[ProvisionerService] Tailscale key failed — continuing without:", err);
logger.warn("Tailscale key failed — continuing without Tailscale", { error: String(err) });
}
}
@@ -534,7 +535,7 @@ export class ProvisionerService {
if (this.doVolumeGb > 0) {
const volName = `timmy-data-${jobId.slice(0, 8)}`;
volumeId = await createVolume(volName, this.doVolumeGb, this.doRegion, this.doToken);
console.log(`[ProvisionerService] Volume created: id=${volumeId} (${this.doVolumeGb} GB)`);
logger.info("block volume created", { volumeId, sizeGb: this.doVolumeGb });
}
// 5. Create droplet
@@ -556,11 +557,11 @@ export class ProvisionerService {
dropletPayload,
);
const dropletId = dropletData.droplet.id;
console.log(`[ProvisionerService] Droplet created: id=${dropletId}`);
logger.info("droplet created", { bootstrapJobId: jobId, dropletId });
// 6. Poll for public IP (up to 2 min)
const nodeIp = await pollDropletIp(dropletId, this.doToken, 120_000);
console.log(`[ProvisionerService] Node IP: ${nodeIp ?? "(not yet assigned)"}`);
logger.info("node ip assigned", { bootstrapJobId: jobId, nodeIp: nodeIp ?? "(not yet assigned)" });
// 7. Tailscale hostname
const tailscaleHostname =
@@ -589,7 +590,7 @@ export class ProvisionerService {
})
.where(eq(bootstrapJobs.id, jobId));
console.log(`[ProvisionerService] Bootstrap job ${jobId} ready.`);
logger.info("real provisioning complete", { bootstrapJobId: jobId });
}
}