@ebowwa/hetzner 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bootstrap/index.js +1126 -0
- package/dist/bootstrap/index.js.map +15 -0
- package/dist/index.js +3540 -0
- package/dist/index.js.map +31 -0
- package/dist/onboarding/index.js +460 -0
- package/dist/onboarding/index.js.map +14 -0
- package/package.json +53 -16
- package/actions.js +0 -1084
- package/actions.ts +0 -1053
- package/auth.js +0 -39
- package/auth.ts +0 -37
- package/bootstrap/FIREWALL.md +0 -326
- package/bootstrap/KERNEL-HARDENING.md +0 -258
- package/bootstrap/SECURITY-INTEGRATION.md +0 -281
- package/bootstrap/TESTING.md +0 -301
- package/bootstrap/cloud-init.js +0 -323
- package/bootstrap/cloud-init.ts +0 -394
- package/bootstrap/firewall.js +0 -292
- package/bootstrap/firewall.ts +0 -342
- package/bootstrap/genesis.js +0 -424
- package/bootstrap/genesis.ts +0 -518
- package/bootstrap/index.js +0 -59
- package/bootstrap/index.ts +0 -71
- package/bootstrap/kernel-hardening.js +0 -270
- package/bootstrap/kernel-hardening.test.js +0 -182
- package/bootstrap/kernel-hardening.test.ts +0 -230
- package/bootstrap/kernel-hardening.ts +0 -272
- package/bootstrap/security-audit.js +0 -122
- package/bootstrap/security-audit.ts +0 -124
- package/bootstrap/ssh-hardening.js +0 -186
- package/bootstrap/ssh-hardening.ts +0 -192
- package/client.js +0 -234
- package/client.ts +0 -177
- package/config.js +0 -7
- package/config.ts +0 -5
- package/errors.js +0 -345
- package/errors.ts +0 -371
- package/index.js +0 -73
- package/index.ts +0 -59
- package/onboarding/doppler.ts +0 -116
- package/onboarding/git.ts +0 -133
- package/onboarding/index.ts +0 -18
- package/onboarding/onboarding.ts +0 -193
- package/onboarding/tailscale.ts +0 -159
- package/onboarding/types.ts +0 -115
- package/pricing.js +0 -387
- package/pricing.ts +0 -422
- package/schemas.js +0 -667
- package/schemas.ts +0 -765
- package/server-status.js +0 -122
- package/server-status.ts +0 -81
- package/servers.js +0 -667
- package/servers.ts +0 -568
- package/ssh-keys.js +0 -180
- package/ssh-keys.ts +0 -122
- package/ssh-setup.js +0 -253
- package/ssh-setup.ts +0 -218
- package/types.js +0 -99
- package/types.ts +0 -389
- package/volumes.js +0 -295
- package/volumes.ts +0 -229
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/config.ts", "../src/auth.ts", "../src/servers.ts", "../src/schemas.ts", "../src/types.ts", "../src/errors.ts", "../src/actions.ts", "../src/pricing.ts", "../src/ssh-keys.ts", "../src/volumes.ts", "../src/client.ts", "../src/bootstrap/ssh-hardening.ts", "../src/bootstrap/firewall.ts", "../src/bootstrap/kernel-hardening.ts", "../src/bootstrap/security-audit.ts", "../src/bootstrap/genesis.ts", "../src/bootstrap/cloud-init.ts", "../src/onboarding/doppler.ts", "../src/onboarding/tailscale.ts", "../src/onboarding/git.ts", "../src/onboarding/claude.ts", "../src/onboarding/onboarding.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * Hetzner Cloud API configuration\n */\n\nexport const HETZNER_API_BASE = \"https://api.hetzner.cloud/v1\";\n",
|
|
6
|
+
"/**\n * Hetzner authentication utilities\n */\n\nimport { readFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nexport function getTokenFromCLI(): string {\n try {\n const configPath = join(homedir(), \".config\", \"hcloud\", \"cli.toml\");\n if (existsSync(configPath)) {\n const config = readFileSync(configPath, \"utf-8\");\n const match = config.match(/token\\s*=\\s*[\"']([^\"']+)[\"']/);\n if (match && match[1]) {\n return match[1];\n }\n }\n } catch (e) {\n // Ignore errors\n }\n return \"\";\n}\n\nexport function isAuthenticated(apiToken: string): boolean {\n return apiToken.length > 0;\n}\n\nexport function resolveApiToken(explicitToken?: string): string {\n if (explicitToken) {\n return explicitToken;\n }\n if (process.env.HETZNER_API_TOKEN) {\n return process.env.HETZNER_API_TOKEN;\n }\n return getTokenFromCLI();\n}\n",
|
|
7
|
+
"/**\n * Hetzner server operations\n */\n\nimport { z } from \"zod\";\nimport type {\n HetznerServer,\n CreateServerOptions,\n HetznerAction,\n CreateServerResponse,\n} from \"./types.js\";\nimport type { HetznerClient } from \"./client.js\";\nimport {\n HetznerListServersResponseSchema,\n HetznerGetServerResponseSchema,\n HetznerCreateServerResponseSchema,\n HetznerActionSchema,\n} from \"./schemas.js\";\n\nexport class ServerOperations {\n constructor(private client: HetznerClient) {}\n\n /**\n * List all servers\n */\n async list(): Promise<HetznerServer[]> {\n const response = await this.client.request<{ servers: HetznerServer[] }>(\n \"/servers\",\n );\n\n // Validate response with Zod\n const validated = HetznerListServersResponseSchema.safeParse(response);\n if (!validated.success) {\n console.warn('Hetzner list servers validation warning:', validated.error.issues);\n return response.servers; // Return unvalidated data for backward compatibility\n }\n\n return validated.data.servers;\n }\n\n /**\n * Get a specific server by ID\n */\n async get(id: number): Promise<HetznerServer> {\n const response = await this.client.request<{ server: HetznerServer }>(\n `/servers/${id}`,\n );\n\n // Validate response with Zod\n const validated = HetznerGetServerResponseSchema.safeParse(response);\n if (!validated.success) {\n console.warn('Hetzner get server validation warning:', validated.error.issues);\n return response.server; // Return unvalidated data for backward compatibility\n }\n\n return validated.data.server;\n }\n\n /**\n * Create a new server\n *\n * @param options - Server creation options\n * @returns Create server response including server, action, and next_actions\n */\n async create(options: CreateServerOptions): Promise<CreateServerResponse> {\n // Validate input with Zod\n const createServerOptionsSchema = z.object({\n name: z.string().min(1),\n server_type: z.string().min(1).default(\"cpx11\"),\n image: z.string().min(1).default(\"ubuntu-24.04\"),\n location: z.string().min(1).optional(),\n datacenter: z.string().min(1).optional(),\n ssh_keys: z.array(z.union([z.string(), z.number()])).default([]),\n volumes: z.array(z.number()).default([]),\n labels: z.record(z.string(), z.any()).optional(),\n start_after_create: z.boolean().default(true),\n user_data: z.string().optional(),\n });\n\n const validatedOptions = createServerOptionsSchema.safeParse(options);\n if (!validatedOptions.success) {\n throw new Error(`Invalid server options: ${validatedOptions.error.issues.map(i => i.message).join(', ')}`);\n }\n\n // Ensure either location or datacenter, not both\n if (validatedOptions.data.location && validatedOptions.data.datacenter) {\n throw new Error('Cannot specify both location and datacenter');\n }\n\n const body = {\n name: validatedOptions.data.name,\n server_type: validatedOptions.data.server_type,\n image: validatedOptions.data.image,\n ...(validatedOptions.data.location && { location: validatedOptions.data.location }),\n ...(validatedOptions.data.datacenter && { datacenter: { id: validatedOptions.data.datacenter } }),\n ssh_keys: validatedOptions.data.ssh_keys,\n volumes: validatedOptions.data.volumes,\n ...(validatedOptions.data.labels && { labels: validatedOptions.data.labels }),\n start_after_create: validatedOptions.data.start_after_create,\n ...(validatedOptions.data.user_data && { user_data: validatedOptions.data.user_data }),\n };\n\n console.log('[Hetzner] Creating server with body:', JSON.stringify(body, null, 2));\n\n const response = await this.client.request<CreateServerResponse>(\"/servers\", {\n method: \"POST\",\n body: JSON.stringify(body),\n });\n\n // Validate response with Zod\n const validatedResponse = HetznerCreateServerResponseSchema.safeParse(response);\n if (!validatedResponse.success) {\n console.warn('Hetzner create server validation warning:', validatedResponse.error.issues);\n return response; // Return unvalidated data for backward compatibility\n }\n\n return validatedResponse.data as CreateServerResponse;\n }\n\n /**\n * Create a new server and wait for it to be ready\n *\n * This convenience method creates a server and waits for the initial action to complete.\n *\n * @param options - Server creation options\n * @param onProgress - Optional progress callback\n * @returns Server once ready\n */\n async createAndWait(\n options: CreateServerOptions,\n onProgress?: (action: HetznerAction) => void\n ): Promise<HetznerServer> {\n const response = await this.create(options);\n\n // Build wait options (only include onProgress if defined)\n const waitOptions = onProgress !== undefined ? { onProgress } : {};\n\n // Wait for the main create action to complete\n if (response.action.status === 'running') {\n await this.client.actions.waitFor(response.action.id, waitOptions);\n }\n\n // Wait for any next actions (e.g., start server)\n if (response.next_actions.length > 0) {\n for (const action of response.next_actions) {\n await this.client.actions.waitFor(action.id, waitOptions);\n }\n }\n\n // Return the server object\n const server = await this.get(response.server.id);\n return server;\n }\n\n /**\n * Delete a server\n *\n * @param id - Server ID\n * @returns Action for server deletion\n */\n async delete(id: number): Promise<HetznerAction> {\n // Validate ID with Zod\n const serverIdSchema = z.number().int().positive();\n const validatedId = serverIdSchema.safeParse(id);\n if (!validatedId.success) {\n throw new Error(`Invalid server ID: ${validatedId.error.issues.map(i => i.message).join(', ')}`);\n }\n\n const response = await this.client.request<{ action: HetznerAction }>(\n `/servers/${validatedId.data}`,\n { method: \"DELETE\" }\n );\n\n const validated = HetznerActionSchema.safeParse(response.action);\n if (!validated.success) {\n console.warn('Hetzner delete server validation warning:', validated.error.issues);\n return response.action;\n }\n\n return validated.data as HetznerAction;\n }\n\n /**\n * Delete a server and wait for completion\n *\n * @param id - Server ID\n * @param onProgress - Optional progress callback\n */\n async deleteAndWait(\n id: number,\n onProgress?: (action: HetznerAction) => void\n ): Promise<void> {\n const action = await this.delete(id);\n await this.client.actions.waitFor(action.id, { onProgress });\n }\n\n /**\n * Power on a server\n *\n * @param id - Server ID\n * @returns Action for server power on\n */\n async powerOn(id: number): Promise<HetznerAction> {\n // Validate ID with Zod\n const serverIdSchema = z.number().int().positive();\n const validatedId = serverIdSchema.safeParse(id);\n if (!validatedId.success) {\n throw new Error(`Invalid server ID: ${validatedId.error.issues.map(i => i.message).join(', ')}`);\n }\n\n const response = await this.client.request<{ action: HetznerAction }>(\n `/servers/${validatedId.data}/actions/poweron`,\n { method: \"POST\" }\n );\n\n const validated = HetznerActionSchema.safeParse(response.action);\n if (!validated.success) {\n console.warn('Hetzner power on validation warning:', validated.error.issues);\n return response.action;\n }\n\n return validated.data as HetznerAction;\n }\n\n /**\n * Power on a server and wait for completion\n *\n * @param id - Server ID\n * @param onProgress - Optional progress callback\n */\n async powerOnAndWait(\n id: number,\n onProgress?: (action: HetznerAction) => void\n ): Promise<HetznerAction> {\n const action = await this.powerOn(id);\n return await this.client.actions.waitFor(action.id, { onProgress });\n }\n\n /**\n * Power off a server\n *\n * @param id - Server ID\n * @returns Action for server power off\n */\n async powerOff(id: number): Promise<HetznerAction> {\n // Validate ID with Zod\n const serverIdSchema = z.number().int().positive();\n const validatedId = serverIdSchema.safeParse(id);\n if (!validatedId.success) {\n throw new Error(`Invalid server ID: ${validatedId.error.issues.map(i => i.message).join(', ')}`);\n }\n\n const response = await this.client.request<{ action: HetznerAction }>(\n `/servers/${validatedId.data}/actions/poweroff`,\n { method: \"POST\" }\n );\n\n const validated = HetznerActionSchema.safeParse(response.action);\n if (!validated.success) {\n console.warn('Hetzner power off validation warning:', validated.error.issues);\n return response.action;\n }\n\n return validated.data as HetznerAction;\n }\n\n /**\n * Power off a server and wait for completion\n *\n * @param id - Server ID\n * @param onProgress - Optional progress callback\n */\n async powerOffAndWait(\n id: number,\n onProgress?: (action: HetznerAction) => void\n ): Promise<HetznerAction> {\n const action = await this.powerOff(id);\n return await this.client.actions.waitFor(action.id, { onProgress });\n }\n\n /**\n * Reboot a server\n *\n * @param id - Server ID\n * @returns Action for server reboot\n */\n async reboot(id: number): Promise<HetznerAction> {\n // Validate ID with Zod\n const serverIdSchema = z.number().int().positive();\n const validatedId = serverIdSchema.safeParse(id);\n if (!validatedId.success) {\n throw new Error(`Invalid server ID: ${validatedId.error.issues.map(i => i.message).join(', ')}`);\n }\n\n const response = await this.client.request<{ action: HetznerAction }>(\n `/servers/${validatedId.data}/actions/reboot`,\n { method: \"POST\" }\n );\n\n const validated = HetznerActionSchema.safeParse(response.action);\n if (!validated.success) {\n console.warn('Hetzner reboot validation warning:', validated.error.issues);\n return response.action;\n }\n\n return validated.data as HetznerAction;\n }\n\n /**\n * Reboot a server and wait for completion\n *\n * @param id - Server ID\n * @param onProgress - Optional progress callback\n */\n async rebootAndWait(\n id: number,\n onProgress?: (action: HetznerAction) => void\n ): Promise<HetznerAction> {\n const action = await this.reboot(id);\n return await this.client.actions.waitFor(action.id, { onProgress });\n }\n\n /**\n * Shutdown a server gracefully\n *\n * @param id - Server ID\n * @returns Action for server shutdown\n */\n async shutdown(id: number): Promise<HetznerAction> {\n // Validate ID with Zod\n const serverIdSchema = z.number().int().positive();\n const validatedId = serverIdSchema.safeParse(id);\n if (!validatedId.success) {\n throw new Error(`Invalid server ID: ${validatedId.error.issues.map(i => i.message).join(', ')}`);\n }\n\n const response = await this.client.request<{ action: HetznerAction }>(\n `/servers/${validatedId.data}/actions/shutdown`,\n { method: \"POST\" }\n );\n\n const validated = HetznerActionSchema.safeParse(response.action);\n if (!validated.success) {\n console.warn('Hetzner shutdown validation warning:', validated.error.issues);\n return response.action;\n }\n\n return validated.data as HetznerAction;\n }\n\n /**\n * Shutdown a server and wait for completion\n *\n * @param id - Server ID\n * @param onProgress - Optional progress callback\n */\n async shutdownAndWait(\n id: number,\n onProgress?: (action: HetznerAction) => void\n ): Promise<HetznerAction> {\n const action = await this.shutdown(id);\n return await this.client.actions.waitFor(action.id, { onProgress });\n }\n\n /**\n * Reset a server\n *\n * @param id - Server ID\n * @returns Action for server reset\n */\n async reset(id: number): Promise<HetznerAction> {\n // Validate ID with Zod\n const serverIdSchema = z.number().int().positive();\n const validatedId = serverIdSchema.safeParse(id);\n if (!validatedId.success) {\n throw new Error(`Invalid server ID: ${validatedId.error.issues.map(i => i.message).join(', ')}`);\n }\n\n const response = await this.client.request<{ action: HetznerAction }>(\n `/servers/${validatedId.data}/actions/reset`,\n { method: \"POST\" }\n );\n\n const validated = HetznerActionSchema.safeParse(response.action);\n if (!validated.success) {\n console.warn('Hetzner reset validation warning:', validated.error.issues);\n return response.action;\n }\n\n return validated.data as HetznerAction;\n }\n\n /**\n * Reset a server and wait for completion\n *\n * @param id - Server ID\n * @param onProgress - Optional progress callback\n */\n async resetAndWait(\n id: number,\n onProgress?: (action: HetznerAction) => void\n ): Promise<HetznerAction> {\n const action = await this.reset(id);\n return await this.client.actions.waitFor(action.id, { onProgress });\n }\n\n /**\n * Rebuild a server from an image\n *\n * @param id - Server ID\n * @param image - Image ID or name\n * @returns Action for server rebuild\n */\n async rebuild(id: number, image: string): Promise<HetznerAction> {\n // Validate ID with Zod\n const serverIdSchema = z.number().int().positive();\n const validatedId = serverIdSchema.safeParse(id);\n if (!validatedId.success) {\n throw new Error(`Invalid server ID: ${validatedId.error.issues.map(i => i.message).join(', ')}`);\n }\n\n const response = await this.client.request<{ action: HetznerAction }>(\n `/servers/${validatedId.data}/actions/rebuild`,\n {\n method: \"POST\",\n body: JSON.stringify({ image }),\n }\n );\n\n const validated = HetznerActionSchema.safeParse(response.action);\n if (!validated.success) {\n console.warn('Hetzner rebuild validation warning:', validated.error.issues);\n return response.action;\n }\n\n return validated.data as HetznerAction;\n }\n\n /**\n * Enable rescue mode for a server\n *\n * @param id - Server ID\n * @param options - Rescue mode options\n * @returns Action for enabling rescue mode\n */\n async enableRescue(\n id: number,\n options?: { type?: string; ssh_keys?: number[] }\n ): Promise<HetznerAction> {\n // Validate ID with Zod\n const serverIdSchema = z.number().int().positive();\n const validatedId = serverIdSchema.safeParse(id);\n if (!validatedId.success) {\n throw new Error(`Invalid server ID: ${validatedId.error.issues.map(i => i.message).join(', ')}`);\n }\n\n const response = await this.client.request<{ action: HetznerAction }>(\n `/servers/${validatedId.data}/actions/enable_rescue`,\n {\n method: \"POST\",\n body: JSON.stringify(options || {}),\n }\n );\n\n const validated = HetznerActionSchema.safeParse(response.action);\n if (!validated.success) {\n console.warn('Hetzner enable rescue validation warning:', validated.error.issues);\n return response.action;\n }\n\n return validated.data as HetznerAction;\n }\n\n /**\n * Disable rescue mode for a server\n *\n * @param id - Server ID\n * @returns Action for disabling rescue mode\n */\n async disableRescue(id: number): Promise<HetznerAction> {\n // Validate ID with Zod\n const serverIdSchema = z.number().int().positive();\n const validatedId = serverIdSchema.safeParse(id);\n if (!validatedId.success) {\n throw new Error(`Invalid server ID: ${validatedId.error.issues.map(i => i.message).join(', ')}`);\n }\n\n const response = await this.client.request<{ action: HetznerAction }>(\n `/servers/${validatedId.data}/actions/disable_rescue`,\n { method: \"POST\" }\n );\n\n const validated = HetznerActionSchema.safeParse(response.action);\n if (!validated.success) {\n console.warn('Hetzner disable rescue validation warning:', validated.error.issues);\n return response.action;\n }\n\n return validated.data as HetznerAction;\n }\n\n /**\n * Change server type\n *\n * @param id - Server ID\n * @param serverType - New server type\n * @param upgradeDisk - Whether to upgrade disk (default: false)\n * @returns Action for changing server type\n */\n async changeType(\n id: number,\n serverType: string,\n upgradeDisk: boolean = false\n ): Promise<HetznerAction> {\n // Validate ID with Zod\n const serverIdSchema = z.number().int().positive();\n const validatedId = serverIdSchema.safeParse(id);\n if (!validatedId.success) {\n throw new Error(`Invalid server ID: ${validatedId.error.issues.map(i => i.message).join(', ')}`);\n }\n\n const response = await this.client.request<{ action: HetznerAction }>(\n `/servers/${validatedId.data}/actions/change_type`,\n {\n method: \"POST\",\n body: JSON.stringify({ server_type: serverType, upgrade_disk: upgradeDisk }),\n }\n );\n\n const validated = HetznerActionSchema.safeParse(response.action);\n if (!validated.success) {\n console.warn('Hetzner change type validation warning:', validated.error.issues);\n return response.action;\n }\n\n return validated.data as HetznerAction;\n }\n\n /**\n * Get actions for a specific server\n *\n * @param id - Server ID\n * @param options - Optional filters (status, sort, etc.)\n * @returns Array of server actions\n */\n async getActions(\n id: number,\n options?: { status?: \"running\" | \"success\" | \"error\"; sort?: string }\n ): Promise<HetznerAction[]> {\n // Validate ID with Zod\n const serverIdSchema = z.number().int().positive();\n const validatedId = serverIdSchema.safeParse(id);\n if (!validatedId.success) {\n throw new Error(`Invalid server ID: ${validatedId.error.issues.map(i => i.message).join(', ')}`);\n }\n\n const params = new URLSearchParams();\n if (options?.status) params.append(\"status\", options.status);\n if (options?.sort) params.append(\"sort\", options.sort);\n\n const query = params.toString();\n const response = await this.client.request<{ actions: HetznerAction[] }>(\n `/servers/${validatedId.data}/actions${query ? `?${query}` : \"\"}`\n );\n\n return response.actions;\n }\n}\n",
|
|
8
|
+
"/**\n * Hetzner Cloud API Zod validation schemas\n *\n * These schemas provide runtime validation for API responses\n * and help ensure type safety throughout the application.\n */\n\nimport { z } from \"zod\";\n\n// Import status enums to use in schema validation\nimport {\n EnvironmentStatus,\n ActionStatus,\n VolumeStatus,\n} from \"@ebowwa/codespaces-types/compile\";\n\n// ============================================================================\n// Helper Validators\n// ============================================================================\n\n/**\n * IPv4 address validator\n */\nconst ipv4Regex =\n /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;\n\n/**\n * IPv6 address validator\n * Hetzner returns IPv6 in CIDR notation which can vary in format\n * Using a more lenient pattern since exact format varies\n */\nconst ipv6Regex = /^[0-9a-fA-F:]+(?:\\/\\d{1,3})?$/;\n\n/**\n * IP address validator (IPv4 or IPv6)\n */\nconst ipRegex =\n /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$|^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;\n\n// ============================================================================\n// Base Schemas\n// ============================================================================\n\n/**\n * Hetzner API error response schema\n */\nexport const HetznerErrorSchema = z.object({\n code: z.string(),\n message: z.string(),\n details: z.any().optional(),\n});\n\n/**\n * Pagination metadata schema\n */\nexport const HetznerPaginationSchema = z.object({\n page: z.number(),\n per_page: z.number(),\n previous_page: z.number().nullable(),\n next_page: z.number().nullable(),\n last_page: z.number(),\n total_entries: z.number(),\n});\n\n/**\n * Metadata wrapper schema\n */\nexport const HetznerMetaSchema = z.object({\n pagination: HetznerPaginationSchema.optional(),\n});\n\n// ============================================================================\n// Action Schemas\n// ============================================================================\n\n/**\n * Action resource schema\n */\nexport const HetznerActionResourceSchema = z.object({\n id: z.number(),\n type: z.enum([\n \"server\",\n \"volume\",\n \"network\",\n \"floating_ip\",\n \"load_balancer\",\n \"certificate\",\n \"firewall\",\n \"image\",\n ]),\n});\n\n/**\n * Action error schema\n */\nexport const HetznerActionErrorSchema = z.object({\n code: z.string(),\n message: z.string(),\n});\n\n/**\n * Base action schema\n */\nexport const HetznerActionSchema = z.object({\n id: z.number(),\n command: z.string(), // API returns string, not ActionCommand enum\n status: z.nativeEnum(ActionStatus),\n started: z.string(),\n finished: z.string().nullable(),\n progress: z.number().min(0).max(100),\n resources: z.array(HetznerActionResourceSchema),\n error: HetznerActionErrorSchema.nullable(),\n});\n\n/**\n * Action response schema\n */\nexport const HetznerActionResponseSchema = z.object({\n action: HetznerActionSchema,\n});\n\n/**\n * Actions list response schema\n */\nexport const HetznerActionsResponseSchema = z.object({\n actions: z.array(HetznerActionSchema),\n meta: HetznerMetaSchema,\n});\n\n// ============================================================================\n// Server Schemas\n// ============================================================================\n\n/**\n * Server image schema\n */\nexport const HetznerServerImageSchema = z.object({\n id: z.number(),\n name: z.string(),\n description: z.string(),\n type: z.enum([\"snapshot\", \"backup\", \"system\"]),\n});\n\n/**\n * Server IPv4 schema\n */\nexport const HetznerIPv4Schema = z.object({\n ip: z.string().regex(ipv4Regex),\n blocked: z.boolean(),\n});\n\n/**\n * Server IPv6 schema\n */\nexport const HetznerIPv6Schema = z.object({\n ip: z.string().regex(ipv6Regex),\n blocked: z.boolean(),\n});\n\n/**\n * Server floating IP reference schema\n */\nexport const HetznerFloatingIpRefSchema = z.object({\n id: z.number(),\n ip: z.string(),\n});\n\n/**\n * Server firewall reference schema\n */\nexport const HetznerFirewallRefSchema = z.object({\n id: z.number(),\n name: z.string(),\n status: z.enum([\"applied\", \"pending\"]),\n});\n\n/**\n * Server public network schema\n */\nexport const HetznerPublicNetSchema = z.object({\n ipv4: HetznerIPv4Schema,\n ipv6: HetznerIPv6Schema.optional(),\n floating_ips: z.array(HetznerFloatingIpRefSchema),\n firewalls: z.array(HetznerFirewallRefSchema),\n});\n\n/**\n * Server type schema\n */\nexport const HetznerServerTypeSchema = z.object({\n id: z.number(),\n name: z.string(),\n description: z.string(),\n cores: z.number(),\n memory: z.number(),\n disk: z.number(),\n});\n\n/**\n * Location schema\n */\nexport const HetznerLocationSchema = z.object({\n id: z.number(),\n name: z.string(),\n description: z.string(),\n country: z.string(),\n city: z.string(),\n latitude: z.number(),\n longitude: z.number(),\n network_zone: z.string(),\n});\n\n/**\n * Datacenter schema\n */\nexport const HetznerDatacenterSchema = z.object({\n id: z.number(),\n name: z.string(),\n description: z.string(),\n location: HetznerLocationSchema,\n // Hetzner API sometimes doesn't return this field\n supported_server_types: z\n .array(\n z.object({\n id: z.number(),\n name: z.string(),\n }),\n )\n .optional()\n .nullable(),\n});\n\n/**\n * Server volume reference schema\n */\nexport const HetznerVolumeRefSchema = z.object({\n id: z.number(),\n name: z.string(),\n size: z.number().positive(),\n linux_device: z.string(),\n});\n\n/**\n * Server protection schema\n */\nexport const HetznerServerProtectionSchema = z.object({\n delete: z.boolean(),\n rebuild: z.boolean(),\n});\n\n/**\n * Full server schema\n */\nexport const HetznerServerSchema = z.object({\n id: z.number().positive(),\n name: z.string().min(1),\n status: z.nativeEnum(EnvironmentStatus),\n image: HetznerServerImageSchema.nullable().optional(),\n public_net: HetznerPublicNetSchema,\n server_type: HetznerServerTypeSchema,\n datacenter: HetznerDatacenterSchema,\n labels: z.record(z.string(), z.any()),\n created: z.string().datetime(),\n protection: HetznerServerProtectionSchema,\n volumes: z.array(HetznerVolumeRefSchema),\n});\n\n/**\n * List servers response schema\n */\nexport const HetznerListServersResponseSchema = z.object({\n servers: z.array(HetznerServerSchema),\n meta: HetznerMetaSchema,\n});\n\n/**\n * Get server response schema\n */\nexport const HetznerGetServerResponseSchema = z.object({\n server: HetznerServerSchema,\n});\n\n/**\n * Create server request options schema\n */\nexport const HetznerCreateServerRequestSchema = z\n .object({\n name: z\n .string()\n .min(1)\n .max(64)\n .regex(\n /^[a-zA-Z0-9][a-zA-Z0-9-]*$/,\n \"Name must start with letter/number and contain only letters, numbers, and hyphens\",\n ),\n server_type: z.string().min(1),\n image: z.string().min(1),\n location: z.string().min(1).optional(),\n datacenter: z.string().min(1).optional(),\n ssh_keys: z.array(z.union([z.string(), z.number()])).optional(),\n volumes: z.array(z.number().positive()).optional(),\n labels: z.record(z.string(), z.any()).optional(),\n start_after_create: z.boolean().optional(),\n })\n .refine(\n (data) => !(data.location && data.datacenter),\n \"Cannot specify both location and datacenter\",\n );\n\n/**\n * Create server response schema\n */\nexport const HetznerCreateServerResponseSchema = z.object({\n server: HetznerServerSchema,\n action: HetznerActionSchema,\n next_actions: z.array(HetznerActionSchema),\n root_password: z.string().nullable(),\n});\n\n/**\n * Update server request schema\n */\nexport const HetznerUpdateServerRequestSchema = z.object({\n name: z.string().min(1).max(64).optional(),\n labels: z.record(z.string(), z.any()).optional(),\n});\n\n/**\n * Update server response schema\n */\nexport const HetznerUpdateServerResponseSchema = z.object({\n server: HetznerServerSchema,\n});\n\n// ============================================================================\n// Volume Schemas\n// ============================================================================\n\n/**\n * Volume location schema\n */\nexport const HetznerVolumeLocationSchema = z.object({\n id: z.number(),\n name: z.string(),\n description: z.string(),\n country: z.string(),\n city: z.string(),\n latitude: z.number(),\n longitude: z.number(),\n});\n\n/**\n * Volume protection schema\n */\nexport const HetznerVolumeProtectionSchema = z.object({\n delete: z.boolean(),\n});\n\n/**\n * Volume schema\n */\nexport const HetznerVolumeSchema = z.object({\n id: z.number().positive(),\n name: z.string().min(1),\n status: z.nativeEnum(VolumeStatus),\n server: z.number().positive().nullable().optional(),\n size: z.number().positive(),\n linux_device: z.string().nullable().optional(),\n format: z.string().nullable().optional(),\n location: HetznerVolumeLocationSchema.nullable().optional(),\n labels: z.record(z.string(), z.any()),\n created: z.string().datetime(),\n protection: HetznerVolumeProtectionSchema,\n});\n\n/**\n * List volumes response schema\n */\nexport const HetznerListVolumesResponseSchema = z.object({\n volumes: z.array(HetznerVolumeSchema),\n meta: HetznerMetaSchema,\n});\n\n/**\n * Get volume response schema\n */\nexport const HetznerGetVolumeResponseSchema = z.object({\n volume: HetznerVolumeSchema,\n});\n\n/**\n * Create volume request schema\n */\nexport const HetznerCreateVolumeRequestSchema = z\n .object({\n name: z.string().min(1).max(64),\n size: z.number().positive().multipleOf(1), // GB\n server: z.number().positive().optional(),\n location: z.string().min(1).optional(),\n automount: z.boolean().optional(),\n format: z.string().optional(),\n labels: z.record(z.string(), z.any()).optional(),\n })\n .refine((data) => {\n // Ensure size is a multiple of GB (1, 2, 3, etc.)\n return Number.isInteger(data.size);\n }, \"Volume size must be a whole number in GB\");\n\n/**\n * Create volume response schema\n */\nexport const HetznerCreateVolumeResponseSchema = z.object({\n volume: HetznerVolumeSchema,\n action: HetznerActionSchema,\n next_actions: z.array(HetznerActionSchema),\n});\n\n// ============================================================================\n// Network Schemas\n// ============================================================================\n\n/**\n * Network subnet schema\n */\nexport const HetznerSubnetSchema = z.object({\n type: z.enum([\"server\", \"cloud\", \"vswitch\"]),\n ip_range: z.string().regex(ipRegex),\n network_zone: z.string(),\n gateway: z.string().regex(ipRegex),\n});\n\n/**\n * Network route schema\n */\nexport const HetznerRouteSchema = z.object({\n destination: z.string().regex(ipRegex),\n gateway: z.string().regex(ipRegex),\n});\n\n/**\n * Network protection schema\n */\nexport const HetznerNetworkProtectionSchema = z.object({\n delete: z.boolean(),\n});\n\n/**\n * Network schema\n */\nexport const HetznerNetworkSchema = z.object({\n id: z.number().positive(),\n name: z.string().min(1).max(64),\n ip_range: z.string().regex(ipRegex),\n subnets: z.array(HetznerSubnetSchema),\n routes: z.array(HetznerRouteSchema),\n servers: z.array(z.number().positive()),\n protection: HetznerNetworkProtectionSchema,\n labels: z.record(z.string(), z.any()),\n created: z.string().datetime(),\n});\n\n/**\n * List networks response schema\n */\nexport const HetznerListNetworksResponseSchema = z.object({\n networks: z.array(HetznerNetworkSchema),\n meta: HetznerMetaSchema,\n});\n\n/**\n * Get network response schema\n */\nexport const HetznerGetNetworkResponseSchema = z.object({\n network: HetznerNetworkSchema,\n});\n\n// ============================================================================\n// SSH Key Schemas\n// ============================================================================\n\n/**\n * SSH key schema\n */\nexport const HetznerSSHKeySchema = z.object({\n id: z.number().positive(),\n name: z.string().min(1).max(64),\n fingerprint: z.string(),\n public_key: z.string(),\n labels: z.record(z.string(), z.any()),\n created: z.string().datetime(),\n});\n\n/**\n * List SSH keys response schema\n */\nexport const HetznerListSSHKeysResponseSchema = z.object({\n ssh_keys: z.array(HetznerSSHKeySchema),\n meta: HetznerMetaSchema,\n});\n\n/**\n * Get SSH key response schema\n */\nexport const HetznerGetSSHKeyResponseSchema = z.object({\n ssh_key: HetznerSSHKeySchema,\n});\n\n/**\n * Create SSH key request schema\n */\nexport const HetznerCreateSSHKeyRequestSchema = z.object({\n name: z\n .string()\n .min(1)\n .max(64)\n .regex(\n /^[a-zA-Z0-9][a-zA-Z0-9-]*$/,\n \"Name must start with letter/number and contain only letters, numbers, and hyphens\",\n ),\n public_key: z.string().min(1),\n labels: z.record(z.string(), z.any()).optional(),\n});\n\n/**\n * Create SSH key response schema\n */\nexport const HetznerCreateSSHKeyResponseSchema = z.object({\n ssh_key: HetznerSSHKeySchema,\n});\n\n// ============================================================================\n// Floating IP Schemas\n// ============================================================================\n\n/**\n * Floating IP schema\n */\nexport const HetznerFloatingIpSchema = z.object({\n id: z.number().positive(),\n name: z.string().min(1).max(64),\n description: z.string().optional(),\n type: z.enum([\"ipv4\", \"ipv6\"]),\n ip: z.string().regex(ipRegex),\n server: z.number().positive().nullable(),\n dns_ptr: z.array(\n z.object({\n ip: z.string(),\n dns_ptr: z.string(),\n }),\n ),\n home_location: HetznerLocationSchema,\n blocked: z.boolean(),\n protection: z.object({\n delete: z.boolean(),\n }),\n labels: z.record(z.string(), z.any()),\n created: z.string().datetime(),\n});\n\n/**\n * List floating IPs response schema\n */\nexport const HetznerListFloatingIpsResponseSchema = z.object({\n floating_ips: z.array(HetznerFloatingIpSchema),\n meta: HetznerMetaSchema,\n});\n\n// ============================================================================\n// Firewall Schemas\n// ============================================================================\n\n/**\n * Firewall rule schema\n */\nexport const HetznerFirewallRuleSchema = z.object({\n direction: z.enum([\"in\", \"out\"]),\n source_ips: z.array(z.string().regex(ipRegex)).optional(),\n destination_ips: z.array(z.string().regex(ipRegex)).optional(),\n source_port: z.string().optional(),\n destination_port: z.string().optional(),\n protocol: z.enum([\"tcp\", \"udp\", \"icmp\", \"esp\", \"gre\"]),\n});\n\n/**\n * Firewall resource schema\n */\nexport const HetznerFirewallResourceSchema = z.object({\n type: z.enum([\"server\", \"label_selector\"]),\n server: z\n .object({\n id: z.number().positive(),\n })\n .optional(),\n label_selector: z\n .object({\n selector: z.string(),\n })\n .optional(),\n});\n\n/**\n * Firewall schema\n */\nexport const HetznerFirewallSchema = z.object({\n id: z.number().positive(),\n name: z.string().min(1).max(64),\n rules: z.array(HetznerFirewallRuleSchema),\n apply_to: z.array(HetznerFirewallResourceSchema),\n labels: z.record(z.string(), z.any()),\n created: z.string().datetime(),\n});\n\n/**\n * List firewalls response schema\n */\nexport const HetznerListFirewallsResponseSchema = z.object({\n firewalls: z.array(HetznerFirewallSchema),\n meta: HetznerMetaSchema,\n});\n\n// ============================================================================\n// ISO Schemas\n// ============================================================================\n\n/**\n * ISO schema\n */\nexport const HetznerIsoSchema = z.object({\n id: z.number().positive(),\n name: z.string(),\n description: z.string(),\n type: z.enum([\"public\", \"private\"]),\n deprecated: z.date().nullable().optional(),\n architecture: z.array(z.enum([\"x86\", \"arm\"])).optional(),\n});\n\n/**\n * List ISOs response schema\n */\nexport const HetznerListIsosResponseSchema = z.object({\n isos: z.array(HetznerIsoSchema),\n meta: HetznerMetaSchema,\n});\n\n// ============================================================================\n// Location Schemas\n// ============================================================================\n\n/**\n * List locations response schema\n */\nexport const HetznerListLocationsResponseSchema = z.object({\n locations: z.array(HetznerLocationSchema),\n});\n\n// ============================================================================\n// Datacenter Schemas\n// ============================================================================\n\n/**\n * List datacenters response schema\n */\nexport const HetznerListDatacentersResponseSchema = z.object({\n datacenters: z.array(HetznerDatacenterSchema),\n});\n\n// ============================================================================\n// Server Type Schemas\n// ============================================================================\n\n/**\n * Server type pricing schema\n *\n * Note: location can be null or absent in some Hetzner API responses\n */\nexport const HetznerServerTypePricingSchema = z.object({\n location: z.string().nullable().optional(),\n price_hourly: z.object({\n net: z.string(),\n gross: z.string(),\n }),\n price_monthly: z.object({\n net: z.string(),\n gross: z.string(),\n }),\n});\n\n/**\n * Extended server type schema (for listing)\n */\nexport const HetznerServerTypeExtendedSchema = HetznerServerTypeSchema.extend({\n deprecated: z.boolean().optional(),\n prices: z.array(HetznerServerTypePricingSchema),\n storage_type: z.enum([\"local\", \"network\"]),\n cpu_type: z.enum([\"shared\", \"dedicated\"]),\n});\n\n/**\n * List server types response schema\n */\nexport const HetznerListServerTypesResponseSchema = z.object({\n server_types: z.array(HetznerServerTypeExtendedSchema),\n});\n\n// ============================================================================\n// Certificate Schemas\n// ============================================================================\n\n/**\n * Certificate schema\n */\nexport const HetznerCertificateSchema = z.object({\n id: z.number().positive(),\n name: z.string().min(1).max(64),\n labels: z.record(z.string(), z.any()),\n certificate: z.string(),\n not_valid_before: z.string().datetime(),\n not_valid_after: z.string().datetime(),\n domain_names: z.array(z.string().url()),\n fingerprint: z.string(),\n created: z.string().datetime(),\n status: z.enum([\"pending\", \"issued\", \"failed\", \"revoked\"]),\n failed: z.boolean().optional(),\n type: z.enum([\"uploaded\", \"managed\"]),\n usage: z\n .array(z.enum([\"dual_stack\", \"server\", \"load_balancer\", \"dns\"]))\n .optional(),\n});\n\n/**\n * List certificates response schema\n */\nexport const HetznerListCertificatesResponseSchema = z.object({\n certificates: z.array(HetznerCertificateSchema),\n meta: HetznerMetaSchema,\n});\n\n// ============================================================================\n// Generic Response Wrappers\n// ============================================================================\n\n/**\n * Generic paginated response schema\n */\nexport function createPaginatedResponseSchema<T extends z.ZodType>(\n itemSchema: T,\n itemName: string,\n) {\n return z.object({\n [itemName]: z.array(itemSchema),\n meta: HetznerMetaSchema,\n });\n}\n\n/**\n * Generic single item response schema\n */\nexport function createItemResponseSchema<T extends z.ZodType>(\n itemSchema: T,\n itemName: string,\n) {\n return z.object({\n [itemName]: itemSchema,\n });\n}\n",
|
|
9
|
+
"/**\n * Hetzner Cloud API types\n */\n\n// ============================================================================\n// Import shared status enums\n// ============================================================================\n\nimport {\n EnvironmentStatus,\n ActionStatus,\n VolumeStatus,\n} from \"@ebowwa/codespaces-types/compile\";\n\n// Re-export for convenience\nexport { EnvironmentStatus, ActionStatus, VolumeStatus };\n\n// ============================================================================\n// Server Types\n// ============================================================================\n\nexport interface HetznerServer {\n id: number;\n name: string;\n status: EnvironmentStatus;\n image?: {\n id: number;\n name: string;\n description: string;\n type: \"snapshot\" | \"backup\" | \"system\";\n } | null;\n public_net: {\n ipv4: {\n ip: string;\n blocked: boolean;\n };\n ipv6?: {\n ip: string;\n blocked: boolean;\n };\n floating_ips: Array<{\n id: number;\n ip: string;\n }>;\n firewalls: Array<{\n id: number;\n name: string;\n status: \"applied\" | \"pending\";\n }>;\n };\n server_type: {\n id: number;\n name: string;\n description: string;\n cores: number;\n memory: number;\n disk: number;\n };\n datacenter: {\n id: number;\n name: string;\n description: string;\n location: {\n id: number;\n name: string;\n description: string;\n country: string;\n city: string;\n latitude: number;\n longitude: number;\n network_zone: string;\n };\n supported_server_types?: Array<{\n id: number;\n name: string;\n }> | null;\n };\n labels: Record<string, string>;\n created: string;\n protection: {\n delete: boolean;\n rebuild: boolean;\n };\n volumes: Array<{\n id: number;\n name: string;\n size: number;\n linux_device: string;\n }>;\n}\n\nexport interface CreateServerOptions {\n name: string;\n server_type?: string;\n image?: string;\n location?: string;\n datacenter?: string;\n ssh_keys?: Array<string | number>;\n volumes?: number[];\n labels?: Record<string, string>;\n start_after_create?: boolean;\n /** Cloud-init user data script for first-boot provisioning */\n user_data?: string;\n}\n\nexport interface UpdateServerOptions {\n name?: string;\n labels?: Record<string, string>;\n}\n\n// ============================================================================\n// Action Types\n// ============================================================================\n\n/**\n * Action command types from Hetzner Cloud API\n */\nexport enum ActionCommand {\n // Server actions\n CreateServer = \"create_server\",\n DeleteServer = \"delete_server\",\n StartServer = \"start_server\",\n StopServer = \"stop_server\",\n RebootServer = \"reboot_server\",\n ResetServer = \"reset_server\",\n ShutdownServer = \"shutdown_server\",\n Poweroff = \"poweroff\",\n ChangeServerType = \"change_server_type\",\n RebuildServer = \"rebuild_server\",\n EnableBackup = \"enable_backup\",\n DisableBackup = \"disable_backup\",\n CreateImage = \"create_image\",\n ChangeDnsPtr = \"change_dns_ptr\",\n AttachToNetwork = \"attach_to_network\",\n DetachFromNetwork = \"detach_from_network\",\n ChangeAliasIps = \"change_alias_ips\",\n EnableRescue = \"enable_rescue\",\n DisableRescue = \"disable_rescue\",\n ChangeProtection = \"change_protection\",\n\n // Volume actions\n CreateVolume = \"create_volume\",\n DeleteVolume = \"delete_volume\",\n AttachVolume = \"attach_volume\",\n DetachVolume = \"detach_volume\",\n ResizeVolume = \"resize_volume\",\n VolumeChangeProtection = \"volume_change_protection\",\n\n // Network actions\n AddSubnet = \"add_subnet\",\n DeleteSubnet = \"delete_subnet\",\n AddRoute = \"add_route\",\n DeleteRoute = \"delete_route\",\n ChangeIpRange = \"change_ip_range\",\n NetworkChangeProtection = \"network_change_protection\",\n\n // Floating IP actions\n AssignFloatingIp = \"assign_floating_ip\",\n UnassignFloatingIp = \"unassign_floating_ip\",\n FloatingIpChangeDnsPtr = \"floating_ip_change_dns_ptr\",\n FloatingIpChangeProtection = \"floating_ip_change_protection\",\n\n // Load Balancer actions\n CreateLoadBalancer = \"create_load_balancer\",\n DeleteLoadBalancer = \"delete_load_balancer\",\n AddTarget = \"add_target\",\n RemoveTarget = \"remove_target\",\n AddService = \"add_service\",\n UpdateService = \"update_service\",\n DeleteService = \"delete_service\",\n LoadBalancerAttachToNetwork = \"load_balancer_attach_to_network\",\n LoadBalancerDetachFromNetwork = \"load_balancer_detach_from_network\",\n ChangeAlgorithm = \"change_algorithm\",\n ChangeType = \"change_type\",\n LoadBalancerChangeProtection = \"load_balancer_change_protection\",\n\n // Certificate actions\n IssueCertificate = \"issue_certificate\",\n RetryCertificate = \"retry_certificate\",\n\n // Firewall actions\n SetFirewallRules = \"set_firewall_rules\",\n ApplyFirewall = \"apply_firewall\",\n RemoveFirewall = \"remove_firewall\",\n FirewallChangeProtection = \"firewall_change_protection\",\n\n // Image actions\n ImageChangeProtection = \"image_change_protection\",\n}\n\n/**\n * Resource types that can be affected by actions\n */\nexport enum ResourceType {\n Server = \"server\",\n Volume = \"volume\",\n Network = \"network\",\n FloatingIp = \"floating_ip\",\n LoadBalancer = \"load_balancer\",\n Certificate = \"certificate\",\n Firewall = \"firewall\",\n Image = \"image\",\n}\n\n/**\n * Action resource reference\n */\nexport interface ActionResource {\n id: number;\n type: ResourceType;\n}\n\n/**\n * Action error details\n */\nexport interface ActionError {\n code: string;\n message: string;\n}\n\n/**\n * Base Hetzner Action type matching the API response\n *\n * The API returns actions with:\n * - status: \"running\" | \"success\" | \"error\"\n * - finished: string | null (null when running)\n * - error: ActionError | null (null when not error)\n *\n * Note: Zod validation makes finished and error optional, but the API\n * typically returns them. Use type guards for runtime checks.\n */\nexport interface HetznerAction {\n id: number;\n command: ActionCommand | string; // API returns string\n status: ActionStatus;\n started: string;\n finished?: string | null;\n progress: number;\n resources: ActionResource[];\n error?: ActionError | null;\n}\n\n/**\n * Server action response (includes server reference)\n */\nexport interface ServerActionResponse {\n action: HetznerAction;\n server?: HetznerServer;\n}\n\n/**\n * Create server response with actions\n */\nexport interface CreateServerResponse {\n server: HetznerServer;\n action: HetznerAction;\n next_actions: HetznerAction[];\n root_password: string | null;\n}\n\n// ============================================================================\n// Volume Types\n// ============================================================================\n\nexport interface HetznerVolume {\n id: number;\n name: string;\n status: VolumeStatus;\n server?: number | null;\n size: number;\n linux_device?: string | null;\n format?: string | null;\n location?: {\n id: number;\n name: string;\n description: string;\n country: string;\n city: string;\n latitude: number;\n longitude: number;\n } | null;\n labels: Record<string, any>;\n created: string;\n protection: {\n delete: boolean;\n };\n}\n\nexport interface CreateVolumeOptions {\n name: string;\n size: number;\n server?: number;\n location?: string;\n format?: string;\n automount?: boolean;\n labels?: Record<string, string>;\n}\n\n// ============================================================================\n// Network Types\n// ============================================================================\n\nexport interface HetznerNetwork {\n id: number;\n name: string;\n ip_range: string;\n subnets: Array<{\n type: \"server\" | \"cloud\" | \"vswitch\";\n ip_range: string;\n network_zone: string;\n gateway: string;\n }>;\n routes: Array<{\n destination: string;\n gateway: string;\n }>;\n servers: number[];\n protection: {\n delete: boolean;\n };\n labels: Record<string, string>;\n created: string;\n}\n\n// ============================================================================\n// SSH Key Types\n// ============================================================================\n\nexport interface HetznerSSHKey {\n id: number;\n name: string;\n fingerprint: string;\n public_key: string;\n labels: Record<string, string>;\n created: string;\n}\n\nexport interface CreateSSHKeyOptions {\n name: string;\n public_key: string;\n labels?: Record<string, string>;\n}\n\n// ============================================================================\n// Rate Limiting Types\n// ============================================================================\n\nexport interface RateLimitInfo {\n limit: number;\n remaining: number;\n reset: number; // Unix timestamp\n}\n\nexport interface RateLimitHeaders {\n \"RateLimit-Limit\": string;\n \"RateLimit-Remaining\": string;\n \"RateLimit-Reset\": string;\n}\n\n// ============================================================================\n// Polling Options\n// ============================================================================\n\nexport interface ActionPollingOptions {\n /** Polling interval in milliseconds (default: 2000) */\n pollInterval?: number;\n /** Maximum number of polling attempts (default: 60) */\n maxRetries?: number;\n /** Optional callback for progress updates */\n onProgress?: (action: HetznerAction) => void;\n /** Optional timeout in milliseconds */\n timeout?: number;\n}\n\n// ============================================================================\n// Import shared Hetzner types for local use\n// ============================================================================\n\nimport type {\n HetznerServerType,\n HetznerLocation,\n HetznerDatacenter,\n} from \"@ebowwa/codespaces-types/compile\";\n\n// ============================================================================\n// Re-export shared Hetzner types\n// ============================================================================\n\nexport type { HetznerServerType, HetznerLocation, HetznerDatacenter };\n",
|
|
10
|
+
"/**\n * Hetzner Cloud API error types and utilities\n */\n\nimport type { RateLimitInfo, ActionError } from \"./types.js\";\n\n// Re-export ActionError for convenience\nexport type { ActionError };\n\n// ============================================================================\n// Error Codes\n// ============================================================================\n\n/**\n * Hetzner API error codes\n * @see https://docs.hetzner.cloud/#errors\n */\nexport enum HetznerErrorCode {\n // Authentication errors\n Unauthorized = \"unauthorized\",\n InvalidInput = \"invalid_input\",\n JSONError = \"json_error\",\n Forbidden = \"forbidden\",\n\n // Resource errors\n NotFound = \"not_found\",\n ResourceLocked = \"locked\",\n ResourceLimitExceeded = \"resource_limit_exceeded\",\n UniquenessError = \"uniqueness_error\",\n\n // Rate limiting\n RateLimitExceeded = \"rate_limit_exceeded\",\n\n // Conflict errors\n Conflict = \"conflict\",\n ServiceError = \"service_error\",\n\n // Server-specific errors\n ServerNotStopped = \"server_not_stopped\",\n ServerAlreadyStopped = \"server_already_stopped\",\n InvalidServerType = \"invalid_server_type\",\n\n // IP/network errors\n IpNotOwned = \"ip_not_owned\",\n IpAlreadyAssigned = \"ip_already_assigned\",\n\n // Volume errors\n VolumeAlreadyAttached = \"volume_already_attached\",\n VolumeSizeNotMultiple = \"volume_size_not_multiple\",\n\n // Firewall errors\n FirewallInUse = \"firewall_in_use\",\n\n // Certificate errors\n CertificateValidationFailed = \"certificate_validation_failed\",\n CertificatePending = \"certificate_pending\",\n}\n\n// ============================================================================\n// Error Classes\n// ============================================================================\n\n/**\n * Base Hetzner API error\n */\nexport class HetznerAPIError extends Error {\n constructor(\n message: string,\n public code?: string,\n public details?: unknown\n ) {\n super(message);\n this.name = \"HetznerAPIError\";\n }\n}\n\n/**\n * Authentication error (401)\n */\nexport class HetznerUnauthorizedError extends HetznerAPIError {\n constructor(message: string = \"Unauthorized: Invalid API token\") {\n super(message, HetznerErrorCode.Unauthorized);\n this.name = \"HetznerUnauthorizedError\";\n }\n}\n\n/**\n * Forbidden error (403)\n */\nexport class HetznerForbiddenError extends HetznerAPIError {\n constructor(message: string = \"Forbidden: Insufficient permissions\") {\n super(message, HetznerErrorCode.Forbidden);\n this.name = \"HetznerForbiddenError\";\n }\n}\n\n/**\n * Resource not found error (404)\n */\nexport class HetznerNotFoundError extends HetznerAPIError {\n constructor(resource: string, id: number | string) {\n super(\n `${resource} with ID ${id} not found`,\n HetznerErrorCode.NotFound,\n { resource, id }\n );\n this.name = \"HetznerNotFoundError\";\n }\n}\n\n/**\n * Rate limit exceeded error (429)\n */\nexport class HetznerRateLimitError extends HetznerAPIError {\n constructor(\n message: string = \"Rate limit exceeded\",\n public rateLimitInfo?: RateLimitInfo\n ) {\n super(message, HetznerErrorCode.RateLimitExceeded, rateLimitInfo);\n this.name = \"HetznerRateLimitError\";\n }\n\n /**\n * Get the number of milliseconds until the rate limit resets\n */\n get resetInMs(): number {\n if (!this.rateLimitInfo) return 60000; // Default to 1 minute\n return Math.max(0, this.rateLimitInfo.reset * 1000 - Date.now());\n }\n\n /**\n * Get a human-readable reset time\n */\n get resetTime(): string {\n if (!this.rateLimitInfo) return \"unknown\";\n return new Date(this.rateLimitInfo.reset * 1000).toISOString();\n }\n}\n\n/**\n * Resource locked error\n */\nexport class HetznerResourceLockedError extends HetznerAPIError {\n constructor(\n resource: string,\n id: number | string,\n public actionInProgress?: string\n ) {\n super(\n `${resource} ${id} is locked${actionInProgress ? ` by ${actionInProgress}` : \"\"}`,\n HetznerErrorCode.ResourceLocked,\n { resource, id, actionInProgress }\n );\n this.name = \"HetznerResourceLockedError\";\n }\n}\n\n/**\n * Resource limit exceeded error\n */\nexport class HetznerResourceLimitError extends HetznerAPIError {\n constructor(resource: string, limit: number) {\n super(\n `Resource limit exceeded: ${resource} (limit: ${limit})`,\n HetznerErrorCode.ResourceLimitExceeded,\n { resource, limit }\n );\n this.name = \"HetznerResourceLimitError\";\n }\n}\n\n/**\n * Invalid input error\n */\nexport class HetznerInvalidInputError extends HetznerAPIError {\n constructor(\n message: string,\n public fields?: Record<string, string>\n ) {\n super(message, HetznerErrorCode.InvalidInput, { fields });\n this.name = \"HetznerInvalidInputError\";\n }\n}\n\n/**\n * Conflict error\n */\nexport class HetznerConflictError extends HetznerAPIError {\n constructor(message: string, details?: unknown) {\n super(message, HetznerErrorCode.Conflict, details);\n this.name = \"HetznerConflictError\";\n }\n}\n\n/**\n * Service error (5xx)\n */\nexport class HetznerServiceError extends HetznerAPIError {\n constructor(message: string, public statusCode?: number) {\n super(message, HetznerErrorCode.ServiceError, { statusCode });\n this.name = \"HetznerServiceError\";\n }\n}\n\n/**\n * Action failed error\n */\nexport class HetznerActionError extends HetznerAPIError {\n constructor(\n public actionError: ActionError,\n public actionId: number\n ) {\n super(\n `Action ${actionId} failed: ${actionError.code} - ${actionError.message}`,\n actionError.code,\n { actionError, actionId }\n );\n this.name = \"HetznerActionError\";\n }\n}\n\n/**\n * Timeout error for action polling\n */\nexport class HetznerTimeoutError extends HetznerAPIError {\n constructor(\n actionId: number,\n timeout: number,\n public lastProgress: number\n ) {\n super(\n `Action ${actionId} timed out after ${timeout}ms (last progress: ${lastProgress}%)`,\n \"timeout\",\n { actionId, timeout, lastProgress }\n );\n this.name = \"HetznerTimeoutError\";\n }\n}\n\n// ============================================================================\n// Error Factory\n// ============================================================================\n\n/**\n * Parse Hetzner API error response and create appropriate error\n */\nexport function createHetznerError(\n statusCode: number,\n body: {\n error?: {\n code: string;\n message: string;\n details?: unknown;\n };\n }\n): HetznerAPIError {\n const error = body.error;\n\n if (!error) {\n return new HetznerServiceError(\n `HTTP ${statusCode}: ${JSON.stringify(body)}`,\n statusCode\n );\n }\n\n switch (statusCode) {\n case 401:\n return new HetznerUnauthorizedError(error.message);\n case 403:\n return new HetznerForbiddenError(error.message);\n case 404:\n return new HetznerNotFoundError(\"resource\", \"unknown\");\n case 429:\n return new HetznerRateLimitError(error.message);\n case 400:\n if (error.code === HetznerErrorCode.ResourceLocked) {\n return new HetznerResourceLockedError(\n \"resource\",\n \"unknown\",\n error.message\n );\n }\n if (error.code === HetznerErrorCode.InvalidInput) {\n return new HetznerInvalidInputError(error.message);\n }\n return new HetznerInvalidInputError(error.message);\n case 409:\n return new HetznerConflictError(error.message, error.details);\n default:\n if (statusCode >= 500) {\n return new HetznerServiceError(error.message, statusCode);\n }\n return new HetznerAPIError(error.message, error.code, error.details);\n }\n}\n\n/**\n * Check if an error is retryable\n */\nexport function isRetryableError(error: unknown): boolean {\n if (error instanceof HetznerRateLimitError) return true;\n if (error instanceof HetznerResourceLockedError) return true;\n if (error instanceof HetznerServiceError) return true;\n if (error instanceof HetznerConflictError) return true;\n return false;\n}\n\n/**\n * Check if an error is a rate limit error\n */\nexport function isRateLimitError(error: unknown): error is HetznerRateLimitError {\n return error instanceof HetznerRateLimitError;\n}\n\n/**\n * Check if an error is a resource locked error\n */\nexport function isResourceLockedError(\n error: unknown\n): error is HetznerResourceLockedError {\n return error instanceof HetznerResourceLockedError;\n}\n\n/**\n * Calculate retry delay with exponential backoff\n */\nexport function calculateRetryDelay(\n attempt: number,\n baseDelay: number = 1000,\n maxDelay: number = 60000\n): number {\n const delay = baseDelay * Math.pow(2, attempt);\n // Add jitter (±25%)\n const jitter = delay * 0.25 * (Math.random() * 2 - 1);\n return Math.min(maxDelay, delay + jitter);\n}\n\n// ============================================================================\n// Error Handler Types\n// ============================================================================\n\n/**\n * Error handler function type\n */\nexport type ErrorHandler = (error: HetznerAPIError) => void | Promise<void>;\n\n/**\n * Error handler options\n */\nexport interface ErrorHandlerContext {\n /** Maximum number of retry attempts */\n maxRetries?: number;\n /** Base delay for exponential backoff in milliseconds */\n baseDelay?: number;\n /** Maximum delay between retries in milliseconds */\n maxDelay?: number;\n /** Optional error handler callback */\n onError?: ErrorHandler;\n /** Whether to log errors */\n logErrors?: boolean;\n}\n\n/**\n * Default error handler that logs to console\n */\nexport function defaultErrorHandler(error: HetznerAPIError): void {\n console.error(`[Hetzner API Error] ${error.name}: ${error.message}`);\n if (error.details) {\n console.error(\"Details:\", error.details);\n }\n}\n",
|
|
11
|
+
"/**\n * Hetzner Cloud API action polling and management\n *\n * Provides a robust polling service for monitoring async Hetzner actions\n * with progress tracking, error handling, and cancellation support.\n */\n\nimport type { HetznerClient } from \"./client.js\";\nimport type {\n HetznerAction,\n ActionPollingOptions,\n RateLimitInfo,\n} from \"./types.js\";\nimport {\n ActionStatus,\n ActionCommand,\n} from \"./types.js\";\nimport {\n HetznerActionError,\n HetznerTimeoutError,\n isRetryableError,\n calculateRetryDelay,\n type ErrorHandler,\n} from \"./errors.js\";\n\n// ============================================================================\n// Enhanced Polling Options\n// ============================================================================\n\n/**\n * Enhanced options for action polling with more granular control\n */\nexport interface EnhancedActionPollingOptions {\n /** Polling interval in milliseconds (default: 2000) */\n pollInterval?: number;\n /** Maximum number of polling attempts before timeout */\n maxRetries?: number;\n /** Maximum time to wait in milliseconds before timeout */\n timeout?: number;\n /** Callback fired on each progress update */\n onProgress?: (action: HetznerAction) => void;\n /** Callback fired when action completes successfully */\n onComplete?: (action: HetznerAction) => void;\n /** Callback fired when action fails */\n onError?: (error: HetznerActionError, action: HetznerAction) => void;\n /** Callback fired on each retry attempt */\n onRetry?: (attempt: number, delay: number) => void;\n /** Abort signal for cancellation */\n signal?: AbortSignal;\n /** Whether to use adaptive polling intervals (default: false) */\n adaptive?: boolean;\n /** Concurrency limit for multiple actions (default: 5) */\n concurrency?: number;\n}\n\n/**\n * Result of a polling operation\n */\nexport interface PollingResult<T = HetznerAction> {\n /** Whether the operation completed successfully */\n success: boolean;\n /** The final action state (if successful) */\n action?: HetznerAction;\n /** Error that occurred (if failed) */\n error?: Error;\n /** Number of polling attempts made */\n attempts: number;\n /** Total time elapsed in milliseconds */\n elapsed: number;\n}\n\n/**\n * Result for batch polling operations\n */\nexport interface BatchPollingResult {\n /** Map of action ID to result */\n results: Map<number, PollingResult>;\n /** Count of successful actions */\n successful: number;\n /** Count of failed actions */\n failed: number;\n /** Total time elapsed in milliseconds */\n elapsed: number;\n}\n\n// ============================================================================\n// Action Operations Class\n// ============================================================================\n\n/**\n * Action operations for the Hetzner Cloud API\n *\n * Provides methods for managing and polling actions with enhanced\n * polling capabilities including cancellation, progress tracking,\n * and batch operations.\n */\nexport class ActionOperations {\n constructor(private client: HetznerClient) {}\n\n /**\n * Get a specific action by ID\n *\n * @param id - Action ID\n * @returns Action details\n */\n async get(id: number): Promise<HetznerAction> {\n const response = await this.client.request<{ action: HetznerAction }>(\n `/actions/${id}`\n );\n return response.action;\n }\n\n /**\n * List all actions\n *\n * @param options - Optional filters (status, sort, server_id, etc.)\n * @returns Array of actions\n */\n async list(options?: {\n status?: ActionStatus;\n sort?: string;\n page?: number;\n per_page?: number;\n server_id?: number;\n }): Promise<HetznerAction[]> {\n const params = new URLSearchParams();\n if (options?.status) params.append(\"status\", options.status);\n if (options?.sort) params.append(\"sort\", options.sort);\n if (options?.page) params.append(\"page\", options.page.toString());\n if (options?.per_page)\n params.append(\"per_page\", options.per_page.toString());\n if (options?.server_id)\n params.append(\"server_id\", options.server_id.toString());\n\n const query = params.toString();\n const response = await this.client.request<{ actions: HetznerAction[] }>(\n `/actions${query ? `?${query}` : \"\"}`\n );\n return response.actions;\n }\n\n /**\n * Poll a single action until completion (enhanced version)\n *\n * This is the main polling service method with full feature support:\n * - Progress tracking with onProgress callback\n * - Success/failure callbacks\n * - Cancellation via AbortSignal\n * - Adaptive polling intervals\n * - Comprehensive error handling\n *\n * @param actionId - Action ID to poll\n * @param options - Polling options\n * @returns Promise resolving to the completed action\n *\n * @example\n * ```typescript\n * const action = await client.actions.poll(123, {\n * onProgress: (a) => console.log(`Progress: ${a.progress}%`),\n * onComplete: (a) => console.log('Done!'),\n * onError: (e) => console.error('Failed:', e.message),\n * timeout: 300000, // 5 minutes\n * signal: abortController.signal\n * });\n * ```\n */\n async poll(\n actionId: number,\n options: EnhancedActionPollingOptions = {}\n ): Promise<HetznerAction> {\n return pollAction(this.client, actionId, options);\n }\n\n /**\n * Poll multiple actions until completion\n *\n * Handles concurrent polling of multiple actions with optional\n * concurrency limit and individual action tracking.\n *\n * @param actionIds - Array of action IDs to poll\n * @param options - Polling options\n * @returns Promise resolving to array of completed actions\n *\n * @example\n * ```typescript\n * const actions = await client.actions.pollMany([1, 2, 3], {\n * onProgress: (a) => updateUI(a),\n * concurrency: 3, // Poll 3 at a time\n * signal: abortController.signal\n * });\n * ```\n */\n async pollMany(\n actionIds: number[],\n options: EnhancedActionPollingOptions = {}\n ): Promise<HetznerAction[]> {\n return pollActions(this.client, actionIds, options);\n }\n\n /**\n * Poll multiple actions with detailed result tracking\n *\n * Returns a BatchPollingResult with success/failure counts and\n * per-action results for better error handling.\n *\n * @param actionIds - Array of action IDs to poll\n * @param options - Polling options\n * @returns Batch polling result with detailed status\n *\n * @example\n * ```typescript\n * const result = await client.actions.pollManyDetailed([1, 2, 3], {\n * concurrency: 2\n * });\n * console.log(`Success: ${result.successful}, Failed: ${result.failed}`);\n * for (const [id, r] of result.results) {\n * if (r.error) console.error(`Action ${id} failed:`, r.error);\n * }\n * ```\n */\n async pollManyDetailed(\n actionIds: number[],\n options: EnhancedActionPollingOptions = {}\n ): Promise<BatchPollingResult> {\n return pollActionsDetailed(this.client, actionIds, options);\n }\n\n /**\n * Wait for an action to complete (backward compatible alias)\n *\n * @param id - Action ID\n * @param options - Polling options\n * @returns Completed action\n * @deprecated Use poll() instead for new code\n */\n async waitFor(\n id: number,\n options?: ActionPollingOptions\n ): Promise<HetznerAction> {\n return waitForAction(this.client, id, options);\n }\n\n /**\n * Wait for multiple actions to complete (backward compatible alias)\n *\n * @param ids - Array of action IDs\n * @param options - Polling options\n * @returns Array of completed actions\n * @deprecated Use pollMany() instead for new code\n */\n async waitForMany(\n ids: number[],\n options?: ActionPollingOptions\n ): Promise<HetznerAction[]> {\n return waitForMultipleActions(this.client, ids, options);\n }\n\n /**\n * Batch check multiple actions (no polling, single fetch)\n *\n * @param ids - Array of action IDs\n * @returns Map of action ID to action\n */\n async batchCheck(\n ids: number[]\n ): Promise<Map<number, HetznerAction>> {\n return batchCheckActions(this.client, ids);\n }\n}\n\n// ============================================================================\n// Action Timeouts\n// ============================================================================\n\n/**\n * Default timeouts for different action types (in milliseconds)\n * Adjusted based on typical operation durations\n */\nexport const ACTION_TIMEOUTS: Record<ActionCommand, number> = {\n // Quick operations (under 1 minute)\n [ActionCommand.StartServer]: 60000,\n [ActionCommand.StopServer]: 60000,\n [ActionCommand.RebootServer]: 120000,\n [ActionCommand.Poweroff]: 60000,\n [ActionCommand.ShutdownServer]: 60000,\n [ActionCommand.ResetServer]: 60000,\n\n // Medium operations (1-5 minutes)\n [ActionCommand.CreateServer]: 300000,\n [ActionCommand.DeleteServer]: 180000,\n [ActionCommand.ChangeServerType]: 600000,\n [ActionCommand.ChangeDnsPtr]: 30000,\n\n // Long operations (5-30 minutes)\n [ActionCommand.RebuildServer]: 900000,\n [ActionCommand.CreateImage]: 1800000,\n [ActionCommand.EnableRescue]: 120000,\n [ActionCommand.DisableRescue]: 60000,\n\n // Volume operations\n [ActionCommand.CreateVolume]: 300000,\n [ActionCommand.DeleteVolume]: 180000,\n [ActionCommand.AttachVolume]: 120000,\n [ActionCommand.DetachVolume]: 60000,\n [ActionCommand.ResizeVolume]: 600000,\n\n // Network operations\n [ActionCommand.AddSubnet]: 60000,\n [ActionCommand.DeleteSubnet]: 60000,\n [ActionCommand.AddRoute]: 60000,\n [ActionCommand.DeleteRoute]: 60000,\n [ActionCommand.ChangeIpRange]: 120000,\n [ActionCommand.AttachToNetwork]: 60000,\n [ActionCommand.DetachFromNetwork]: 60000,\n\n // Floating IP operations\n [ActionCommand.AssignFloatingIp]: 60000,\n [ActionCommand.UnassignFloatingIp]: 60000,\n\n // Load Balancer operations\n [ActionCommand.CreateLoadBalancer]: 300000,\n [ActionCommand.DeleteLoadBalancer]: 180000,\n [ActionCommand.AddTarget]: 60000,\n [ActionCommand.RemoveTarget]: 60000,\n [ActionCommand.AddService]: 60000,\n [ActionCommand.UpdateService]: 60000,\n [ActionCommand.DeleteService]: 60000,\n [ActionCommand.LoadBalancerAttachToNetwork]: 60000,\n [ActionCommand.LoadBalancerDetachFromNetwork]: 60000,\n [ActionCommand.ChangeAlgorithm]: 60000,\n [ActionCommand.ChangeType]: 60000,\n\n // Certificate operations\n [ActionCommand.IssueCertificate]: 600000, // Can take up to 10 minutes\n [ActionCommand.RetryCertificate]: 600000,\n\n // Firewall operations\n [ActionCommand.SetFirewallRules]: 60000,\n [ActionCommand.ApplyFirewall]: 120000,\n [ActionCommand.RemoveFirewall]: 60000,\n\n // Floating IP DNS\n [ActionCommand.FloatingIpChangeDnsPtr]: 30000,\n\n // Backup operations\n [ActionCommand.EnableBackup]: 60000,\n [ActionCommand.DisableBackup]: 60000,\n\n // Protection operations\n [ActionCommand.ChangeProtection]: 30000,\n [ActionCommand.VolumeChangeProtection]: 30000,\n [ActionCommand.NetworkChangeProtection]: 30000,\n [ActionCommand.FloatingIpChangeProtection]: 30000,\n [ActionCommand.LoadBalancerChangeProtection]: 30000,\n [ActionCommand.FirewallChangeProtection]: 30000,\n [ActionCommand.ImageChangeProtection]: 30000,\n\n // Other operations\n [ActionCommand.ChangeAliasIps]: 60000,\n};\n\n/**\n * Get default timeout for an action command\n */\nexport function getActionTimeout(command: ActionCommand): number {\n return ACTION_TIMEOUTS[command] || 300000; // Default 5 minutes\n}\n\n// ============================================================================\n// Enhanced Action Polling Service\n// ============================================================================\n\n/**\n * Default polling options\n */\nconst DEFAULT_POLLING_OPTIONS: Omit<Required<EnhancedActionPollingOptions>, 'signal'> & { signal: AbortSignal | undefined } = {\n pollInterval: 2000,\n maxRetries: 60,\n timeout: 300000,\n onProgress: () => {},\n onComplete: () => {},\n onError: () => {},\n onRetry: () => {},\n signal: undefined,\n adaptive: false,\n concurrency: 5,\n};\n\n/**\n * Poll for an action to complete with full feature support\n *\n * This is the core polling service function that provides:\n * - Progress tracking via onProgress callback\n * - Success/error notification via onComplete/onError\n * - Cancellation support via AbortSignal\n * - Adaptive polling intervals\n * - Retry logic with exponential backoff\n *\n * @param client - Hetzner API client\n * @param actionId - Action ID to poll\n * @param options - Polling options\n * @returns Completed action\n * @throws {HetznerActionError} If action fails\n * @throws {HetznerTimeoutError} If action times out\n *\n * @example\n * ```typescript\n * const action = await pollAction(client, 123, {\n * onProgress: (a) => console.log(`Progress: ${a.progress}%`),\n * onComplete: (a) => console.log('Completed:', a.command),\n * onError: (e) => console.error('Failed:', e.message),\n * timeout: 60000,\n * signal: abortSignal\n * });\n * ```\n */\nexport async function pollAction(\n client: HetznerClient,\n actionId: number,\n options: EnhancedActionPollingOptions = {}\n): Promise<HetznerAction> {\n const opts = { ...DEFAULT_POLLING_OPTIONS, ...options };\n const startTime = Date.now();\n let lastProgress = 0;\n let lastError: Error | null = null;\n let attempt = 0;\n\n // Check if already aborted\n if (opts.signal?.aborted) {\n throw new Error(\"Polling aborted before start\");\n }\n\n // Set up abort listener\n const abortListener = () => {\n throw new Error(\"Polling aborted\");\n };\n opts.signal?.addEventListener(\"abort\", abortListener);\n\n try {\n while (attempt < opts.maxRetries) {\n // Check timeout\n const elapsed = Date.now() - startTime;\n if (elapsed > opts.timeout) {\n throw new HetznerTimeoutError(actionId, opts.timeout, lastProgress);\n }\n\n try {\n const response = await client.request<{ action: HetznerAction }>(\n `/actions/${actionId}`\n );\n const action = response.action;\n attempt++;\n\n // Notify progress callback on any change\n if (action.progress !== lastProgress) {\n lastProgress = action.progress;\n opts.onProgress(action);\n }\n\n // Check if action completed successfully\n if (action.status === \"success\") {\n opts.onComplete(action);\n return action;\n }\n\n // Check if action failed\n if (action.status === \"error\") {\n const error = new HetznerActionError(\n action.error!,\n actionId\n );\n opts.onError(error, action);\n throw error;\n }\n\n // Still running - calculate wait time\n let waitTime = opts.pollInterval;\n if (opts.adaptive) {\n waitTime = getAdaptivePollInterval(action.progress);\n }\n\n await sleep(waitTime);\n\n } catch (error) {\n // Check if this is a retryable error\n if (isRetryableError(error)) {\n const delay = calculateRetryDelay(attempt);\n opts.onRetry(attempt, delay);\n\n if (opts.signal?.aborted) {\n throw new Error(\"Polling aborted during retry\");\n }\n\n await sleep(delay);\n continue;\n }\n\n // Non-retryable error - throw immediately\n throw error;\n }\n }\n\n // Max retries exceeded\n throw new HetznerTimeoutError(actionId, opts.timeout, lastProgress);\n\n } finally {\n opts.signal?.removeEventListener(\"abort\", abortListener);\n }\n}\n\n/**\n * Poll multiple actions concurrently\n *\n * Manages polling of multiple actions with optional concurrency limit.\n * Each action is polled independently with shared callbacks.\n *\n * @param client - Hetzner API client\n * @param actionIds - Array of action IDs to poll\n * @param options - Polling options\n * @returns Array of completed actions in same order as input\n *\n * @example\n * ```typescript\n * const actions = await pollActions(client, [1, 2, 3], {\n * onProgress: (a) => console.log(`Action ${a.id}: ${a.progress}%`),\n * onComplete: (a) => console.log(`Action ${a.id} complete`),\n * concurrency: 3 // Poll 3 actions at a time\n * });\n * ```\n */\nexport async function pollActions(\n client: HetznerClient,\n actionIds: number[],\n options: EnhancedActionPollingOptions = {}\n): Promise<HetznerAction[]> {\n const concurrency = options.concurrency ?? DEFAULT_POLLING_OPTIONS.concurrency;\n\n // If concurrency is high enough, poll all at once\n if (concurrency >= actionIds.length) {\n const promises = actionIds.map((id) =>\n pollAction(client, id, options)\n );\n return Promise.all(promises);\n }\n\n // Otherwise, process in batches with concurrency limit\n const results: HetznerAction[] = new Array(actionIds.length);\n let currentIndex = 0;\n\n const processBatch = async (): Promise<void> => {\n while (currentIndex < actionIds.length) {\n const batchStart = currentIndex;\n const batchEnd = Math.min(currentIndex + concurrency, actionIds.length);\n const batchIds = actionIds.slice(batchStart, batchEnd);\n currentIndex = batchEnd;\n\n const batchResults = await Promise.all(\n batchIds.map((id, i) => pollAction(client, id, options))\n );\n\n // Store results in correct positions\n batchResults.forEach((result, i) => {\n results[batchStart + i] = result;\n });\n }\n };\n\n // Process batches sequentially but actions within each batch concurrently\n await processBatch();\n return results;\n}\n\n/**\n * Poll multiple actions with detailed result tracking\n *\n * Similar to pollActions but returns a BatchPollingResult with\n * success/failure counts and per-action results for better\n * error handling and monitoring.\n *\n * @param client - Hetzner API client\n * @param actionIds - Array of action IDs to poll\n * @param options - Polling options\n * @returns Batch polling result with detailed status\n *\n * @example\n * ```typescript\n * const result = await pollActionsDetailed(client, [1, 2, 3], {\n * onProgress: (a) => updateProgressBar(a)\n * });\n *\n * console.log(`Completed: ${result.successful}/${actionIds.length}`);\n * for (const [id, r] of result.results) {\n * if (r.error) {\n * console.error(`Action ${id} failed:`, r.error.message);\n * }\n * }\n * ```\n */\nexport async function pollActionsDetailed(\n client: HetznerClient,\n actionIds: number[],\n options: EnhancedActionPollingOptions = {}\n): Promise<BatchPollingResult> {\n const startTime = Date.now();\n const results = new Map<number, PollingResult>();\n let successful = 0;\n let failed = 0;\n\n // Wrap callbacks to track results\n const wrappedOptions: EnhancedActionPollingOptions = {\n ...options,\n onComplete: (action) => {\n results.set(action.id, {\n success: true,\n action,\n attempts: 0,\n elapsed: Date.now() - startTime,\n });\n successful++;\n options.onComplete?.(action);\n },\n onError: (error, action) => {\n results.set(action.id, {\n success: false,\n action,\n error,\n attempts: 0,\n elapsed: Date.now() - startTime,\n });\n failed++;\n options.onError?.(error, action);\n },\n };\n\n try {\n // Poll all actions\n await pollActions(client, actionIds, wrappedOptions);\n } catch (error) {\n // Some actions may have failed, but we still return results\n console.warn(\"Some actions failed during batch polling:\", error);\n }\n\n return {\n results,\n successful,\n failed,\n elapsed: Date.now() - startTime,\n };\n}\n\n// ============================================================================\n// Backward Compatible Polling Functions\n// ============================================================================\n\n/**\n * Poll for an action to complete (backward compatible)\n *\n * @deprecated Use pollAction() instead for new code\n */\nexport async function waitForAction(\n client: HetznerClient,\n actionId: number,\n options: ActionPollingOptions = {}\n): Promise<HetznerAction> {\n const opts = { ...DEFAULT_POLLING_OPTIONS, ...options };\n const startTime = Date.now();\n let lastProgress = 0;\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < opts.maxRetries; attempt++) {\n // Check timeout\n if (Date.now() - startTime > opts.timeout) {\n throw new HetznerTimeoutError(actionId, opts.timeout, lastProgress);\n }\n\n try {\n const action = await client.request<{ action: HetznerAction }>(\n `/actions/${actionId}`\n );\n\n // Notify progress callback\n if (action.action.progress !== lastProgress) {\n lastProgress = action.action.progress;\n opts.onProgress(action.action);\n }\n\n // Check if action is complete\n if (action.action.status === \"success\") {\n return action.action;\n }\n\n if (action.action.status === \"error\") {\n throw new HetznerActionError(\n action.action.error!,\n actionId\n );\n }\n\n // Still running - wait before next poll\n await sleep(opts.pollInterval);\n\n } catch (error) {\n // Check if error is retryable\n if (isRetryableError(error)) {\n const delay = calculateRetryDelay(attempt);\n console.warn(\n `Retrying action ${actionId} after ${delay}ms (attempt ${attempt + 1}/${opts.maxRetries})`\n );\n await sleep(delay);\n continue;\n }\n\n // Non-retryable error - throw immediately\n throw error;\n }\n }\n\n // Max retries exceeded\n throw new HetznerTimeoutError(actionId, opts.timeout, lastProgress);\n}\n\n/**\n * Poll for multiple actions concurrently (backward compatible)\n *\n * @deprecated Use pollActions() instead for new code\n */\nexport async function waitForMultipleActions(\n client: HetznerClient,\n actionIds: number[],\n options: ActionPollingOptions = {}\n): Promise<HetznerAction[]> {\n const promises = actionIds.map((id) => waitForAction(client, id, options));\n return Promise.all(promises);\n}\n\n/**\n * Poll for multiple actions with concurrency limit (backward compatible)\n *\n * @deprecated Use pollActions() with concurrency option instead\n */\nexport async function waitForMultipleActionsWithLimit(\n client: HetznerClient,\n actionIds: number[],\n concurrency: number = 5,\n options: ActionPollingOptions = {}\n): Promise<HetznerAction[]> {\n const results: HetznerAction[] = [];\n const chunks: number[][] = [];\n\n // Split action IDs into chunks\n for (let i = 0; i < actionIds.length; i += concurrency) {\n chunks.push(actionIds.slice(i, i + concurrency));\n }\n\n // Process each chunk sequentially\n for (const chunk of chunks) {\n const chunkResults = await waitForMultipleActions(client, chunk, options);\n results.push(...chunkResults);\n }\n\n return results;\n}\n\n/**\n * Batch check multiple actions in a single API call\n *\n * Uses the /actions?id=42&id=43 endpoint to fetch multiple actions at once\n *\n * @param client - Hetzner API client\n * @param actionIds - Array of action IDs to check\n * @returns Map of action ID to action\n */\nexport async function batchCheckActions(\n client: HetznerClient,\n actionIds: number[]\n): Promise<Map<number, HetznerAction>> {\n const MAX_BATCH_SIZE = 50; // API limit for ID parameter\n const results = new Map<number, HetznerAction>();\n\n // Process in batches\n for (let i = 0; i < actionIds.length; i += MAX_BATCH_SIZE) {\n const batch = actionIds.slice(i, i + MAX_BATCH_SIZE);\n const idParams = batch.map((id) => `id=${id}`).join(\"&\");\n\n const response = await client.request<{ actions: HetznerAction[] }>(\n `/actions?${idParams}`\n );\n\n for (const action of response.actions) {\n results.set(action.id, action);\n }\n }\n\n return results;\n}\n\n// ============================================================================\n// Action Status Utilities\n// ============================================================================\n\n/**\n * Check if an action is running\n */\nexport function isActionRunning(action: HetznerAction): boolean {\n return action.status === \"running\";\n}\n\n/**\n * Check if an action completed successfully\n */\nexport function isActionSuccess(action: HetznerAction): boolean {\n return action.status === \"success\";\n}\n\n/**\n * Check if an action failed\n */\nexport function isActionError(action: HetznerAction): boolean {\n return action.status === \"error\";\n}\n\n/**\n * Format action progress for display\n */\nexport function formatActionProgress(action: HetznerAction): string {\n const command = action.command.replace(/_/g, \" \");\n const status = action.status.toUpperCase();\n return `${status}: ${command} (${action.progress}%)`;\n}\n\n/**\n * Get human-readable action description\n */\nexport function getActionDescription(command: ActionCommand | string): string {\n const descriptions: Record<ActionCommand, string> = {\n [ActionCommand.CreateServer]: \"Creating server\",\n [ActionCommand.DeleteServer]: \"Deleting server\",\n [ActionCommand.StartServer]: \"Starting server\",\n [ActionCommand.StopServer]: \"Stopping server\",\n [ActionCommand.RebootServer]: \"Rebooting server\",\n [ActionCommand.ResetServer]: \"Resetting server\",\n [ActionCommand.ShutdownServer]: \"Shutting down server\",\n [ActionCommand.Poweroff]: \"Cutting power to server\",\n [ActionCommand.ChangeServerType]: \"Changing server type\",\n [ActionCommand.RebuildServer]: \"Rebuilding server\",\n [ActionCommand.EnableBackup]: \"Enabling backups\",\n [ActionCommand.DisableBackup]: \"Disabling backups\",\n [ActionCommand.CreateImage]: \"Creating image\",\n [ActionCommand.ChangeDnsPtr]: \"Changing reverse DNS\",\n [ActionCommand.AttachToNetwork]: \"Attaching to network\",\n [ActionCommand.DetachFromNetwork]: \"Detaching from network\",\n [ActionCommand.ChangeAliasIps]: \"Changing alias IPs\",\n [ActionCommand.EnableRescue]: \"Enabling rescue mode\",\n [ActionCommand.DisableRescue]: \"Disabling rescue mode\",\n [ActionCommand.ChangeProtection]: \"Changing protection\",\n [ActionCommand.CreateVolume]: \"Creating volume\",\n [ActionCommand.DeleteVolume]: \"Deleting volume\",\n [ActionCommand.AttachVolume]: \"Attaching volume\",\n [ActionCommand.DetachVolume]: \"Detaching volume\",\n [ActionCommand.ResizeVolume]: \"Resizing volume\",\n [ActionCommand.VolumeChangeProtection]: \"Changing volume protection\",\n [ActionCommand.AddSubnet]: \"Adding subnet\",\n [ActionCommand.DeleteSubnet]: \"Deleting subnet\",\n [ActionCommand.AddRoute]: \"Adding route\",\n [ActionCommand.DeleteRoute]: \"Deleting route\",\n [ActionCommand.ChangeIpRange]: \"Changing IP range\",\n [ActionCommand.NetworkChangeProtection]: \"Changing network protection\",\n [ActionCommand.AssignFloatingIp]: \"Assigning floating IP\",\n [ActionCommand.UnassignFloatingIp]: \"Unassigning floating IP\",\n [ActionCommand.FloatingIpChangeDnsPtr]: \"Changing floating IP DNS\",\n [ActionCommand.FloatingIpChangeProtection]: \"Changing floating IP protection\",\n [ActionCommand.CreateLoadBalancer]: \"Creating load balancer\",\n [ActionCommand.DeleteLoadBalancer]: \"Deleting load balancer\",\n [ActionCommand.AddTarget]: \"Adding target to load balancer\",\n [ActionCommand.RemoveTarget]: \"Removing target from load balancer\",\n [ActionCommand.AddService]: \"Adding service to load balancer\",\n [ActionCommand.UpdateService]: \"Updating load balancer service\",\n [ActionCommand.DeleteService]: \"Deleting load balancer service\",\n [ActionCommand.LoadBalancerAttachToNetwork]: \"Attaching load balancer to network\",\n [ActionCommand.LoadBalancerDetachFromNetwork]: \"Detaching load balancer from network\",\n [ActionCommand.ChangeAlgorithm]: \"Changing load balancer algorithm\",\n [ActionCommand.ChangeType]: \"Changing load balancer type\",\n [ActionCommand.LoadBalancerChangeProtection]: \"Changing load balancer protection\",\n [ActionCommand.IssueCertificate]: \"Issuing certificate\",\n [ActionCommand.RetryCertificate]: \"Retrying certificate\",\n [ActionCommand.SetFirewallRules]: \"Setting firewall rules\",\n [ActionCommand.ApplyFirewall]: \"Applying firewall\",\n [ActionCommand.RemoveFirewall]: \"Removing firewall\",\n [ActionCommand.FirewallChangeProtection]: \"Changing firewall protection\",\n [ActionCommand.ImageChangeProtection]: \"Changing image protection\",\n };\n\n return (descriptions as Record<string, string>)[command] || command.replace(/_/g, \" \");\n}\n\n// ============================================================================\n// Adaptive Polling\n// ============================================================================\n\n/**\n * Get adaptive polling interval based on operation type\n */\nexport function getPollInterval(command: ActionCommand): number {\n const intervals: Partial<Record<ActionCommand, number>> = {\n // Quick operations - poll frequently\n [ActionCommand.StartServer]: 5000,\n [ActionCommand.StopServer]: 5000,\n [ActionCommand.RebootServer]: 10000,\n [ActionCommand.Poweroff]: 5000,\n [ActionCommand.ShutdownServer]: 5000,\n\n // Medium operations\n [ActionCommand.CreateServer]: 15000,\n [ActionCommand.CreateVolume]: 10000,\n [ActionCommand.AttachVolume]: 8000,\n [ActionCommand.DetachVolume]: 5000,\n\n // Long operations - poll less frequently\n [ActionCommand.RebuildServer]: 30000,\n [ActionCommand.CreateImage]: 60000,\n [ActionCommand.IssueCertificate]: 30000,\n };\n\n return intervals[command] || 10000; // Default 10 seconds\n}\n\n/**\n * Get adaptive polling interval based on action progress\n */\nexport function getAdaptivePollInterval(progress: number): number {\n if (progress < 10) return 2000; // Quick progress at start\n if (progress < 50) return 5000; // Medium progress\n if (progress < 90) return 10000; // Slowing down\n return 15000; // Near completion\n}\n\n/**\n * Poll with adaptive intervals (backward compatible)\n *\n * @deprecated Use pollAction() with adaptive: true option instead\n */\nexport async function waitForActionAdaptive(\n client: HetznerClient,\n actionId: number,\n command: ActionCommand,\n options: ActionPollingOptions = {}\n): Promise<HetznerAction> {\n const startTime = Date.now();\n const timeout = options.timeout ?? getActionTimeout(command);\n let lastProgress = -1;\n\n while (Date.now() - startTime < timeout) {\n const action = await client.request<{ action: HetznerAction }>(\n `/actions/${actionId}`\n );\n\n // Notify progress callback\n if (action.action.progress !== lastProgress) {\n lastProgress = action.action.progress;\n options.onProgress?.(action.action);\n }\n\n if (action.action.status === \"success\") {\n return action.action;\n }\n\n if (action.action.status === \"error\") {\n throw new HetznerActionError(action.action.error!, actionId);\n }\n\n // Adaptive polling based on progress\n const interval = getAdaptivePollInterval(action.action.progress);\n await sleep(interval);\n }\n\n throw new HetznerTimeoutError(actionId, timeout, lastProgress);\n}\n\n// ============================================================================\n// Rate Limit Handling\n// ============================================================================\n\n/**\n * Parse rate limit headers from response\n */\nexport function parseRateLimitHeaders(headers: Headers): RateLimitInfo | null {\n const limit = headers.get(\"RateLimit-Limit\");\n const remaining = headers.get(\"RateLimit-Remaining\");\n const reset = headers.get(\"RateLimit-Reset\");\n\n if (!limit || !remaining || !reset) {\n return null;\n }\n\n return {\n limit: parseInt(limit, 10),\n remaining: parseInt(remaining, 10),\n reset: parseInt(reset, 10),\n };\n}\n\n/**\n * Check if rate limit is low (should warn user)\n */\nexport function isRateLimitLow(info: RateLimitInfo, threshold: number = 100): boolean {\n return info.remaining < threshold;\n}\n\n/**\n * Get human-readable rate limit status\n */\nexport function formatRateLimitStatus(info: RateLimitInfo): string {\n const resetDate = new Date(info.reset * 1000);\n const remaining = info.remaining;\n const limit = info.limit;\n const percentage = ((remaining / limit) * 100).toFixed(1);\n\n return `${remaining}/${limit} (${percentage}%) - resets at ${resetDate.toISOString()}`;\n}\n\n/**\n * Wait for rate limit to reset\n */\nexport async function waitForRateLimitReset(info: RateLimitInfo): Promise<void> {\n const resetTime = info.reset * 1000;\n const now = Date.now();\n const waitTime = Math.max(0, resetTime - now);\n\n if (waitTime > 0) {\n const waitSeconds = Math.ceil(waitTime / 1000);\n console.log(`Rate limit exhausted. Waiting ${waitSeconds}s for reset...`);\n await sleep(waitTime);\n }\n}\n\n// ============================================================================\n// Utilities\n// ============================================================================\n\n/**\n * Sleep for specified milliseconds\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Create a progress logger for actions\n */\nexport function createProgressLogger(prefix: string = \"Action\") {\n return (action: HetznerAction) => {\n console.log(\n `[${prefix}] ${getActionDescription(action.command)}: ${action.progress}%`\n );\n };\n}\n",
|
|
12
|
+
"/**\n * Hetzner pricing operations - fetch server types, locations, and calculate costs\n */\n\nimport { z } from \"zod\";\nimport type {\n HetznerServerType,\n HetznerLocation,\n HetznerDatacenter,\n} from \"./types.js\";\nimport type { HetznerClient } from \"./client.js\";\nimport type { Environment } from \"@ebowwa/codespaces-types/compile\";\nimport {\n HetznerListServerTypesResponseSchema,\n HetznerListLocationsResponseSchema,\n HetznerListDatacentersResponseSchema,\n} from \"./schemas.js\";\n\n// ============================================================================\n// Cost Calculation Types\n// ============================================================================\n\n/**\n * Price information for a server type (in EUR)\n */\nexport interface ServerTypePrice {\n /** Server type name (e.g., \"cpx11\") */\n serverType: string;\n /** Monthly price in EUR */\n priceMonthly: number;\n /** Hourly price in EUR */\n priceHourly: number;\n /** Whether the server type is deprecated */\n deprecated: boolean;\n}\n\n/**\n * Cost breakdown for a single environment\n */\nexport interface EnvironmentCost {\n /** Environment ID */\n environmentId: string;\n /** Environment name */\n environmentName: string;\n /** Server type name */\n serverType: string;\n /** Whether the environment is currently running */\n isRunning: boolean;\n /** Monthly cost in EUR */\n costMonthly: number;\n /** Hourly cost in EUR */\n costHourly: number;\n /** Price info (undefined if server type not found) */\n priceInfo?: ServerTypePrice;\n}\n\n/**\n * Total cost calculation result\n */\nexport interface CostCalculationResult {\n /** Total monthly cost for all running environments (EUR) */\n totalMonthly: number;\n /** Total hourly cost for all running environments (EUR) */\n totalHourly: number;\n /** Number of environments included in calculation */\n runningEnvironmentCount: number;\n /** Number of environments excluded (not running) */\n stoppedEnvironmentCount: number;\n /** Number of environments with unknown server types */\n unknownServerTypeCount: number;\n /** Detailed breakdown by environment */\n breakdown: EnvironmentCost[];\n /** Map of server type names to their prices (for reference) */\n priceMap: Map<string, ServerTypePrice>;\n}\n\n/**\n * Default fallback price for unknown server types (EUR/month)\n * Conservative estimate based on Hetzner's smallest standard server\n */\nconst DEFAULT_FALLBACK_PRICE_MONTHLY = 5.0;\n\n/**\n * Hours per month for hourly cost calculation\n * Using 730 hours (average month: 365.25 days * 24 hours / 12 months)\n */\nconst HOURS_PER_MONTH = 730;\n\n// ============================================================================\n// Zod Schemas for Cost Calculation\n// ============================================================================\n\n/**\n * Schema for server type price entry\n */\nexport const ServerTypePriceSchema = z.object({\n serverType: z.string(),\n priceMonthly: z.number().nonnegative(),\n priceHourly: z.number().nonnegative(),\n deprecated: z.boolean().optional().default(false),\n});\n\n/**\n * Schema for environment cost entry\n */\nexport const EnvironmentCostSchema = z.object({\n environmentId: z.string(),\n environmentName: z.string(),\n serverType: z.string(),\n isRunning: z.boolean(),\n costMonthly: z.number().nonnegative(),\n costHourly: z.number().nonnegative(),\n priceInfo: ServerTypePriceSchema.optional(),\n});\n\n/**\n * Schema for cost calculation result\n */\nexport const CostCalculationResultSchema = z.object({\n totalMonthly: z.number().nonnegative(),\n totalHourly: z.number().nonnegative(),\n runningEnvironmentCount: z.number().nonnegative().int(),\n stoppedEnvironmentCount: z.number().nonnegative().int(),\n unknownServerTypeCount: z.number().nonnegative().int(),\n breakdown: z.array(EnvironmentCostSchema),\n priceMap: z.custom<Map<string, ServerTypePrice>>(),\n});\n\n// ============================================================================\n// Cost Calculation Utilities\n// ============================================================================\n\n/**\n * Parse Hetzner price string to number (EUR)\n * Hetzner returns prices as strings in gross format (e.g., \"5.3400\" for 5.34 EUR)\n *\n * @param priceString - Price string from Hetzner API (gross field)\n * @returns Price in EUR as number\n */\nexport function parseHetznerPrice(priceString: string): number {\n const parsed = parseFloat(priceString);\n if (isNaN(parsed)) {\n console.warn(`Failed to parse Hetzner price string: ${priceString}`);\n return 0;\n }\n return parsed;\n}\n\n/**\n * Extract pricing information from a Hetzner server type\n * Uses the first price entry (location-agnostic pricing)\n *\n * @param serverType - Hetzner server type object\n * @returns Server type price info or undefined if pricing unavailable\n */\nexport function extractServerTypePrice(\n serverType: HetznerServerType,\n): ServerTypePrice | undefined {\n if (!serverType.prices || serverType.prices.length === 0) {\n console.warn(`Server type ${serverType.name} has no pricing information`);\n return undefined;\n }\n\n // Use first price entry (Hetzner API returns location-agnostic pricing first)\n const priceEntry = serverType.prices[0];\n\n const priceMonthly = parseHetznerPrice(priceEntry.price_monthly.gross);\n const priceHourly = parseHetznerPrice(priceEntry.price_hourly.gross);\n\n return {\n serverType: serverType.name,\n priceMonthly,\n priceHourly,\n deprecated: serverType.deprecated ?? false,\n };\n}\n\n/**\n * Build a price lookup map from server types\n *\n * @param serverTypes - Array of Hetzner server types\n * @returns Map of server type name to price info\n */\nexport function buildPriceMap(\n serverTypes: HetznerServerType[],\n): Map<string, ServerTypePrice> {\n const priceMap = new Map<string, ServerTypePrice>();\n\n for (const serverType of serverTypes) {\n const priceInfo = extractServerTypePrice(serverType);\n if (priceInfo) {\n priceMap.set(serverType.name, priceInfo);\n }\n }\n\n return priceMap;\n}\n\n/**\n * Get the monthly price for a server type from the price map\n * Returns fallback price for unknown/deprecated types\n *\n * @param serverTypeName - Name of the server type\n * @param priceMap - Price lookup map\n * @param fallbackPrice - Fallback price for unknown types (default: 5.0 EUR)\n * @returns Monthly price in EUR\n */\nexport function getServerTypeMonthlyPrice(\n serverTypeName: string,\n priceMap: Map<string, ServerTypePrice>,\n fallbackPrice: number = DEFAULT_FALLBACK_PRICE_MONTHLY,\n): number {\n const priceInfo = priceMap.get(serverTypeName);\n return priceInfo?.priceMonthly ?? fallbackPrice;\n}\n\n/**\n * Calculate hourly price from monthly price\n * Uses standard 730 hours per month\n *\n * @param monthlyPrice - Monthly price in EUR\n * @returns Hourly price in EUR\n */\nexport function calculateHourlyFromMonthly(monthlyPrice: number): number {\n return monthlyPrice / HOURS_PER_MONTH;\n}\n\n// ============================================================================\n// Main Cost Calculation Function\n// ============================================================================\n\n/**\n * Calculate total costs for a list of environments\n *\n * This function:\n * - Only includes environments with \"running\" status\n * - Handles missing/deprecated server types with fallback pricing\n * - Returns detailed breakdown and aggregated totals\n *\n * @param environments - Array of environment objects\n * @param serverTypes - Array of Hetzner server types with pricing\n * @param options - Optional configuration\n * @returns Cost calculation result with totals and breakdown\n */\nexport function calculateCosts(\n environments: Environment[],\n serverTypes: HetznerServerType[],\n options: {\n /** Custom fallback price for unknown server types (EUR/month) */\n fallbackPrice?: number;\n /** Whether to include stopped environments in breakdown (default: false) */\n includeStopped?: boolean;\n } = {},\n): CostCalculationResult {\n const { fallbackPrice = DEFAULT_FALLBACK_PRICE_MONTHLY, includeStopped = false } =\n options;\n\n // Build price lookup map\n const priceMap = buildPriceMap(serverTypes);\n\n // Calculate costs for each environment\n const breakdown: EnvironmentCost[] = [];\n let totalMonthly = 0;\n let runningCount = 0;\n let stoppedCount = 0;\n let unknownTypeCount = 0;\n\n for (const env of environments) {\n const isRunning = env.status === \"running\";\n const priceInfo = priceMap.get(env.serverType);\n const isUnknownType = !priceInfo;\n\n // Count environments by status\n if (isRunning) {\n runningCount++;\n } else {\n stoppedCount++;\n }\n\n // Count unknown server types (only for running environments)\n if (isRunning && isUnknownType) {\n unknownTypeCount++;\n }\n\n // Get price (use fallback for unknown types, or 0 for stopped environments)\n const monthlyPrice = isRunning\n ? (priceInfo?.priceMonthly ?? fallbackPrice)\n : 0;\n const hourlyPrice = isRunning\n ? (priceInfo?.priceHourly ?? calculateHourlyFromMonthly(fallbackPrice))\n : 0;\n\n // Add to totals (only running environments)\n if (isRunning) {\n totalMonthly += monthlyPrice;\n }\n\n // Include in breakdown if running or if includeStopped is true\n if (isRunning || includeStopped) {\n breakdown.push({\n environmentId: env.id,\n environmentName: env.name,\n serverType: env.serverType,\n isRunning,\n costMonthly: monthlyPrice,\n costHourly: hourlyPrice,\n priceInfo: priceInfo,\n });\n }\n }\n\n // Calculate total hourly from monthly total\n const totalHourly = calculateHourlyFromMonthly(totalMonthly);\n\n return {\n totalMonthly,\n totalHourly,\n runningEnvironmentCount: runningCount,\n stoppedEnvironmentCount: stoppedCount,\n unknownServerTypeCount: unknownTypeCount,\n breakdown,\n priceMap,\n };\n}\n\n// ============================================================================\n// Pricing Operations Class\n// ============================================================================\n\nexport class PricingOperations {\n constructor(private client: HetznerClient) {}\n\n /**\n * List all server types\n */\n async listServerTypes(): Promise<HetznerServerType[]> {\n const response = await this.client.request<{ server_types: HetznerServerType[] }>(\n \"/server_types\"\n );\n\n // Validate response with Zod\n const validated = HetznerListServerTypesResponseSchema.safeParse(response);\n if (!validated.success) {\n console.warn('Hetzner list server types validation warning:', validated.error.issues);\n return response.server_types; // Return unvalidated data for backward compatibility\n }\n\n return validated.data.server_types as HetznerServerType[];\n }\n\n /**\n * Get a specific server type by name\n */\n async getServerType(name: string): Promise<HetznerServerType | undefined> {\n const types = await this.listServerTypes();\n return types.find(t => t.name === name);\n }\n\n /**\n * List all locations\n */\n async listLocations(): Promise<HetznerLocation[]> {\n const response = await this.client.request<{ locations: HetznerLocation[] }>(\n \"/locations\"\n );\n\n // Validate response with Zod\n const validated = HetznerListLocationsResponseSchema.safeParse(response);\n if (!validated.success) {\n console.warn('Hetzner list locations validation warning:', validated.error.issues);\n return response.locations; // Return unvalidated data for backward compatibility\n }\n\n return validated.data.locations;\n }\n\n /**\n * Get a specific location by name\n */\n async getLocation(name: string): Promise<HetznerLocation | undefined> {\n const locations = await this.listLocations();\n return locations.find(l => l.name === name);\n }\n\n /**\n * List all datacenters\n */\n async listDatacenters(): Promise<HetznerDatacenter[]> {\n const response = await this.client.request<{ datacenters: HetznerDatacenter[] }>(\n \"/datacenters\"\n );\n\n // Validate response with Zod\n const validated = HetznerListDatacentersResponseSchema.safeParse(response);\n if (!validated.success) {\n console.warn('Hetzner list datacenters validation warning:', validated.error.issues);\n return response.datacenters; // Return unvalidated data for backward compatibility\n }\n\n return validated.data.datacenters;\n }\n\n /**\n * Calculate costs for environments using current Hetzner pricing\n *\n * Convenience method that fetches server types and calculates costs in one call\n *\n * @param environments - Array of environment objects\n * @param options - Optional configuration for cost calculation\n * @returns Cost calculation result\n */\n async calculateEnvironmentCosts(\n environments: Environment[],\n options?: {\n fallbackPrice?: number;\n includeStopped?: boolean;\n },\n ): Promise<CostCalculationResult> {\n const serverTypes = await this.listServerTypes();\n return calculateCosts(environments, serverTypes, options);\n }\n}\n",
|
|
13
|
+
"/**\n * Hetzner SSH key operations\n */\n\nimport { z } from \"zod\";\nimport type {\n HetznerSSHKey,\n CreateSSHKeyOptions,\n} from \"./types.js\";\nimport type { HetznerClient } from \"./client.js\";\nimport {\n HetznerListSSHKeysResponseSchema,\n HetznerGetSSHKeyResponseSchema,\n HetznerCreateSSHKeyRequestSchema,\n HetznerCreateSSHKeyResponseSchema,\n} from \"./schemas.js\";\n\nexport class SSHKeyOperations {\n constructor(private client: HetznerClient) {}\n\n /**\n * List all SSH keys\n */\n async list(): Promise<HetznerSSHKey[]> {\n const response = await this.client.request<{ ssh_keys: HetznerSSHKey[] }>(\n \"/ssh_keys\",\n );\n\n // Validate response with Zod\n const validated = HetznerListSSHKeysResponseSchema.safeParse(response);\n if (!validated.success) {\n console.warn('Hetzner list SSH keys validation warning:', validated.error.issues);\n return response.ssh_keys; // Return unvalidated data for backward compatibility\n }\n\n return validated.data.ssh_keys;\n }\n\n /**\n * Get a specific SSH key by ID or name\n */\n async get(idOrName: number | string): Promise<HetznerSSHKey> {\n const endpoint = typeof idOrName === 'number'\n ? `/ssh_keys/${idOrName}`\n : `/ssh_keys?name=${encodeURIComponent(idOrName)}`;\n\n const response = await this.client.request<{ ssh_key: HetznerSSHKey }>(\n endpoint,\n );\n\n // Validate response with Zod\n const validated = HetznerGetSSHKeyResponseSchema.safeParse(response);\n if (!validated.success) {\n console.warn('Hetzner get SSH key validation warning:', validated.error.issues);\n return response.ssh_key; // Return unvalidated data for backward compatibility\n }\n\n return validated.data.ssh_key;\n }\n\n /**\n * Create a new SSH key\n *\n * @param options - SSH key creation options\n * @returns Created SSH key\n */\n async create(options: CreateSSHKeyOptions): Promise<HetznerSSHKey> {\n // Validate input with Zod\n const validatedOptions = HetznerCreateSSHKeyRequestSchema.safeParse(options);\n if (!validatedOptions.success) {\n throw new Error(`Invalid SSH key options: ${validatedOptions.error.issues.map(i => i.message).join(', ')}`);\n }\n\n const body = {\n name: validatedOptions.data.name,\n public_key: validatedOptions.data.public_key,\n ...(validatedOptions.data.labels && { labels: validatedOptions.data.labels }),\n };\n\n const response = await this.client.request<{ ssh_key: HetznerSSHKey }>(\n \"/ssh_keys\",\n {\n method: \"POST\",\n body: JSON.stringify(body),\n }\n );\n\n // Validate response with Zod\n const validated = HetznerCreateSSHKeyResponseSchema.safeParse(response);\n if (!validated.success) {\n console.warn('Hetzner create SSH key validation warning:', validated.error.issues);\n return response.ssh_key; // Return unvalidated data for backward compatibility\n }\n\n return validated.data.ssh_key;\n }\n\n /**\n * Delete an SSH key\n *\n * @param id - SSH key ID\n */\n async delete(id: number): Promise<void> {\n await this.client.request(\n `/ssh_keys/${id}`,\n { method: \"DELETE\" }\n );\n }\n\n /**\n * Find an SSH key by name\n * Returns undefined if not found\n */\n async findByName(name: string): Promise<HetznerSSHKey | undefined> {\n try {\n const keys = await this.list();\n return keys.find(key => key.name === name);\n } catch {\n return undefined;\n }\n }\n}\n",
|
|
14
|
+
"/**\n * Hetzner Volume Operations\n *\n * Provides methods for managing Hetzner Cloud volumes.\n * See: https://docs.hetzner.cloud/#volumes\n */\n\nimport type { HetznerClient } from \"./client.js\";\nimport type {\n HetznerVolume,\n CreateVolumeOptions,\n} from \"./types.js\";\nimport {\n HetznerListVolumesResponseSchema,\n HetznerGetVolumeResponseSchema,\n HetznerCreateVolumeResponseSchema,\n HetznerActionResponseSchema,\n} from \"./schemas.js\";\n\n/**\n * Volume operations for Hetzner Cloud API\n */\nexport class VolumeOperations {\n constructor(private client: HetznerClient) {}\n\n /**\n * List all volumes\n *\n * @param options - List options (name, status, sort, etc.)\n * @returns Array of volumes\n */\n async list(options?: {\n name?: string;\n status?: string;\n sort?: string;\n label_selector?: string;\n }): Promise<HetznerVolume[]> {\n const params = new URLSearchParams();\n if (options?.name) params.set(\"name\", options.name);\n if (options?.status) params.set(\"status\", options.status);\n if (options?.sort) params.set(\"sort\", options.sort);\n if (options?.label_selector) params.set(\"label_selector\", options.label_selector);\n\n const endpoint = `/volumes${params.toString() ? `?${params}` : \"\"}`;\n const response = await this.client.request<typeof HetznerListVolumesResponseSchema._output>(\n endpoint,\n );\n\n return response.volumes || [];\n }\n\n /**\n * Get a specific volume by ID\n *\n * @param id - Volume ID\n * @returns Volume details\n */\n async get(id: number): Promise<HetznerVolume> {\n const response = await this.client.request<typeof HetznerGetVolumeResponseSchema._output>(\n `/volumes/${id}`,\n );\n return response.volume;\n }\n\n /**\n * Create a new volume\n *\n * @param options - Volume creation options\n * @returns Created volume with action info\n */\n async create(options: CreateVolumeOptions): Promise<{\n volume: HetznerVolume;\n action: any;\n next_actions: any[];\n }> {\n const response = await this.client.request<typeof HetznerCreateVolumeResponseSchema._output>(\n \"/volumes\",\n {\n method: \"POST\",\n body: JSON.stringify({\n name: options.name,\n size: options.size,\n server: options.server,\n location: options.location,\n automount: options.automount ?? true,\n format: options.format,\n labels: options.labels,\n }),\n },\n );\n return response;\n }\n\n /**\n * Delete a volume\n *\n * @param id - Volume ID\n * @returns Action response\n */\n async delete(id: number): Promise<any> {\n const response = await this.client.request<typeof HetznerActionResponseSchema._output>(\n `/volumes/${id}`,\n {\n method: \"DELETE\",\n },\n );\n return response.action;\n }\n\n /**\n * Attach a volume to a server\n *\n * @param volumeId - Volume ID\n * @param serverId - Server ID\n * @param automount - Automatically mount the volume\n * @returns Action response\n */\n async attach(\n volumeId: number,\n serverId: number,\n automount: boolean = true,\n ): Promise<any> {\n const response = await this.client.request<typeof HetznerActionResponseSchema._output>(\n `/volumes/${volumeId}/actions/attach`,\n {\n method: \"POST\",\n body: JSON.stringify({\n server: serverId,\n automount,\n }),\n },\n );\n return response.action;\n }\n\n /**\n * Detach a volume from a server\n *\n * @param volumeId - Volume ID\n * @returns Action response\n */\n async detach(volumeId: number): Promise<any> {\n const response = await this.client.request<typeof HetznerActionResponseSchema._output>(\n `/volumes/${volumeId}/actions/detach`,\n {\n method: \"POST\",\n },\n );\n return response.action;\n }\n\n /**\n * Resize a volume\n *\n * @param volumeId - Volume ID\n * @param size - New size in GB (must be larger than current)\n * @returns Action response\n */\n async resize(volumeId: number, size: number): Promise<any> {\n const response = await this.client.request<typeof HetznerActionResponseSchema._output>(\n `/volumes/${volumeId}/actions/resize`,\n {\n method: \"POST\",\n body: JSON.stringify({ size }),\n },\n );\n return response.action;\n }\n\n /**\n * Change volume protection\n *\n * @param volumeId - Volume ID\n * @param deleteProtection - Enable delete protection\n * @returns Action response\n */\n async changeProtection(volumeId: number, deleteProtection: boolean): Promise<any> {\n const response = await this.client.request<typeof HetznerActionResponseSchema._output>(\n `/volumes/${volumeId}/actions/change_protection`,\n {\n method: \"POST\",\n body: JSON.stringify({\n delete: deleteProtection,\n }),\n },\n );\n return response.action;\n }\n\n /**\n * Update volume labels\n *\n * @param volumeId - Volume ID\n * @param labels - New labels\n * @returns Updated volume\n */\n async updateLabels(volumeId: number, labels: Record<string, string>): Promise<HetznerVolume> {\n const response = await this.client.request<typeof HetznerGetVolumeResponseSchema._output>(\n `/volumes/${volumeId}`,\n {\n method: \"PUT\",\n body: JSON.stringify({ labels }),\n },\n );\n return response.volume;\n }\n\n /**\n * Get volume pricing information\n * Calculates monthly cost based on size (€0.008/GB per month)\n *\n * @param sizeInGB - Volume size in GB\n * @returns Monthly and hourly pricing\n */\n static calculatePrice(sizeInGB: number) {\n const PRICE_PER_GB_MONTHLY = 0.008; // €0.008 per GB per month\n const HOURS_PER_MONTH = 730; // Average\n\n const monthly = sizeInGB * PRICE_PER_GB_MONTHLY;\n const hourly = monthly / HOURS_PER_MONTH;\n\n return {\n size: sizeInGB,\n monthly: Math.round(monthly * 100) / 100,\n hourly: Math.round(hourly * 10000) / 10000,\n currency: \"EUR\",\n };\n }\n}\n",
|
|
15
|
+
"/**\n * Hetzner Cloud API client\n * For server-side use only (requires API token)\n *\n * TODO: RE-REVIEW https://docs.hetzner.cloud/reference/cloud#authentication\n * - https://tailscale.com/kb/1150/cloud-hetzner\n */\n\nimport { z } from \"zod\";\nimport { HETZNER_API_BASE } from \"./config.js\";\n\n// Universal fetch - works in both Node.js (18+) and Bun\n// Node.js 18+ has native fetch, Bun has enhanced fetch\nconst fetch = globalThis.fetch;\nimport { resolveApiToken, getTokenFromCLI, isAuthenticated } from \"./auth.js\";\nimport { ServerOperations } from \"./servers.js\";\nimport { ActionOperations } from \"./actions.js\";\nimport { PricingOperations } from \"./pricing.js\";\nimport { SSHKeyOperations } from \"./ssh-keys.js\";\nimport { VolumeOperations } from \"./volumes.js\";\nimport {\n HetznerListServersResponseSchema,\n HetznerGetServerResponseSchema,\n HetznerCreateServerResponseSchema,\n} from \"./schemas.js\";\nimport {\n createHetznerError,\n isRateLimitError,\n} from \"./errors.js\";\nimport {\n parseRateLimitHeaders,\n waitForRateLimitReset,\n} from \"./actions.js\";\nimport type { RateLimitInfo } from \"./types.js\";\n\nexport class HetznerClient {\n private apiToken: string;\n\n constructor(apiToken?: string) {\n this.apiToken = resolveApiToken(apiToken);\n\n // If no token from env or explicit, try CLI config\n if (!this.apiToken) {\n this.apiToken = getTokenFromCLI();\n }\n }\n\n get isAuthenticated(): boolean {\n return isAuthenticated(this.apiToken);\n }\n\n /**\n * Make a request to the Hetzner Cloud API\n *\n * @param endpoint - API endpoint (e.g., \"/servers\")\n * @param options - RequestInit options\n * @returns Parsed JSON response\n * @throws {HetznerAPIError} On API errors\n */\n async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {\n const response = await fetch(`${HETZNER_API_BASE}${endpoint}`, {\n ...options,\n headers: {\n Authorization: `Bearer ${this.apiToken}`,\n \"Content-Type\": \"application/json\",\n ...options.headers,\n },\n });\n\n // Parse rate limit headers\n const rateLimit = parseRateLimitHeaders(response.headers);\n this.handleRateLimit(rateLimit);\n\n if (!response.ok) {\n const body = await response.json().catch(() => ({}));\n throw createHetznerError(response.status, body);\n }\n\n const data = await response.json();\n return data as T;\n }\n\n /**\n * Validate Hetzner API response with Zod schema\n *\n * @param schema - Zod schema to validate against\n * @param data - Data to validate\n * @returns Validated data\n */\n private validateResponse<T>(schema: z.ZodType<T>, data: unknown): T {\n const result = schema.safeParse(data);\n if (result.success) {\n return result.data;\n }\n // Log validation errors but don't throw to maintain backward compatibility\n console.warn(\n \"Hetzner API response validation warning:\",\n result.error.issues\n );\n return data as T;\n }\n\n /**\n * Handle rate limit information from response headers\n *\n * @param rateLimit - Rate limit info from response\n */\n private handleRateLimit(rateLimit: RateLimitInfo | null): void {\n if (!rateLimit) return;\n\n // Warn if rate limit is low\n if (rateLimit.remaining < 100) {\n console.warn(\n `[Hetzner API] Rate limit low: ${rateLimit.remaining}/${rateLimit.limit} remaining. Resets at ${new Date(rateLimit.reset * 1000).toISOString()}`\n );\n }\n }\n\n /**\n * Get current rate limit information\n *\n * Makes a lightweight request to check rate limit status\n *\n * @returns Rate limit info or null if not available\n */\n async getRateLimit(): Promise<RateLimitInfo | null> {\n try {\n const response = await fetch(`${HETZNER_API_BASE}/servers`, {\n headers: {\n Authorization: `Bearer ${this.apiToken}`,\n },\n });\n return parseRateLimitHeaders(response.headers);\n } catch {\n return null;\n }\n }\n\n readonly servers = new ServerOperations(this);\n readonly actions = new ActionOperations(this);\n readonly pricing = new PricingOperations(this);\n readonly ssh_keys = new SSHKeyOperations(this);\n readonly volumes = new VolumeOperations(this);\n\n // Backward-compatible convenience methods (delegates to servers operations)\n async listServers() {\n return this.servers.list();\n }\n\n async getServer(id: number) {\n return this.servers.get(id);\n }\n\n async createServer(options: import(\"./types.js\").CreateServerOptions) {\n return this.servers.create(options);\n }\n\n async deleteServer(id: number) {\n return this.servers.delete(id);\n }\n\n async powerOn(id: number) {\n return this.servers.powerOn(id);\n }\n\n async powerOff(id: number) {\n return this.servers.powerOff(id);\n }\n\n async reboot(id: number) {\n return this.servers.reboot(id);\n }\n}\n\n// Re-export types for convenience\nexport type * from \"./types.js\";\n",
|
|
16
|
+
"/**\n * SSH Hardening Cloud-Init Components\n *\n * Composable cloud-init blocks for securing sshd on new servers.\n * Includes: hardened sshd config, fail2ban, and health monitoring.\n *\n * Background: Hetzner public IPs get brute-forced constantly (~5k failed SSH\n * logins per 24h observed on genesis). Without hardening, the default sshd\n * MaxStartups (10:30:100) gets overwhelmed and legitimate connections time out\n * with \"Timed out while waiting for handshake\".\n *\n * This module is imported by both cloud-init.ts (seed/worker nodes) and\n * genesis.ts (control plane) so every new server gets hardened at first boot.\n *\n * Three composable functions return cloud-init line arrays for splicing into\n * the appropriate YAML sections:\n * - sshdHardeningPackages() → packages: section\n * - sshdHardeningWriteFiles() → write_files: section\n * - sshdHardeningRunCmd() → runcmd: section\n */\n\n/**\n * Packages required for SSH hardening.\n * Returns cloud-init YAML lines for the `packages:` section.\n *\n * - fail2ban: bans IPs after repeated failed SSH attempts (3 tries → 1hr ban)\n */\nexport function sshdHardeningPackages(): string[] {\n return [\n \" - fail2ban\",\n ];\n}\n\n/**\n * Files to write at first boot for SSH hardening.\n * Returns cloud-init YAML lines for the `write_files:` section.\n *\n * Drops 5 files onto the server:\n *\n * 1. /etc/ssh/sshd_config.d/hardened.conf\n * - Disables password auth entirely (key-only)\n * - Raises MaxStartups from default 10:30:100 → 20:50:60 so brute-force\n * traffic doesn't starve legitimate connections\n * - Reduces LoginGraceTime from 2min → 30s (attackers hold slots open)\n * - Limits MaxAuthTries to 3 per connection\n * - Enables keepalive (30s interval, 3 missed = disconnect)\n *\n * 2. /etc/fail2ban/jail.local\n * - Monitors sshd via systemd journal\n * - Bans IP for 1 hour after 3 failures within 10 minutes\n * - Uses nftables (Ubuntu 24.04 default firewall backend)\n *\n * 3. /opt/monitoring/sshd-health.sh\n * - Collects sshd + fail2ban + system metrics into JSON\n * - Writes to /var/log/sshd-health.json (read by the app via SSH)\n * - Auto-restarts sshd if it detects it's down\n *\n * 4. /etc/systemd/system/sshd-health.service (oneshot runner)\n * 5. /etc/systemd/system/sshd-health.timer (runs every 60 seconds)\n */\nexport function sshdHardeningWriteFiles(): string[] {\n const lines: string[] = [];\n\n // 1. Hardened sshd config — dropped into sshd_config.d/ so it overrides defaults\n // without touching the main sshd_config file\n lines.push(\" # Hardened SSH configuration\");\n lines.push(\" - path: /etc/ssh/sshd_config.d/hardened.conf\");\n lines.push(\" owner: root:root\");\n lines.push(\" permissions: '0644'\");\n lines.push(\" content: |\");\n lines.push(\" # Hardened SSH config - applied via cloud-init\");\n lines.push(\" PasswordAuthentication no\");\n lines.push(\" PermitEmptyPasswords no\");\n lines.push(\" KbdInteractiveAuthentication no\");\n lines.push(\" PermitRootLogin prohibit-password\");\n lines.push(\" LoginGraceTime 30\");\n lines.push(\" MaxStartups 20:50:60\");\n lines.push(\" ClientAliveInterval 30\");\n lines.push(\" ClientAliveCountMax 3\");\n lines.push(\" MaxAuthTries 3\");\n lines.push(\"\");\n\n // 2. fail2ban jail — 3 failed attempts in 10min = 1hr ban via nftables\n lines.push(\" # fail2ban SSH jail configuration\");\n lines.push(\" - path: /etc/fail2ban/jail.local\");\n lines.push(\" owner: root:root\");\n lines.push(\" permissions: '0644'\");\n lines.push(\" content: |\");\n lines.push(\" [sshd]\");\n lines.push(\" enabled = true\");\n lines.push(\" port = ssh\");\n lines.push(\" backend = systemd\");\n lines.push(\" maxretry = 3\");\n lines.push(\" findtime = 600\");\n lines.push(\" bantime = 3600\");\n lines.push(\" banaction = nftables-multiport\");\n lines.push(\"\");\n\n // 3. Health monitoring script — collects sshd/fail2ban/system stats into JSON\n // Output at /var/log/sshd-health.json is read by the app's collectSSHDHealth()\n // function (src/lib/metrics.ts) every 5 minutes via SSH\n lines.push(\" # sshd health monitoring script\");\n lines.push(\" - path: /opt/monitoring/sshd-health.sh\");\n lines.push(\" owner: root:root\");\n lines.push(\" permissions: '0755'\");\n lines.push(\" content: |\");\n lines.push(\" #!/bin/bash\");\n lines.push(\" set -euo pipefail\");\n lines.push(\" LOGFILE=\\\"/var/log/sshd-health.json\\\"\");\n lines.push(\" sshd_active=$(systemctl is-active ssh 2>/dev/null || echo \\\"inactive\\\")\");\n lines.push(\" sshd_pid=$(pgrep -x sshd | head -1 || echo \\\"0\\\")\");\n lines.push(\" f2b_active=$(systemctl is-active fail2ban 2>/dev/null || echo \\\"inactive\\\")\");\n lines.push(\" f2b_banned=$(fail2ban-client status sshd 2>/dev/null | grep \\\"Currently banned\\\" | awk '{print $NF}' || echo \\\"0\\\")\");\n lines.push(\" f2b_total=$(fail2ban-client status sshd 2>/dev/null | grep \\\"Total banned\\\" | awk '{print $NF}' || echo \\\"0\\\")\");\n lines.push(\" failed_1h=$(journalctl -u ssh --since \\\"1 hour ago\\\" --no-pager 2>/dev/null | grep -c \\\"Failed\\\" || true)\");\n lines.push(\" failed_24h=$(journalctl -u ssh --since \\\"24 hours ago\\\" --no-pager 2>/dev/null | grep -c \\\"Failed\\\" || true)\");\n lines.push(\" active_connections=$(ss -tnp | grep -c \\\":22 \\\" || echo \\\"0\\\")\");\n lines.push(\" uptime_seconds=$(awk '{print int($1)}' /proc/uptime)\");\n lines.push(\" load=$(awk '{print $1}' /proc/loadavg)\");\n lines.push(\" mem_used_pct=$(free | awk '/Mem:/{printf \\\"%.1f\\\", $3/$2*100}')\");\n lines.push(\" timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)\");\n lines.push(\" cat > \\\"$LOGFILE\\\" <<HEALTHEOF\");\n lines.push(\" {\");\n lines.push(\" \\\"timestamp\\\": \\\"$timestamp\\\",\");\n lines.push(\" \\\"sshd\\\": { \\\"active\\\": \\\"$sshd_active\\\", \\\"pid\\\": $sshd_pid },\");\n lines.push(\" \\\"fail2ban\\\": { \\\"active\\\": \\\"$f2b_active\\\", \\\"currently_banned\\\": $f2b_banned, \\\"total_banned\\\": $f2b_total },\");\n lines.push(\" \\\"connections\\\": { \\\"active\\\": $active_connections, \\\"failed_1h\\\": $failed_1h, \\\"failed_24h\\\": $failed_24h },\");\n lines.push(\" \\\"system\\\": { \\\"uptime_seconds\\\": $uptime_seconds, \\\"load\\\": $load, \\\"memory_used_pct\\\": $mem_used_pct }\");\n lines.push(\" }\");\n lines.push(\" HEALTHEOF\");\n lines.push(\" if [ \\\"$sshd_active\\\" != \\\"active\\\" ]; then\");\n lines.push(\" logger -t sshd-health -p auth.crit \\\"ALERT: sshd is $sshd_active\\\"\");\n lines.push(\" systemctl start ssh 2>/dev/null || logger -t sshd-health -p auth.crit \\\"FAILED to restart sshd\\\"\");\n lines.push(\" fi\");\n lines.push(\"\");\n\n // 4. Systemd oneshot service — wraps the health script for timer-based execution\n lines.push(\" # sshd health check systemd service\");\n lines.push(\" - path: /etc/systemd/system/sshd-health.service\");\n lines.push(\" owner: root:root\");\n lines.push(\" permissions: '0644'\");\n lines.push(\" content: |\");\n lines.push(\" [Unit]\");\n lines.push(\" Description=sshd health check\");\n lines.push(\" After=ssh.service\");\n lines.push(\" [Service]\");\n lines.push(\" Type=oneshot\");\n lines.push(\" ExecStart=/opt/monitoring/sshd-health.sh\");\n lines.push(\"\");\n\n // 5. Systemd timer — fires the health check every 60 seconds, starting 30s after boot\n lines.push(\" # sshd health check timer (every 60s)\");\n lines.push(\" - path: /etc/systemd/system/sshd-health.timer\");\n lines.push(\" owner: root:root\");\n lines.push(\" permissions: '0644'\");\n lines.push(\" content: |\");\n lines.push(\" [Unit]\");\n lines.push(\" Description=Run sshd health check every minute\");\n lines.push(\" [Timer]\");\n lines.push(\" OnBootSec=30\");\n lines.push(\" OnUnitActiveSec=60\");\n lines.push(\" [Install]\");\n lines.push(\" WantedBy=timers.target\");\n lines.push(\"\");\n\n return lines;\n}\n\n/**\n * Commands to activate all SSH hardening services at first boot.\n * Returns cloud-init YAML lines for the `runcmd:` section.\n *\n * Order matters:\n * 1. Create /opt/monitoring dir (health script target)\n * 2. Reload sshd to pick up hardened.conf (fallback: full restart)\n * 3. Enable + start fail2ban (reads jail.local immediately)\n * 4. Reload systemd to pick up the health service/timer units\n * 5. Enable + start the health timer (begins 60s monitoring loop)\n */\nexport function sshdHardeningRunCmd(): string[] {\n const lines: string[] = [];\n\n lines.push(\" # SSH hardening: reload sshd, enable fail2ban and health monitoring\");\n lines.push(\" - mkdir -p /opt/monitoring\");\n lines.push(\" - systemctl reload ssh || systemctl restart ssh\");\n lines.push(\" - systemctl enable --now fail2ban\");\n lines.push(\" - systemctl daemon-reload\");\n lines.push(\" - systemctl enable --now sshd-health.timer\");\n lines.push(\"\");\n\n return lines;\n}\n",
|
|
17
|
+
"/**\n * UFW Firewall Cloud-Init Components\n *\n * Composable cloud-init blocks for securing servers with UFW (Uncomplicated Firewall).\n * Includes: default deny incoming, allow outgoing, rate limiting, and logging.\n *\n * Background: Hetzner public IPs face constant scanning and brute-force attacks.\n * UFW provides a simple interface to iptables/nftables with secure defaults.\n *\n * This module is imported by cloud-init.ts (seed/worker nodes) and genesis.ts\n * (control plane) so every new server gets firewall protection at first boot.\n *\n * Three composable functions return cloud-init line arrays for splicing into\n * the appropriate YAML sections:\n * - ufwFirewallPackages() → packages: section\n * - ufwFirewallWriteFiles() → write_files: section\n * - ufwFirewallRunCmd() → runcmd: section\n *\n * Security Policy:\n * - Default: deny incoming, allow outgoing (stateful)\n * - SSH (22): rate limited to prevent brute-force\n * - HTTP/HTTPS (80/443): allowed for web services\n * - Node Agent (8911): allowed for internal communication\n * - Tailscale (41641): allowed for VPN\n * - Logging: enabled with rate limiting to prevent log flooding\n */\n\n/**\n * UFW firewall configuration options.\n */\nexport interface UFWFirewallOptions {\n /** Allow SSH from specific IPs/CIDRs (default: allow from anywhere) */\n allowSSHFrom?: string[];\n\n /** Allow HTTP (port 80) */\n allowHTTP?: boolean;\n\n /** Allow HTTPS (port 443) */\n allowHTTPS?: boolean;\n\n /** Allow Node Agent port (8911) */\n allowNodeAgent?: boolean;\n\n /** Additional ports to allow */\n additionalPorts?: Array<{ port: number; protocol?: string; comment?: string }>;\n\n /** Enable verbose logging (default: rate-limited logging) */\n verboseLogging?: boolean;\n}\n\n/**\n * Default firewall options for Genesis control plane servers.\n */\nexport const DEFAULT_UFW_GENESIS_OPTIONS: UFWFirewallOptions = {\n allowSSHFrom: [], // Empty = allow from anywhere\n allowHTTP: true,\n allowHTTPS: true,\n allowNodeAgent: false, // Genesis doesn't run node-agent\n verboseLogging: false,\n};\n\n/**\n * Default firewall options for worker/seed servers.\n */\nexport const DEFAULT_UFW_WORKER_OPTIONS: UFWFirewallOptions = {\n allowSSHFrom: [], // Empty = allow from anywhere\n allowHTTP: false,\n allowHTTPS: false,\n allowNodeAgent: true, // Workers run node-agent on port 8911\n verboseLogging: false,\n};\n\n/**\n * Packages required for UFW firewall.\n * Returns cloud-init YAML lines for the `packages:` section.\n *\n * - ufw: Uncomplicated Firewall interface to iptables/nftables\n */\nexport function ufwFirewallPackages(): string[] {\n return [\n \" - ufw\",\n ];\n}\n\n/**\n * Files to write at first boot for UFW firewall configuration.\n * Returns cloud-init YAML lines for the `write_files:` section.\n *\n * Drops 2 files onto the server:\n *\n * 1. /etc/ufw/before.rules\n * - Custom before rules for stateful firewall behavior\n * - Allows loopback, established/related connections\n * - Drops invalid packets early\n *\n * 2. /etc/ufw/sysctl.conf\n * - Enables kernel network security parameters\n * - IP spoofing protection\n * - ICMP redirect protection\n * - Log martian packets\n */\nexport function ufwFirewallWriteFiles(options: UFWFirewallOptions = {}): string[] {\n const lines: string[] = [];\n\n // 1. UFW before.rules - stateful firewall rules applied before UFW rules\n lines.push(\" # UFW before.rules - stateful firewall and network security\");\n lines.push(\" - path: /etc/ufw/before.rules\");\n lines.push(\" owner: root:root\");\n lines.push(\" permissions: '0644'\");\n lines.push(\" content: |\");\n lines.push(\" #\");\n lines.push(\" # UFW before.rules - applied before UFW rules\");\n lines.push(\" #\");\n lines.push(\" # Start with the standard configuration\");\n lines.push(\" *filter\");\n lines.push(\" :ufw-before-input - [0:0]\");\n lines.push(\" :ufw-before-output - [0:0]\");\n lines.push(\" :ufw-before-forward - [0:0]\");\n lines.push(\" :ufw-not-local - [0:0]\");\n lines.push(\" # End of lines to adjust\");\n lines.push(\"\");\n lines.push(\" # Allow all on loopback\");\n lines.push(\" -A ufw-before-input -i lo -j ACCEPT\");\n lines.push(\" -A ufw-before-output -o lo -j ACCEPT\");\n lines.push(\"\");\n lines.push(\" # Drop invalid packets\");\n lines.push(\" -A ufw-before-input -m conntrack --ctstate INVALID -j DROP\");\n lines.push(\"\");\n lines.push(\" # Allow established and related connections\");\n lines.push(\" -A ufw-before-input -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\");\n lines.push(\" -A ufw-before-output -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\");\n lines.push(\"\");\n lines.push(\" # Allow ICMP messages (required for PMTU discovery)\");\n lines.push(\" -A ufw-before-input -p icmp --icmp-type destination-unreachable -j ACCEPT\");\n lines.push(\" -A ufw-before-input -p icmp --icmp-type time-exceeded -j ACCEPT\");\n lines.push(\" -A ufw-before-input -p icmp --icmp-type parameter-problem -j ACCEPT\");\n lines.push(\" -A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT\");\n lines.push(\"\");\n lines.push(\" # Drop packets with bogus TCP flags (potential scan)\");\n lines.push(\" -A ufw-before-input -p tcp --tcp-flags ALL NONE -j DROP\");\n lines.push(\" -A ufw-before-input -p tcp --tcp-flags ALL ALL -j DROP\");\n lines.push(\"\");\n lines.push(\" # Commit changes\");\n lines.push(\" COMMIT\");\n lines.push(\"\");\n\n // 2. UFW sysctl.conf - kernel network security parameters\n lines.push(\" # UFW sysctl.conf - kernel network hardening\");\n lines.push(\" - path: /etc/ufw/sysctl.conf\");\n lines.push(\" owner: root:root\");\n lines.push(\" permissions: '0644'\");\n lines.push(\" content: |\");\n lines.push(\" #\");\n lines.push(\" # UFW sysctl.conf - kernel network security parameters\");\n lines.push(\" #\");\n lines.push(\"\");\n lines.push(\" # IP spoofing protection\");\n lines.push(\" net/ipv4/conf/all/rp_filter=1\");\n lines.push(\" net/ipv4/conf/default/rp_filter=1\");\n lines.push(\"\");\n lines.push(\" # Ignore ICMP redirect messages\");\n lines.push(\" net/ipv4/conf/all/accept_redirects=0\");\n lines.push(\" net/ipv6/conf/all/accept_redirects=0\");\n lines.push(\" net/ipv4/conf/default/accept_redirects=0\");\n lines.push(\" net/ipv6/conf/default/accept_redirects=0\");\n lines.push(\"\");\n lines.push(\" # Ignore send redirects\");\n lines.push(\" net/ipv4/conf/all/send_redirects=0\");\n lines.push(\" net/ipv4/conf/default/send_redirects=0\");\n lines.push(\"\");\n lines.push(\" # Log martian packets (packets with impossible addresses)\");\n lines.push(\" net/ipv4/conf/all/log_martians=1\");\n lines.push(\" net/ipv4/conf/default/log_martians=1\");\n lines.push(\"\");\n lines.push(\" # SYN cookies protection (SYN flood mitigation)\");\n lines.push(\" net/ipv4/tcp_syncookies=1\");\n lines.push(\"\");\n lines.push(\" # Source address verification (spoofing protection)\");\n lines.push(\" net/ipv4/conf/all/secure_redirects=1\");\n lines.push(\" net/ipv4/conf/default/secure_redirects=1\");\n lines.push(\"\");\n\n return lines;\n}\n\n/**\n * Commands to configure and activate UFW firewall at first boot.\n * Returns cloud-init YAML lines for the `runcmd:` section.\n *\n * Order matters:\n * 1. Set default policies (deny incoming, allow outgoing)\n * 2. Allow loopback interface\n * 3. Allow SSH with rate limiting (prevents brute-force)\n * 4. Allow HTTP/HTTPS if enabled\n * 5. Allow Node Agent port if enabled\n * 6. Allow Tailscale port (required for VPN)\n * 7. Enable logging with rate limiting\n * 8. Enable and reload UFW\n * 9. Display firewall status\n */\nexport function ufwFirewallRunCmd(options: UFWFirewallOptions = {}): string[] {\n const {\n allowSSHFrom = [],\n allowHTTP = true,\n allowHTTPS = true,\n allowNodeAgent = false,\n additionalPorts = [],\n verboseLogging = false,\n } = options;\n\n const lines: string[] = [];\n\n lines.push(\" # UFW Firewall: Configure and enable secure firewall\");\n lines.push(\"\");\n\n // Set default policies\n lines.push(\" # Set default policies: deny incoming, allow outgoing\");\n lines.push(\" - ufw --force reset\");\n lines.push(\" - ufw default deny incoming\");\n lines.push(\" - ufw default allow outgoing\");\n lines.push(\" - ufw default deny forwarded\");\n lines.push(\"\");\n\n // Allow loopback\n lines.push(\" # Allow loopback interface\");\n lines.push(\" - ufw allow in on lo\");\n lines.push(\"\");\n\n // Allow SSH with rate limiting\n if (allowSSHFrom.length === 0) {\n // Allow SSH from anywhere with rate limiting\n lines.push(\" # Allow SSH with rate limiting (6 connections in 30 seconds)\");\n lines.push(\" - ufw limit 22/tcp comment 'Rate-limited SSH'\");\n } else {\n // Allow SSH from specific IPs/CIDRs\n for (const source of allowSSHFrom) {\n lines.push(` - ufw allow from ${source} to any port 22 proto tcp comment 'SSH from ${source}'`);\n }\n }\n lines.push(\"\");\n\n // Allow HTTP if enabled\n if (allowHTTP) {\n lines.push(\" # Allow HTTP\");\n lines.push(\" - ufw allow 80/tcp comment 'HTTP'\");\n }\n\n // Allow HTTPS if enabled\n if (allowHTTPS) {\n lines.push(\" # Allow HTTPS\");\n lines.push(\" - ufw allow 443/tcp comment 'HTTPS'\");\n }\n lines.push(\"\");\n\n // Allow Node Agent port if enabled\n if (allowNodeAgent) {\n lines.push(\" # Allow Node Agent (internal communication)\");\n lines.push(\" - ufw allow 8911/tcp comment 'Node Agent'\");\n lines.push(\"\");\n }\n\n // Allow Tailscale (required for VPN functionality)\n lines.push(\" # Allow Tailscale VPN\");\n lines.push(\" - ufw allow 41641/udp comment 'Tailscale'\");\n lines.push(\"\");\n\n // Additional ports\n if (additionalPorts.length > 0) {\n lines.push(\" # Additional custom ports\");\n for (const portConfig of additionalPorts) {\n const protocol = portConfig.protocol || \"tcp\";\n const comment = portConfig.comment || `Custom port ${portConfig.port}`;\n lines.push(` - ufw allow ${portConfig.port}/${protocol} comment '${comment}'`);\n }\n lines.push(\"\");\n }\n\n // Configure logging\n if (verboseLogging) {\n lines.push(\" # Enable verbose logging\");\n lines.push(\" - ufw logging on\");\n lines.push(\" - ufw logging high\");\n } else {\n lines.push(\" # Enable rate-limited logging (prevent log flooding)\");\n lines.push(\" - ufw logging on\");\n lines.push(\" - ufw logging low\");\n }\n lines.push(\"\");\n\n // Enable and reload UFW\n lines.push(\" # Enable and reload UFW\");\n lines.push(\" - ufw --force enable\");\n lines.push(\" - ufw reload\");\n lines.push(\"\");\n\n // Display status\n lines.push(\" # Display firewall status\");\n lines.push(\" - ufw status verbose > /var/log/ufw-bootstrap-status.log\");\n lines.push(\"\");\n\n return lines;\n}\n\n/**\n * Generate complete UFW firewall configuration for Genesis servers.\n *\n * @param options - UFW firewall options (uses DEFAULT_UFW_GENESIS_OPTIONS if not provided)\n * @returns Object with packages, writeFiles, and runCmd arrays\n */\nexport function generateUFWFirewallForGenesis(\n options: UFWFirewallOptions = DEFAULT_UFW_GENESIS_OPTIONS,\n): {\n packages: string[];\n writeFiles: string[];\n runCmd: string[];\n} {\n return {\n packages: ufwFirewallPackages(),\n writeFiles: ufwFirewallWriteFiles(options),\n runCmd: ufwFirewallRunCmd(options),\n };\n}\n\n/**\n * Generate complete UFW firewall configuration for worker/seed servers.\n *\n * @param options - UFW firewall options (uses DEFAULT_UFW_WORKER_OPTIONS if not provided)\n * @returns Object with packages, writeFiles, and runCmd arrays\n */\nexport function generateUFWFirewallForWorker(\n options: UFWFirewallOptions = DEFAULT_UFW_WORKER_OPTIONS,\n): {\n packages: string[];\n writeFiles: string[];\n runCmd: string[];\n} {\n return {\n packages: ufwFirewallPackages(),\n writeFiles: ufwFirewallWriteFiles(options),\n runCmd: ufwFirewallRunCmd(options),\n };\n}\n",
|
|
18
|
+
"/**\n * Kernel Hardening Cloud-Init Components\n *\n * Composable cloud-init blocks for securing the Linux kernel on new servers.\n * Implements 2026 best practices for network stack hardening, IP spoofing\n * protection, SYN flood mitigation, and secure core dump policies.\n *\n * Background: Public-facing VPS servers are constantly probed and attacked.\n * Default Linux kernel settings prioritize compatibility over security. This\n * module applies CIS Benchmark-aligned hardening via /etc/sysctl.d/ which\n * persists across reboots and overrides defaults.\n *\n * Three composable functions return cloud-init line arrays for splicing into\n * the appropriate YAML sections:\n * - kernelHardeningPackages() → packages: section (currently empty, reserved)\n * - kernelHardeningWriteFiles() → write_files: section (drops sysctl config)\n * - kernelHardeningRunCmd() → runcmd: section (applies settings immediately)\n *\n * Security Measures Implemented:\n * 1. Network Stack Hardening: SYN cookies, ICMP rate limits, martian packet logging\n * 2. IP Spoofing Protection: Reverse path filtering, source address verification\n * 3. SYN Flood Protection: TCP SYN cookies, reuse time_wait connections\n * 4. Core Dump Restrictions: Disable setuid dumps, limit core dump size to 0\n * 5. File Permissions: Hard links, symlinks, FIFO protection\n * 6. Memory Protection: ASLR, randomize_va_space\n *\n * References:\n * - CIS Benchmark for Ubuntu Linux 24.04\n * - NIST SP 800-53 Revision 5\n * - https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt\n */\n\n/**\n * Packages required for kernel hardening.\n * Returns cloud-init YAML lines for the `packages:` section.\n *\n * Note: All kernel hardening is done via sysctl configuration, which uses\n * built-in kernel functionality. No additional packages are required.\n * This function is reserved for future expansion (e.g., auditd, kexec-tools).\n */\nexport function kernelHardeningPackages(): string[] {\n return [\n // Reserved for future packages (auditd, kexec-tools, etc.)\n // Currently empty - all hardening via sysctl\n ];\n}\n\n/**\n * Kernel sysctl configuration file for comprehensive hardening.\n * Returns cloud-init YAML lines for the `write_files:` section.\n *\n * Drops /etc/sysctl.d/99-security-hardening.conf which:\n * - Takes precedence over /etc/sysctl.conf (99- prefix ensures last load)\n * - Persists across reboots (sysctl.d files are applied on boot)\n * - Can be applied immediately via `sysctl --system` (see runcmd)\n *\n * Settings organized by category:\n * 1. IP Spoofing Protection: rp_filter, secure redirects\n * 2. SYN Flood Protection: syncookies, tcp_tw_reuse\n * 3. Network Stack: ICMP rate limits, martian logging, ignore broadcasts\n * 4. Core Dumps: Disabled for setuid programs, limited for all processes\n * 5. Memory Protection: ASLR, randomize_va_space\n * 6. Filesystem: Hard link/symlink protection\n */\nexport function kernelHardeningWriteFiles(): string[] {\n const lines: string[] = [];\n\n lines.push(\" # Kernel hardening: sysctl.d configuration for 2026 best practices\");\n lines.push(\" # This file persists across reboots and overrides /etc/sysctl.conf\");\n lines.push(\" - path: /etc/sysctl.d/99-security-hardening.conf\");\n lines.push(\" owner: root:root\");\n lines.push(\" permissions: '0644'\");\n lines.push(\" content: |\");\n lines.push(\" # =================================================================\");\n lines.push(\" # Kernel Security Hardening Configuration\");\n lines.push(\" # =================================================================\");\n lines.push(\" # Applied via cloud-init for com.hetzner.codespaces\");\n lines.push(\" # Version: 1.0.0 (2026 best practices)\");\n lines.push(\" #\");\n lines.push(\" # This configuration follows CIS Benchmark and NIST guidelines\");\n lines.push(\" # See: /usr/share/doc/linux-doc/sysctl/ for parameter documentation\");\n lines.push(\"\");\n lines.push(\" # =================================================================\");\n lines.push(\" # 1. IP SPOOFING PROTECTION\");\n lines.push(\" # =================================================================\");\n lines.push(\" # Enable reverse path filtering (validates source addresses)\");\n lines.push(\" # Prevents IP spoofing attacks by dropping packets with invalid sources\");\n lines.push(\" net.ipv4.conf.all.rp_filter = 1\");\n lines.push(\" net.ipv4.conf.default.rp_filter = 1\");\n lines.push(\"\");\n lines.push(\" # Log martian packets (packets with impossible addresses)\");\n lines.push(\" # Helps detect spoofing attempts and network misconfigurations\");\n lines.push(\" net.ipv4.conf.all.log_martians = 1\");\n lines.push(\"\");\n lines.push(\" # Disable ICMP redirect acceptance (prevent MITM attacks)\");\n lines.push(\" net.ipv4.conf.all.accept_redirects = 0\");\n lines.push(\" net.ipv4.conf.default.accept_redirects = 0\");\n lines.push(\" net.ipv4.conf.all.secure_redirects = 0\");\n lines.push(\" net.ipv4.conf.default.secure_redirects = 0\");\n lines.push(\"\");\n lines.push(\" # Disable sending ICMP redirects\");\n lines.push(\" net.ipv4.conf.all.send_redirects = 0\");\n lines.push(\" net.ipv4.conf.default.send_redirects = 0\");\n lines.push(\"\");\n lines.push(\" # =================================================================\");\n lines.push(\" # 2. SYN FLOOD PROTECTION\");\n lines.push(\" # =================================================================\");\n lines.push(\" # Enable SYN cookies (protects against SYN flood attacks)\");\n lines.push(\" # Allows server to continue accepting connections under SYN flood\");\n lines.push(\" net.ipv4.tcp_syncookies = 1\");\n lines.push(\"\");\n lines.push(\" # Reuse TIME_WAIT sockets for new connections (safer, faster)\");\n lines.push(\" # Reduces connection table exhaustion under high load\");\n lines.push(\" net.ipv4.tcp_tw_reuse = 1\");\n lines.push(\"\");\n lines.push(\" # Reduce SYN backlog and timeouts for faster detection\");\n lines.push(\" net.ipv4.tcp_max_syn_backlog = 2048\");\n lines.push(\" net.ipv4.tcp_synack_retries = 2\");\n lines.push(\" net.ipv4.tcp_syn_retries = 5\");\n lines.push(\"\");\n lines.push(\" # =================================================================\");\n lines.push(\" # 3. NETWORK STACK HARDENING\");\n lines.push(\" # =================================================================\");\n lines.push(\" # Disable ICMP redirect acceptance (IPv6)\");\n lines.push(\" net.ipv6.conf.all.accept_redirects = 0\");\n lines.push(\" net.ipv6.conf.default.accept_redirects = 0\");\n lines.push(\"\");\n lines.push(\" # Ignore ICMP broadcasts (prevent smurf attacks)\");\n lines.push(\" net.ipv4.icmp_echo_ignore_broadcasts = 1\");\n lines.push(\"\");\n lines.push(\" # Ignore bogus ICMP error responses (prevent ICMP attacks)\");\n lines.push(\" net.ipv4.icmp_ignore_bogus_error_responses = 1\");\n lines.push(\"\");\n lines.push(\" # Enable TCP timestamps (RFC 1323) for better sequence handling\");\n lines.push(\" # Also protects against wrapped sequence number attacks\");\n lines.push(\" net.ipv4.tcp_timestamps = 1\");\n lines.push(\"\");\n lines.push(\" # Enable TCP selective acknowledgments (better performance)\");\n lines.push(\" net.ipv4.tcp_sack = 1\");\n lines.push(\"\");\n lines.push(\" # =================================================================\");\n lines.push(\" # 4. CORE DUMP RESTRICTIONS\");\n lines.push(\" # =================================================================\");\n lines.push(\" # Disable core dumps for setuid programs (prevent privilege escalation)\");\n lines.push(\" fs.suid_dumpable = 0\");\n lines.push(\"\");\n lines.push(\" # Limit core dump size to 0 (disable core dumps)\");\n lines.push(\" # Override in /etc/security/limits.conf if needed for debugging\");\n lines.push(\" kernel.core_pattern = |/bin/false\");\n lines.push(\"\");\n lines.push(\" # =================================================================\");\n lines.push(\" # 5. MEMORY PROTECTION (ASLR)\");\n lines.push(\" # =================================================================\");\n lines.push(\" # Enable Address Space Layout Randomization (full)\");\n lines.push(\" # Makes exploitation of memory corruption vulnerabilities harder\");\n lines.push(\" # 0: Disabled, 1: Conservative, 2: Full (default)\");\n lines.push(\" kernel.randomize_va_space = 2\");\n lines.push(\"\");\n lines.push(\" # =================================================================\");\n lines.push(\" # 6. FILESYSTEM PROTECTION\");\n lines.push(\" # =================================================================\");\n lines.push(\" # Hard link/symlink protection (prevent time-of-check time-of-use)\");\n lines.push(\" fs.protected_hardlinks = 1\");\n lines.push(\" fs.protected_symlinks = 1\");\n lines.push(\"\");\n lines.push(\" # FIFO protection (prevent FIFO attacks on world-writable directories)\");\n lines.push(\" fs.protected_fifos = 2\");\n lines.push(\"\");\n lines.push(\" # Regular file protection (prevent file overwrite attacks)\");\n lines.push(\" fs.protected_regular = 2\");\n lines.push(\"\");\n lines.push(\" # =================================================================\");\n lines.push(\" # 7. NETWORK BEHAVIOR TUNING\");\n lines.push(\" # =================================================================\");\n lines.push(\" # Enable TCP Fast Open (TFO) for reduced latency\");\n lines.push(\" net.ipv4.tcp_fastopen = 3\");\n lines.push(\"\");\n lines.push(\" # Disable source routing (prevent packet routing manipulation)\");\n lines.push(\" net.ipv4.conf.all.accept_source_route = 0\");\n lines.push(\" net.ipv4.conf.default.accept_source_route = 0\");\n lines.push(\" net.ipv6.conf.all.accept_source_route = 0\");\n lines.push(\" net.ipv6.conf.default.accept_source_route = 0\");\n lines.push(\"\");\n lines.push(\" # Enable TCP window scaling (RFC 7323) for high-bandwidth links\");\n lines.push(\" net.ipv4.tcp_window_scaling = 1\");\n lines.push(\"\");\n lines.push(\" # =================================================================\");\n lines.push(\" # 8. SECURITY-RELATED KERNEL PARAMETERS\");\n lines.push(\" # =================================================================\");\n lines.push(\" # Disable magic sysrq key (prevent console-based attacks)\");\n lines.push(\" # 0: Disabled, 1: Enable (for debugging only)\");\n lines.push(\" kernel.sysrq = 0\");\n lines.push(\"\");\n lines.push(\" # Disable kexec system call (prevent kernel replacement)\");\n lines.push(\" # 0: Disabled, 1: Enabled\");\n lines.push(\" kernel.kexec_load = 0\");\n lines.push(\"\");\n lines.push(\" # Disable user namespaces (prevent container breakouts)\");\n lines.push(\" # 0: Disabled, 1: Enabled\");\n lines.push(\" user.max_user_namespaces = 0\");\n lines.push(\"\");\n lines.push(\" # Enable unprivileged bpf disabled (prevent eBPF-based exploits)\");\n lines.push(\" # 0: Disabled, 1: Enabled\");\n lines.push(\" kernel.unprivileged_bpf_disabled = 1\");\n lines.push(\"\");\n lines.push(\" # =================================================================\");\n lines.push(\" # 9. ADDITIONAL HARDENING (2026)\");\n lines.push(\" # =================================================================\");\n lines.push(\" # Disable IPv6 if not needed (uncomment if IPv6 is disabled)\");\n lines.push(\" # net.ipv6.conf.all.disable_ipv6 = 1\");\n lines.push(\" # net.ipv6.conf.default.disable_ipv6 = 1\");\n lines.push(\"\");\n lines.push(\" # Enable dmesg restriction (prevent kernel info leaks)\");\n lines.push(\" kernel.dmesg_restrict = 1\");\n lines.push(\"\");\n lines.push(\" # Restrict ptrace scope (prevent process tracing by non-parent)\");\n lines.push(\" # 0: Traditional, 1: Restricted, 2: Admin-only, 3: No attach\");\n lines.push(\" kernel.yama.ptrace_scope = 2\");\n lines.push(\"\");\n lines.push(\" # =================================================================\");\n lines.push(\" # 10. PERFORMANCE TUNING (safe defaults)\");\n lines.push(\" # =================================================================\");\n lines.push(\" # Increase connection tracking table size (for stateful firewalls)\");\n lines.push(\" net.netfilter.nf_conntrack_max = 262144\");\n lines.push(\"\");\n lines.push(\" # Reduce TCP keepalive timeouts for faster dead peer detection\");\n lines.push(\" net.ipv4.tcp_keepalive_time = 600\");\n lines.push(\" net.ipv4.tcp_keepalive_intvl = 30\");\n lines.push(\" net.ipv4.tcp_keepalive_probes = 3\");\n lines.push(\"\");\n\n return lines;\n}\n\n/**\n * Commands to apply kernel hardening settings immediately at first boot.\n * Returns cloud-init YAML lines for the `runcmd:` section.\n *\n * Order matters:\n * 1. Load all sysctl settings from /etc/sysctl.d/*.conf\n * 2. Apply settings immediately (don't wait for reboot)\n * 3. Log applied settings for audit trail\n * 4. Display summary for cloud-init output verification\n */\nexport function kernelHardeningRunCmd(): string[] {\n const lines: string[] = [];\n\n lines.push(\" # Kernel hardening: apply sysctl settings immediately\");\n lines.push(\" # Settings are already in /etc/sysctl.d/99-security-hardening.conf\");\n lines.push(\"\");\n lines.push(\" # Apply all sysctl settings (overrides defaults immediately)\");\n lines.push(\" - sysctl --system\");\n lines.push(\"\");\n lines.push(\" # Log applied settings for audit trail\");\n lines.push(\" - sysctl -a | grep -E '(rp_filter|syncookies|randomize_va|suid_dump)' > /var/log/kernel-hardening.log 2>&1 || true\");\n lines.push(\"\");\n lines.push(\" # Display summary of critical hardening settings\");\n lines.push(\" - |\");\n lines.push(\" echo '========================================'\");\n lines.push(\" echo 'Kernel Hardening Applied (2026)'\");\n lines.push(\" echo '========================================'\");\n lines.push(\" echo 'IP Spoof Protection: '$(sysctl -n net.ipv4.conf.all.rp_filter)\");\n lines.push(\" echo 'SYN Cookies: '$(sysctl -n net.ipv4.tcp_syncookies)\");\n lines.push(\" echo 'ASLR Level: '$(sysctl -n kernel.randomize_va_space)\");\n lines.push(\" echo 'SUID Core Dumps: '$(sysctl -n fs.suid_dumpable)\");\n lines.push(\" echo 'Hard Links Protected: '$(sysctl -n fs.protected_hardlinks)\");\n lines.push(\" echo 'Ptrace Scope: '$(sysctl -n kernel.yama.ptrace_scope)\");\n lines.push(\" echo '========================================'\");\n lines.push(\"\");\n\n return lines;\n}\n",
|
|
19
|
+
"/**\n * Security Audit Cloud-Init Components\n *\n * Composable cloud-init blocks for running post-bootstrap security audits.\n * Generates comprehensive security reports for verification and compliance.\n *\n * This module runs LAST in the bootstrap sequence, after all other security\n * hardening is applied. It captures the state of the system for verification.\n *\n * Three composable functions return cloud-init line arrays for splicing into\n * the appropriate YAML sections:\n * - securityAuditPackages() → packages: section\n * - securityAuditWriteFiles() → write_files: section\n * - securityAuditRunCmd() → runcmd: section\n */\n\n/**\n * Packages required for security auditing.\n * Returns cloud-init YAML lines for the `packages:` section.\n *\n * - lynis: Comprehensive security auditing tool\n */\nexport function securityAuditPackages(): string[] {\n return [\n \" - lynis\",\n ];\n}\n\n/**\n * Files to write at first boot for security auditing.\n * Returns cloud-init YAML lines for the `write_files:` section.\n *\n * Drops 1 file onto the server:\n *\n * 1. /opt/monitoring/security-audit.sh\n * - Collects security metrics (UFW, fail2ban, sshd, sysctl)\n * - Runs Lynis audit with warnings-only output\n * - Generates JSON report at /var/log/security-audit.json\n * - Logs summary to /var/log/security-audit.log\n */\nexport function securityAuditWriteFiles(): string[] {\n const lines: string[] = [];\n\n // 1. Security audit script - comprehensive security check\n lines.push(\" # Security audit script - runs after all hardening\");\n lines.push(\" - path: /opt/monitoring/security-audit.sh\");\n lines.push(\" owner: root:root\");\n lines.push(\" permissions: '0755'\");\n lines.push(\" content: |\");\n lines.push(\" #!/bin/bash\");\n lines.push(\" set -euo pipefail\");\n lines.push(\" LOGFILE=\\\"/var/log/security-audit.log\\\"\");\n lines.push(\" REPORTFILE=\\\"/var/log/security-audit.json\\\"\");\n lines.push(\" echo \\\"Security Audit started at $(date -Iseconds)\\\" | tee \\\"$LOGFILE\\\"\");\n lines.push(\"\");\n lines.push(\" # Firewall status\");\n lines.push(\" echo \\\"\\\" | tee -a \\\"$LOGFILE\\\"\");\n lines.push(\" echo \\\"=== UFW Firewall Status ===\\\" | tee -a \\\"$LOGFILE\\\"\");\n lines.push(\" ufw status verbose | tee -a \\\"$LOGFILE\\\" || true\");\n lines.push(\"\");\n lines.push(\" # Fail2ban status\");\n lines.push(\" echo \\\"\\\" | tee -a \\\"$LOGFILE\\\"\");\n lines.push(\" echo \\\"=== Fail2ban Status ===\\\" | tee -a \\\"$LOGFILE\\\"\");\n lines.push(\" systemctl status fail2ban --no-pager | tee -a \\\"$LOGFILE\\\" || true\");\n lines.push(\" fail2ban-client status sshd | tee -a \\\"$LOGFILE\\\" || true\");\n lines.push(\"\");\n lines.push(\" # SSHd status\");\n lines.push(\" echo \\\"\\\" | tee -a \\\"$LOGFILE\\\"\");\n lines.push(\" echo \\\"=== SSHd Status ===\\\" | tee -a \\\"$LOGFILE\\\"\");\n lines.push(\" systemctl status ssh --no-pager | tee -a \\\"$LOGFILE\\\" || true\");\n lines.push(\" sshd -T | grep -E '(PasswordAuthentication|PermitRootLogin|MaxStartups)' | tee -a \\\"$LOGFILE\\\" || true\");\n lines.push(\"\");\n lines.push(\" # Kernel hardening status\");\n lines.push(\" echo \\\"\\\" | tee -a \\\"$LOGFILE\\\"\");\n lines.push(\" echo \\\"=== Kernel Hardening Status ===\\\" | tee -a \\\"$LOGFILE\\\"\");\n lines.push(\" sysctl randomize_va_space kptr_restrict tcp_syncookies | tee -a \\\"$LOGFILE\\\" || true\");\n lines.push(\"\");\n lines.push(\" # Lynis audit (warnings only, non-interactive)\");\n lines.push(\" echo \\\"\\\" | tee -a \\\"$LOGFILE\\\"\");\n lines.push(\" echo \\\"=== Lynis Security Audit ===\\\" | tee -a \\\"$LOGFILE\\\"\");\n lines.push(\" lynis audit system --warnings-only --quiet 2>&1 | tee -a \\\"$LOGFILE\\\" || true\");\n lines.push(\"\");\n lines.push(\" # Generate JSON report\");\n lines.push(\" timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)\");\n lines.push(\" ufw_active=$(ufw status | grep -c \\\"Status: active\\\" || echo \\\"0\\\")\");\n lines.push(\" fail2ban_active=$(systemctl is-active fail2ban 2>/dev/null || echo \\\"inactive\\\")\");\n lines.push(\" sshd_active=$(systemctl is-active ssh 2>/dev/null || echo \\\"inactive\\\")\");\n lines.push(\" aslr_enabled=$(cat /proc/sys/kernel/randomize_va_space 2>/dev/null || echo \\\"0\\\")\");\n lines.push(\" cat > \\\"$REPORTFILE\\\" <<AUDEOF\");\n lines.push(\" {\");\n lines.push(\" \\\"timestamp\\\": \\\"$timestamp\\\",\");\n lines.push(\" \\\"firewall\\\": { \\\"active\\\": $ufw_active },\");\n lines.push(\" \\\"fail2ban\\\": { \\\"active\\\": \\\"$fail2ban_active\\\" },\");\n lines.push(\" \\\"sshd\\\": { \\\"active\\\": \\\"$sshd_active\\\" },\");\n lines.push(\" \\\"kernel_hardening\\\": { \\\"aslr_enabled\\\": $aslr_enabled }\");\n lines.push(\" }\");\n lines.push(\" AUDEOF\");\n lines.push(\" echo \\\"Security Audit completed at $(date -Iseconds)\\\" | tee -a \\\"$LOGFILE\\\"\");\n lines.push(\" echo \\\"Report saved to $REPORTFILE\\\" | tee -a \\\"$LOGFILE\\\"\");\n lines.push(\"\");\n\n return lines;\n}\n\n/**\n * Commands to run security audit at first boot.\n * Returns cloud-init YAML lines for the `runcmd:` section.\n *\n * Order matters:\n * 1. Create /opt/monitoring directory (audit script target)\n * 2. Run security audit script (captures state after all hardening)\n * 3. Log audit completion for verification\n */\nexport function securityAuditRunCmd(): string[] {\n const lines: string[] = [];\n\n lines.push(\" # Security audit: run comprehensive security check\");\n lines.push(\" - mkdir -p /opt/monitoring\");\n lines.push(\" - /opt/monitoring/security-audit.sh\");\n lines.push(\" - echo \\\"Security audit completed at $(date -Iseconds)\\\" | tee -a /root/.bootstrap-status\");\n lines.push(\"\");\n\n return lines;\n}\n",
|
|
20
|
+
"/**\n * Genesis Server Bootstrap Generator\n *\n * Generates cloud-init YAML scripts for Genesis server provisioning.\n * Genesis is a bootstrap/control plane node that runs com.hetzner.codespaces\n * and manages Hetzner VPS worker nodes.\n *\n * Security Integration:\n * This module integrates all security modules in the correct order:\n * 1. UFW Firewall (network-level defense)\n * 2. Kernel Hardening (system-level hardening)\n * 3. SSH Hardening (service-level hardening)\n * 4. Security Audit (verification and reporting)\n */\n\nimport {\n sshdHardeningPackages,\n sshdHardeningWriteFiles,\n sshdHardeningRunCmd,\n} from \"./ssh-hardening\";\nimport {\n kernelHardeningPackages,\n kernelHardeningWriteFiles,\n kernelHardeningRunCmd,\n} from \"./kernel-hardening\";\nimport {\n ufwFirewallPackages,\n ufwFirewallWriteFiles,\n ufwFirewallRunCmd,\n generateUFWFirewallForGenesis,\n DEFAULT_UFW_GENESIS_OPTIONS,\n} from \"./firewall\";\nimport {\n securityAuditPackages,\n securityAuditWriteFiles,\n securityAuditRunCmd,\n} from \"./security-audit\";\n\nexport interface GenesisBootstrapOptions {\n /** Admin SSH public key for genesis user */\n adminSSHKey: string;\n\n /** Genesis repository URL (default: https://github.com/ebowwa/com.hetzner.codespaces) */\n genesisRepo?: string;\n\n /** Genesis repository branch or tag */\n genesisBranch?: string;\n\n /** Genesis server hostname (default: genesis) */\n hostname?: string;\n\n /** Default Hetzner server type for workers */\n defaultServerType?: string;\n\n /** Default Hetzner location */\n defaultLocation?: string;\n\n /** Maximum concurrent workers */\n maxWorkers?: string;\n\n /** Additional packages to install */\n packages?: string[];\n\n /** Additional commands to run after genesis setup */\n additionalCommands?: string[];\n\n /** Enable security hardening (default: true) */\n enableSecurity?: boolean;\n}\n\n/**\n * Generate a cloud-init YAML script for Genesis server bootstrap\n *\n * @param options - Genesis bootstrap configuration options\n * @returns Cloud-init YAML string\n */\nexport function generateGenesisBootstrap(options: GenesisBootstrapOptions): string {\n const {\n adminSSHKey,\n genesisRepo = \"https://github.com/ebowwa/com.hetzner.codespaces\",\n genesisBranch = \"main\",\n hostname = \"genesis\",\n defaultServerType = \"cpx11\",\n defaultLocation = \"fsn1\",\n maxWorkers = \"10\",\n packages = [],\n additionalCommands = [],\n enableSecurity = true,\n } = options;\n\n if (!adminSSHKey) {\n throw new Error(\"adminSSHKey is required for Genesis bootstrap\");\n }\n\n const lines: string[] = [];\n\n // Cloud-config header\n lines.push(\"#cloud-config\");\n lines.push(\"# Genesis Server Bootstrap Configuration\");\n lines.push(\"# Version: 1.0.0\");\n lines.push(\"\");\n lines.push(\"# This cloud-init config bootstraps a Genesis server that:\");\n lines.push(\"# - Runs com.hetzner.codespaces web application\");\n lines.push(\"# - Uses the existing Hetzner API to create any server\");\n lines.push(\"# - Can be ephemeral and recreated at any time\");\n lines.push(\"\");\n lines.push(\"# IMPORTANT: Never store secrets in cloud-init! Use Vault/SOPS/external sources.\");\n lines.push(\"\");\n\n // STAGE 1: Network & Early Setup\n lines.push(\"# =====================================================\");\n lines.push(\"# STAGE 1: Network & Early Setup (Network stage)\");\n lines.push(\"# =====================================================\");\n lines.push(\"\");\n lines.push(`hostname: ${hostname}`);\n lines.push(\"manage_etc_hosts: true\");\n lines.push(\"timezone: UTC\");\n lines.push(\"\");\n\n // STAGE 2: SSH & Security\n lines.push(\"# =====================================================\");\n lines.push(\"# STAGE 2: SSH & Security (Network stage)\");\n lines.push(\"# =====================================================\");\n lines.push(\"\");\n lines.push(\"ssh_pwauth: false\");\n lines.push(\"\");\n lines.push(\"# Create genesis service user\");\n lines.push(\"users:\");\n lines.push(\" - name: genesis\");\n lines.push(\" gecos: Genesis Service Account\");\n lines.push(\" primary_group: genesis\");\n lines.push(\" groups: docker,wheel\");\n lines.push(\" sudo: ALL=(ALL) NOPASSWD:ALL\");\n lines.push(\" shell: /bin/bash\");\n lines.push(\" lock_passwd: true\");\n lines.push(\" ssh_authorized_keys:\");\n lines.push(` - ${adminSSHKey}`);\n lines.push(\"\");\n\n // STAGE 3: Package Management\n lines.push(\"# =====================================================\");\n lines.push(\"# STAGE 3: Package Management (Config stage)\");\n lines.push(\"# =====================================================\");\n lines.push(\"\");\n lines.push(\"package_update: true\");\n lines.push(\"package_upgrade: false\");\n lines.push(\"package_reboot_if_required: true\");\n lines.push(\"\");\n lines.push(\"packages:\");\n lines.push(\" - curl\");\n lines.push(\" - wget\");\n lines.push(\" - git\");\n lines.push(\" - unzip\");\n lines.push(\" - jq\");\n lines.push(\" - build-essential\");\n\n // Security Module 1: UFW Firewall packages\n if (enableSecurity) {\n lines.push(\" # Security: UFW Firewall\");\n lines.push(...ufwFirewallPackages());\n }\n\n // Security Module 2: Kernel hardening packages\n if (enableSecurity) {\n lines.push(\" # Security: Kernel hardening\");\n lines.push(...kernelHardeningPackages());\n }\n\n // Security Module 3: SSH hardening packages (fail2ban)\n if (enableSecurity) {\n lines.push(\" # Security: SSH hardening\");\n lines.push(...sshdHardeningPackages());\n }\n\n // Security Module 4: Security audit packages (lynis)\n if (enableSecurity) {\n lines.push(\" # Security: Security audit\");\n lines.push(...securityAuditPackages());\n }\n\n // Add additional packages\n for (const pkg of packages) {\n lines.push(` - ${pkg}`);\n }\n lines.push(\"\");\n\n // STAGE 4: Application Setup\n lines.push(\"# =====================================================\");\n lines.push(\"# STAGE 4: Application Setup (Config stage)\");\n lines.push(\"# =====================================================\");\n lines.push(\"\");\n lines.push(\"write_files:\");\n\n // Genesis directories\n lines.push(\" # Genesis application directories\");\n lines.push(\" - path: /opt/genesis\");\n lines.push(\" owner: genesis:genesis\");\n lines.push(\" permissions: '0755'\");\n lines.push(\"\");\n lines.push(\" - path: /opt/genesis/data\");\n lines.push(\" owner: genesis:genesis\");\n lines.push(\" permissions: '0755'\");\n lines.push(\"\");\n lines.push(\" - path: /var/log/genesis\");\n lines.push(\" owner: genesis:genesis\");\n lines.push(\" permissions: '0755'\");\n lines.push(\"\");\n\n // Environment file template\n lines.push(\" # Environment file template (do NOT include actual secrets)\");\n lines.push(\" - path: /etc/default/genesis.template\");\n lines.push(\" owner: genesis:genesis\");\n lines.push(\" permissions: '0640'\");\n lines.push(\" content: |\");\n lines.push(\" # Genesis Server Environment Configuration\");\n lines.push(\" # Copy this to /etc/default/genesis and fill in required values\");\n lines.push(\" #\");\n lines.push(\" # DO NOT commit actual secrets to version control!\");\n lines.push(\"\");\n lines.push(\" # Application Settings\");\n lines.push(\" NODE_ENV=production\");\n lines.push(` PORT=3000`);\n lines.push(` HOST=0.0.0.0`);\n lines.push(\"\");\n lines.push(\" # Hetzner API (REQUIRED - use Vault or Secrets Manager in production)\");\n lines.push(\" # HETZNER_API_TOKEN should be set securely after bootstrap\");\n lines.push(\" HETZNER_DEFAULT_TYPE=\" + defaultServerType);\n lines.push(\" HETZNER_DEFAULT_LOCATION=\" + defaultLocation);\n lines.push(\" MAX_WORKER_NODES=\" + maxWorkers);\n lines.push(\"\");\n\n // Systemd service unit\n lines.push(\" # Genesis systemd service unit\");\n lines.push(\" - path: /etc/systemd/system/genesis.service\");\n lines.push(\" owner: root:root\");\n lines.push(\" permissions: '0644'\");\n lines.push(\" content: |\");\n lines.push(\" [Unit]\");\n lines.push(\" Description=Genesis Application Server (com.hetzner.codespaces)\");\n lines.push(\" Documentation=https://github.com/ebowwa/com.hetzner.codespaces\");\n lines.push(\" After=network-online.target\");\n lines.push(\" Wants=network-online.target\");\n lines.push(\"\");\n lines.push(\" [Service]\");\n lines.push(\" Type=simple\");\n lines.push(\" User=genesis\");\n lines.push(\" Group=genesis\");\n lines.push(\" WorkingDirectory=/opt/genesis\");\n lines.push(\"\");\n lines.push(\" # Execution\");\n lines.push(\" ExecStart=/usr/bin/bun start\");\n lines.push(\" ExecReload=/bin/kill -HUP $MAINPID\");\n lines.push(\"\");\n lines.push(\" # Restart Policy (with rate limiting)\");\n lines.push(\" Restart=on-failure\");\n lines.push(\" RestartSec=5s\");\n lines.push(\" StartLimitIntervalSec=300\");\n lines.push(\" StartLimitBurst=5\");\n lines.push(\"\");\n lines.push(\" # Logging\");\n lines.push(\" StandardOutput=journal\");\n lines.push(\" StandardError=journal\");\n lines.push(\" SyslogIdentifier=genesis\");\n lines.push(\"\");\n lines.push(\" # Environment\");\n lines.push(' Environment=\"NODE_ENV=production\"');\n lines.push(\" EnvironmentFile=/etc/default/genesis\");\n lines.push(\" EnvironmentFile=-/etc/default/genesis.local\");\n lines.push(\"\");\n lines.push(\" # Resource Limits\");\n lines.push(\" LimitNOFILE=65536\");\n lines.push(\"\");\n \n // Security hardening for genesis service\n if (enableSecurity) {\n lines.push(\" # Security Hardening\");\n lines.push(\" NoNewPrivileges=true\");\n lines.push(\" PrivateTmp=true\");\n lines.push(\" ProtectSystem=strict\");\n lines.push(\" ProtectHome=true\");\n lines.push(\" ReadWritePaths=/opt/genesis/data /var/log/genesis\");\n } else {\n lines.push(\" # Security Hardening (minimal)\");\n lines.push(\" NoNewPrivileges=false\");\n lines.push(\" PrivateTmp=false\");\n }\n lines.push(\"\");\n lines.push(\" [Install]\");\n lines.push(\" WantedBy=multi-user.target\");\n lines.push(\"\");\n\n // Bootstrap status tracking\n lines.push(\" # Bootstrap status tracking\");\n lines.push(\" - path: /root/.genesis-bootstrap-status\");\n lines.push(\" owner: root:root\");\n lines.push(\" permissions: '0644'\");\n lines.push(\" content: |\");\n lines.push(\" status=started\");\n lines.push(\" started_at=$(date -Iseconds)\");\n lines.push(\" source=cloud-init\");\n lines.push(\" version=1.0.0\");\n if (enableSecurity) {\n lines.push(\" security=enabled\");\n }\n lines.push(\"\");\n\n // Add bun to /etc/environment\n lines.push(\" # Add bun to /etc/environment for all users/shells\");\n lines.push(\" # Format: Simple KEY=\\\"value\\\" pairs, no variable expansion\");\n lines.push(\" - path: /etc/environment\");\n lines.push(\" owner: root:root\");\n lines.push(\" permissions: '0644'\");\n lines.push(\" content: |\");\n lines.push(' PATH=\"/root/.bun/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"');\n lines.push(\"\");\n\n // Security Module 1: UFW Firewall configuration files\n if (enableSecurity) {\n lines.push(\" # Security Module 1: UFW Firewall configuration\");\n lines.push(...ufwFirewallWriteFiles(DEFAULT_UFW_GENESIS_OPTIONS));\n }\n\n // Security Module 2: Kernel hardening configuration files\n if (enableSecurity) {\n lines.push(\" # Security Module 2: Kernel hardening\");\n lines.push(...kernelHardeningWriteFiles());\n }\n\n // Security Module 3: SSH hardening configuration files\n if (enableSecurity) {\n lines.push(\" # Security Module 3: SSH hardening\");\n lines.push(...sshdHardeningWriteFiles());\n }\n\n // Security Module 4: Security audit script\n if (enableSecurity) {\n lines.push(\" # Security Module 4: Security audit\");\n lines.push(...securityAuditWriteFiles());\n }\n\n // STAGE 5: Run Commands\n lines.push(\"# =====================================================\");\n lines.push(\"# STAGE 5: Run Commands (Config stage)\");\n lines.push(\"# =====================================================\");\n lines.push(\"\");\n lines.push(\"runcmd:\");\n\n // Install Bun\n lines.push(\" # Install Bun runtime\");\n lines.push(\" - curl -fsSL https://bun.sh/install | bash\");\n lines.push(\"\");\n\n // Clone genesis application\n lines.push(\" # Clone/pull genesis application\");\n const cloneCmd = genesisBranch\n ? `git clone --depth 1 --branch ${genesisBranch} ${genesisRepo} /opt/genesis`\n : `git clone --depth 1 ${genesisRepo} /opt/genesis`;\n\n lines.push(` - |`);\n lines.push(` if [ ! -d /opt/genesis/.git ]; then`);\n lines.push(` ${cloneCmd}`);\n lines.push(` else`);\n lines.push(` cd /opt/genesis && git pull`);\n lines.push(` fi`);\n lines.push(\"\");\n\n // Install dependencies\n lines.push(\" # Install dependencies\");\n lines.push(\" - cd /opt/genesis && bun install\");\n lines.push(\"\");\n\n // Build application\n lines.push(\" # Build application (if needed)\");\n lines.push(\" - cd /opt/genesis && bun run build\");\n lines.push(\"\");\n\n // Configure environment warning\n lines.push(\" # Configure environment (prompt for secrets or use external source)\");\n lines.push(\" - |\");\n lines.push(` echo \"WARNING: HETZNER_API_TOKEN must be configured in /etc/default/genesis\"`);\n lines.push(\"\");\n\n // Enable and start service\n lines.push(\" # Enable and start genesis service\");\n lines.push(\" - systemctl daemon-reload\");\n lines.push(\" - systemctl enable genesis.service\");\n lines.push(\" - systemctl start genesis.service\");\n lines.push(\"\");\n\n // Security Module 1: UFW Firewall activation (runs first)\n if (enableSecurity) {\n lines.push(\" # Security Module 1: Activate UFW Firewall\");\n lines.push(...ufwFirewallRunCmd(DEFAULT_UFW_GENESIS_OPTIONS));\n }\n\n // Security Module 2: Kernel hardening activation\n if (enableSecurity) {\n lines.push(\" # Security Module 2: Apply kernel hardening\");\n lines.push(...kernelHardeningRunCmd());\n }\n\n // Security Module 3: SSH hardening activation\n if (enableSecurity) {\n lines.push(\" # Security Module 3: Activate SSH hardening\");\n lines.push(...sshdHardeningRunCmd());\n }\n\n // Security Module 4: Security audit (runs last)\n if (enableSecurity) {\n lines.push(\" # Security Module 4: Run security audit\");\n lines.push(...securityAuditRunCmd());\n }\n\n // Mark bootstrap complete\n lines.push(\" # Mark bootstrap complete\");\n lines.push(' - echo \"status=complete\" >> /root/.genesis-bootstrap-status');\n lines.push(' - echo \"completed_at=$(date -Iseconds)\" >> /root/.genesis-bootstrap-status');\n if (enableSecurity) {\n lines.push(' - echo \"security_hardening=applied\" >> /root/.genesis-bootstrap-status');\n }\n lines.push(\"\");\n\n // Additional commands\n if (additionalCommands.length > 0) {\n lines.push(\" # Additional custom commands\");\n for (const cmd of additionalCommands) {\n lines.push(` - ${cmd}`);\n }\n lines.push(\"\");\n }\n\n // STAGE 6: Final\n lines.push(\"# =====================================================\");\n lines.push(\"# STAGE 6: Final (Final stage)\");\n lines.push(\"# =====================================================\");\n lines.push(\"\");\n lines.push('final_message: \"Genesis server bootstrap completed after $UPTIME seconds\"');\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Generate a minimal cloud-init script that uses #include to fetch from a URL\n *\n * This is useful for larger bootstrap scripts or when you want to update\n * the bootstrap without code changes.\n *\n * @param url - URL to fetch the cloud-init config from\n * @returns Cloud-init YAML string with #include directive\n */\nexport function generateRemoteGenesisBootstrap(url: string): string {\n return `#include\\n${url}`;\n}\n\n/**\n * Genesis bootstrap configuration presets for common scenarios\n */\nexport const GenesisBootstrapPresets = {\n /**\n * Default Genesis server with standard configuration and full security\n */\n default: (adminSSHKey: string) =>\n generateGenesisBootstrap({\n adminSSHKey,\n }),\n\n /**\n * Genesis server with ARM architecture (CAX series - best €/performance)\n */\n arm: (adminSSHKey: string) =>\n generateGenesisBootstrap({\n adminSSHKey,\n defaultServerType: \"cax21\",\n }),\n\n /**\n * Genesis server with high-performance CPU (CPX series)\n */\n performance: (adminSSHKey: string) =>\n generateGenesisBootstrap({\n adminSSHKey,\n defaultServerType: \"cpx21\",\n }),\n\n /**\n * Genesis server with dedicated CPU (CCX series)\n */\n dedicated: (adminSSHKey: string) =>\n generateGenesisBootstrap({\n adminSSHKey,\n defaultServerType: \"ccx13\",\n }),\n\n /**\n * Development Genesis server without security hardening\n */\n development: (adminSSHKey: string) =>\n generateGenesisBootstrap({\n adminSSHKey,\n enableSecurity: false,\n packages: [\"htop\", \"vim\", \"tmux\", \"strace\"],\n additionalCommands: [\n \"echo 'Genesis development server ready' | wall\",\n ],\n }),\n\n /**\n * Secure Genesis server with full hardening and verbose logging\n */\n secure: (adminSSHKey: string) =>\n generateGenesisBootstrap({\n adminSSHKey,\n packages: [\"lynis\"],\n additionalCommands: [\n \"echo 'Genesis secure server ready - security audit completed' | wall\",\n ],\n }),\n} as const;\n",
|
|
21
|
+
"/**\n * Cloud-Init Bootstrap Generator\n *\n * Generates cloud-init YAML scripts for first-boot server provisioning.\n * Handles seed repository installation and initial setup.\n *\n * Security Integration:\n * This module integrates all security modules in the correct order:\n * 1. UFW Firewall (network-level defense)\n * 2. Kernel Hardening (system-level hardening)\n * 3. SSH Hardening (service-level hardening)\n * 4. Security Audit (verification and reporting)\n */\n\nimport {\n sshdHardeningPackages,\n sshdHardeningWriteFiles,\n sshdHardeningRunCmd,\n} from \"./ssh-hardening\";\nimport {\n ufwFirewallPackages,\n ufwFirewallWriteFiles,\n ufwFirewallRunCmd,\n DEFAULT_UFW_WORKER_OPTIONS,\n} from \"./firewall\";\nimport {\n kernelHardeningPackages,\n kernelHardeningWriteFiles,\n kernelHardeningRunCmd,\n} from \"./kernel-hardening\";\nimport {\n securityAuditPackages,\n securityAuditWriteFiles,\n securityAuditRunCmd,\n} from \"./security-audit\";\n\nexport interface BootstrapOptions {\n /** Seed repository URL (default: https://github.com/ebowwa/seed) */\n seedRepo?: string;\n /** Seed repository branch (default: dev) */\n seedBranch?: string;\n /** Installation path (default: /root/seed) */\n seedPath?: string;\n /** Whether to run setup.sh non-interactively (default: true) */\n runSetup?: boolean;\n /** Additional environment variables for setup.sh */\n setupEnv?: Record<string, string>;\n /** Additional packages to install */\n packages?: string[];\n /** Additional commands to run after seed installation */\n additionalCommands?: string[];\n /** Enable security hardening (default: true) */\n enableSecurity?: boolean;\n}\n\n/**\n * Generate a cloud-init YAML script for seed installation\n *\n * @param options - Bootstrap configuration options\n * @returns Cloud-init YAML string\n */\nexport function generateSeedBootstrap(options: BootstrapOptions = {}): string {\n const {\n seedRepo = \"https://github.com/ebowwa/seed\",\n seedBranch = \"dev\",\n seedPath = \"/root/seed\",\n runSetup = true,\n setupEnv = {},\n packages = [],\n additionalCommands = [],\n enableSecurity = true,\n } = options;\n\n const lines: string[] = [];\n\n // Cloud-config header\n lines.push(\"#cloud-config\");\n lines.push(\"\");\n\n // System updates\n lines.push(\"# Update system packages\");\n lines.push(\"package_update: true\");\n lines.push(\"package_upgrade: true\");\n lines.push(\"\");\n\n // Required packages\n lines.push(\"# Install required packages\");\n lines.push(\"packages:\");\n lines.push(\" - git\");\n lines.push(\" - curl\");\n lines.push(\" - jq\");\n lines.push(\" - unzip\");\n lines.push(\" - tmux\");\n\n // Security Module 1: UFW Firewall packages\n if (enableSecurity) {\n lines.push(\" # Security: UFW Firewall\");\n lines.push(...ufwFirewallPackages());\n }\n\n // Security Module 2: Kernel hardening packages\n if (enableSecurity) {\n lines.push(\" # Security: Kernel hardening\");\n lines.push(...kernelHardeningPackages());\n }\n\n // Security Module 3: SSH hardening packages (fail2ban)\n if (enableSecurity) {\n lines.push(\" # Security: SSH hardening\");\n lines.push(...sshdHardeningPackages());\n }\n\n // Security Module 4: Security audit packages (lynis)\n if (enableSecurity) {\n lines.push(\" # Security: Security audit\");\n lines.push(...securityAuditPackages());\n }\n\n // Add additional packages\n for (const pkg of packages) {\n lines.push(` - ${pkg}`);\n }\n lines.push(\"\");\n\n // Status tracking file\n lines.push(\"# Write bootstrap status file\");\n lines.push(\"write_files:\");\n lines.push(\" - path: /root/.bootstrap-status\");\n lines.push(\" owner: root:root\");\n lines.push(\" permissions: '0644'\");\n lines.push(\" content: |\");\n lines.push(\" status=started\");\n lines.push(\" started_at=$(date -Iseconds)\");\n lines.push(\" source=cloud-init\");\n if (enableSecurity) {\n lines.push(\" security=enabled\");\n }\n lines.push(\"\");\n\n // Add bun to system-wide PATH via /etc/environment\n // NOTE: /etc/environment uses simple KEY=\"value\" format (no variables, no comments)\n // We need to replace PATH rather than append, and include all standard paths\n lines.push(\" # Add bun to /etc/environment for all users/shells\");\n lines.push(\" # Format: Simple KEY=\\\"value\\\" pairs, no variable expansion\");\n lines.push(\" - path: /etc/environment\");\n lines.push(\" owner: root:root\");\n lines.push(\" permissions: '0644'\");\n lines.push(\" content: |\");\n lines.push(\" PATH=\\\"/root/.bun/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"\");\n lines.push(\"\");\n\n // Security Module 1: UFW Firewall configuration files\n if (enableSecurity) {\n lines.push(\" # Security Module 1: UFW Firewall configuration\");\n lines.push(...ufwFirewallWriteFiles(DEFAULT_UFW_WORKER_OPTIONS));\n }\n\n // Security Module 2: Kernel hardening configuration files\n if (enableSecurity) {\n lines.push(\" # Security Module 2: Kernel hardening\");\n lines.push(...kernelHardeningWriteFiles());\n }\n\n // Security Module 3: SSH hardening configuration files\n if (enableSecurity) {\n lines.push(\" # Security Module 3: SSH hardening\");\n lines.push(...sshdHardeningWriteFiles());\n }\n\n // Security Module 4: Security audit script\n if (enableSecurity) {\n lines.push(\" # Security Module 4: Security audit\");\n lines.push(...securityAuditWriteFiles());\n }\n\n // Node-agent systemd service\n lines.push(\" # Node-agent systemd service for Ralph Loop orchestration\");\n lines.push(\" - path: /etc/systemd/system/node-agent.service\");\n lines.push(\" owner: root:root\");\n lines.push(\" permissions: '0644'\");\n lines.push(\" content: |\");\n lines.push(\" [Unit]\");\n lines.push(\" Description=Node Agent for Ralph Loop Orchestration\");\n lines.push(\" Documentation=https://github.com/ebowwa/seed\");\n lines.push(\" After=network-online.target\");\n lines.push(\" Wants=network-online.target\");\n lines.push(\"\");\n lines.push(\" [Service]\");\n lines.push(\" Type=simple\");\n lines.push(\" User=root\");\n lines.push(` WorkingDirectory=${seedPath}/node-agent`);\n lines.push(\" ExecStart=/root/.bun/bin/bun run src/index.ts\");\n lines.push(` EnvironmentFile=-${seedPath}/node-agent/.env`);\n lines.push(\" Environment=PORT=8911\");\n lines.push(\" Restart=always\");\n lines.push(\" RestartSec=10\");\n lines.push(\" StandardOutput=journal\");\n lines.push(\" StandardError=journal\");\n lines.push(\" SyslogIdentifier=node-agent\");\n lines.push(\"\");\n // Security hardening for node-agent service\n if (enableSecurity) {\n lines.push(\" # Security hardening\");\n lines.push(\" NoNewPrivileges=true\");\n lines.push(\" PrivateTmp=true\");\n lines.push(\" ProtectSystem=strict\");\n lines.push(\" ProtectHome=true\");\n lines.push(\" ReadOnlyPaths=/\");\n lines.push(\" ReadWritePaths=/var/log \" + seedPath + \"/node-agent\");\n }\n lines.push(\"\");\n lines.push(\" [Install]\");\n lines.push(\" WantedBy=multi-user.target\");\n lines.push(\"\");\n\n // Run commands\n lines.push(\"# Bootstrap commands\");\n lines.push(\"runcmd:\");\n\n // Install Bun and create node symlink\n lines.push(\" # Install Bun\");\n lines.push(\" - curl -fsSL https://bun.sh/install | bash\");\n lines.push(\" - ln -sf /root/.bun/bin/bun /root/.bun/bin/node # Create 'node' symlink to bun\");\n lines.push(\"\");\n\n // Clone seed repository\n lines.push(` # Clone seed repository`);\n lines.push(` - git clone --depth 1 --branch ${seedBranch} ${seedRepo} ${seedPath}`);\n lines.push(\"\");\n\n if (runSetup) {\n // Build environment variables\n const envVars = [\"NONINTERACTIVE=1\", ...Object.entries(setupEnv).map(([k, v]) => `${k}=${v}`)];\n const envString = envVars.join(\" \");\n\n lines.push(` # Run seed setup non-interactively`);\n lines.push(` - cd ${seedPath} && ${envString} bash ./setup.sh 2>&1 | tee /var/log/seed-setup.log`);\n lines.push(\"\");\n\n // Create completion marker\n lines.push(` # Mark setup complete`);\n lines.push(` - touch ${seedPath}/.seed-setup-complete`);\n lines.push(\"\");\n }\n\n // Additional commands\n if (additionalCommands.length > 0) {\n lines.push(` # Additional custom commands`);\n for (const cmd of additionalCommands) {\n lines.push(` - ${cmd}`);\n }\n lines.push(\"\");\n }\n\n // Security Module 1: UFW Firewall activation (runs first)\n if (enableSecurity) {\n lines.push(\" # Security Module 1: Activate UFW Firewall\");\n lines.push(...ufwFirewallRunCmd(DEFAULT_UFW_WORKER_OPTIONS));\n }\n\n // Security Module 2: Kernel hardening activation\n if (enableSecurity) {\n lines.push(\" # Security Module 2: Apply kernel hardening\");\n lines.push(...kernelHardeningRunCmd());\n }\n\n // Security Module 3: SSH hardening activation\n if (enableSecurity) {\n lines.push(\" # Security Module 3: Activate SSH hardening\");\n lines.push(...sshdHardeningRunCmd());\n }\n\n // Security Module 4: Security audit (runs last)\n if (enableSecurity) {\n lines.push(\" # Security Module 4: Run security audit\");\n lines.push(...securityAuditRunCmd());\n }\n\n // Mark bootstrap complete\n lines.push(` # Mark bootstrap complete`);\n lines.push(` - echo \"status=complete\" >> /root/.bootstrap-status`);\n lines.push(` - echo \"completed_at=$(date -Iseconds)\" >> /root/.bootstrap-status`);\n if (enableSecurity) {\n lines.push(` - echo \"security_hardening=applied\" >> /root/.bootstrap-status`);\n }\n lines.push(\"\");\n lines.push(\" # Start node-agent service\");\n lines.push(\" - systemctl daemon-reload\");\n lines.push(\" - systemctl enable node-agent\");\n lines.push(\" - systemctl start node-agent\");\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Generate a minimal cloud-init script that uses #include to fetch from a URL\n *\n * This is useful for larger bootstrap scripts or when you want to update\n * the bootstrap without code changes.\n *\n * @param url - URL to fetch the cloud-init config from\n * @returns Cloud-init YAML string with #include directive\n */\nexport function generateRemoteBootstrap(url: string): string {\n return `#include\\n${url}`;\n}\n\n/**\n * Bootstrap configuration presets for common scenarios\n */\nexport const BootstrapPresets = {\n /**\n * Default seed installation with setup.sh and full security hardening\n */\n default: () => generateSeedBootstrap(),\n\n /**\n * Seed installation with full security hardening and verbose logging\n */\n secure: () =>\n generateSeedBootstrap({\n setupEnv: {\n DEBUG: \"1\",\n VERBOSE: \"1\",\n },\n }),\n\n /**\n * Seed installation without running setup.sh (useful for debugging)\n */\n cloneOnly: () => generateSeedBootstrap({ runSetup: false }),\n\n /**\n * Development bootstrap without security hardening (for testing)\n */\n development: () =>\n generateSeedBootstrap({\n enableSecurity: false,\n packages: [\"htop\", \"vim\", \"strace\"],\n }),\n\n /**\n * Verbose bootstrap with logging enabled\n */\n verbose: () =>\n generateSeedBootstrap({\n setupEnv: {\n DEBUG: \"1\",\n VERBOSE: \"1\",\n },\n }),\n} as const;\n\n// Re-export Genesis bootstrap functions\nexport {\n generateGenesisBootstrap,\n generateRemoteGenesisBootstrap,\n GenesisBootstrapPresets,\n type GenesisBootstrapOptions,\n} from \"./genesis\";\n\n// Re-export SSH hardening components so callers can compose custom\n// cloud-init scripts with hardening baked in (e.g. for non-standard node types)\nexport {\n sshdHardeningPackages,\n sshdHardeningWriteFiles,\n sshdHardeningRunCmd,\n} from \"./ssh-hardening\";\n\n// Re-export UFW firewall components\nexport {\n ufwFirewallPackages,\n ufwFirewallWriteFiles,\n ufwFirewallRunCmd,\n DEFAULT_UFW_WORKER_OPTIONS,\n DEFAULT_UFW_GENESIS_OPTIONS,\n generateUFWFirewallForGenesis,\n generateUFWFirewallForWorker,\n type UFWFirewallOptions,\n} from \"./firewall\";\n\n// Re-export kernel hardening components\nexport {\n kernelHardeningPackages,\n kernelHardeningWriteFiles,\n kernelHardeningRunCmd,\n} from \"./kernel-hardening\";\n\n// Re-export security audit components\nexport {\n securityAuditPackages,\n securityAuditWriteFiles,\n securityAuditRunCmd,\n} from \"./security-audit\";\n",
|
|
22
|
+
"/**\n * Doppler Onboarding\n *\n * Configure Doppler CLI service token on remote servers.\n * This enables doppler run to inject secrets into processes.\n */\n\nimport type { SSHOptions } from \"@ebowwa/terminal/types\";\n\nexport interface DopplerConfig {\n token: string;\n project?: string;\n config?: string;\n}\n\n/**\n * Configure Doppler on a remote server\n *\n * @param host - Server IP or hostname\n * @param config - Doppler configuration\n * @param sshOptions - SSH options\n * @returns Success status\n */\nexport async function onboardDoppler(\n host: string,\n config: DopplerConfig,\n sshOptions: Partial<SSHOptions> = {}\n): Promise<{ success: boolean; message: string }> {\n const { execSSH } = await import(\"@ebowwa/terminal/client\");\n\n const { token, project = \"seed\", config: dopplerConfig = \"prd\" } = config;\n\n try {\n // Step 1: Configure Doppler service token\n const configureCmd = [\n `doppler configure set token ${token}`,\n `doppler configure set project ${project}`,\n `doppler configure set config ${dopplerConfig}`,\n ].join(\" && \");\n\n await execSSH(configureCmd, {\n host,\n user: \"root\",\n ...sshOptions\n });\n\n // Step 2: Verify configuration by fetching a secret\n const verifyCmd = `doppler secrets get --config ${dopplerConfig} --project ${project} --json 2>/dev/null | head -5`;\n\n await execSSH(verifyCmd, {\n host,\n user: \"root\",\n timeout: 10000,\n ...sshOptions\n });\n\n return {\n success: true,\n message: `Doppler configured for project ${project}/${dopplerConfig}`\n };\n } catch (error) {\n return {\n success: false,\n message: `Doppler configuration failed: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n}\n\n/**\n * Check Doppler status on a remote server\n *\n * @param host - Server IP or hostname\n * @param sshOptions - SSH options\n * @returns Doppler status\n */\nexport async function checkDopplerStatus(\n host: string,\n sshOptions: Partial<SSHOptions> = {}\n): Promise<{ configured: boolean; project?: string; config?: string; message: string }> {\n const { execSSH } = await import(\"@ebowwa/terminal/client\");\n\n try {\n // Check if doppler is configured\n const checkCmd = `\n doppler configure get project 2>/dev/null || echo \"NOT_CONFIGURED\"\n doppler configure get config 2>/dev/null || echo \"NOT_CONFIGURED\"\n `;\n\n const result = await execSSH(checkCmd, {\n host,\n user: \"root\",\n timeout: 5000,\n ...sshOptions\n });\n\n const lines = result.trim().split(\"\\n\");\n const project = lines[0]?.trim() || \"\";\n const config = lines[1]?.trim() || \"\";\n\n const configured = project !== \"NOT_CONFIGURED\" && config !== \"NOT_CONFIGURED\";\n\n return {\n configured,\n project: configured ? project : undefined,\n config: configured ? config : undefined,\n message: configured\n ? `Doppler configured: ${project}/${config}`\n : \"Doppler not configured\"\n };\n } catch (error) {\n return {\n configured: false,\n message: `Could not check Doppler status: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n}\n",
|
|
23
|
+
"/**\n * Tailscale Onboarding\n *\n * Join Tailscale network on remote servers.\n * Enables secure VPN access to servers.\n */\n\nimport type { SSHOptions } from \"@ebowwa/terminal/types\";\n\nexport interface TailscaleConfig {\n authKey: string;\n hostname?: string;\n tags?: string[];\n}\n\n/**\n * Join Tailscale network on a remote server\n *\n * @param host - Server IP or hostname\n * @param config - Tailscale configuration\n * @param sshOptions - SSH options\n * @returns Success status with Tailscale IP\n */\nexport async function onboardTailscale(\n host: string,\n config: TailscaleConfig,\n sshOptions: Partial<SSHOptions> = {}\n): Promise<{ success: boolean; message: string; tailscaleIp?: string }> {\n const { execSSH } = await import(\"@ebowwa/terminal/client\");\n\n const { authKey, hostname, tags = [] } = config;\n\n try {\n // Step 1: Install Tailscale if not present\n const installCmd = `\n if ! command -v tailscale &>/dev/null; then\n curl -fsSL https://tailscale.com/install.sh | sh\n fi\n `;\n\n await execSSH(installCmd, {\n host,\n user: \"root\",\n timeout: 60000, // 1 minute for install\n ...sshOptions\n });\n\n // Step 2: Build tailscale up command\n const upArgs = [\"up\", \"--authkey\", authKey];\n\n if (hostname) {\n upArgs.push(\"--hostname\", hostname);\n }\n\n if (tags.length > 0) {\n upArgs.push(\"--tags\", tags.join(\",\"));\n }\n\n const upCmd = `tailscale ${upArgs.join(\" \")}`;\n\n // Step 3: Run tailscale up\n await execSSH(upCmd, {\n host,\n user: \"root\",\n timeout: 30000,\n ...sshOptions\n });\n\n // Step 4: Get Tailscale IP\n const ipCmd = \"tailscale ip -4 2>/dev/null || tailscale ip 2>/dev/null || echo 'PENDING'\";\n\n const ipResult = await execSSH(ipCmd, {\n host,\n user: \"root\",\n timeout: 5000,\n ...sshOptions\n });\n\n const tailscaleIp = ipResult.trim();\n\n return {\n success: true,\n message: hostname\n ? `Tailscale joined as ${hostname}`\n : \"Tailscale joined\",\n tailscaleIp: tailscaleIp !== \"PENDING\" ? tailscaleIp : undefined\n };\n } catch (error) {\n return {\n success: false,\n message: `Tailscale onboarding failed: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n}\n\n/**\n * Check Tailscale status on a remote server\n *\n * @param host - Server IP or hostname\n * @param sshOptions - SSH options\n * @returns Tailscale status\n */\nexport async function checkTailscaleStatus(\n host: string,\n sshOptions: Partial<SSHOptions> = {}\n): Promise<{ configured: boolean; tailscaleIp?: string; hostname?: string; message: string }> {\n const { execSSH } = await import(\"@ebowwa/terminal/client\");\n\n try {\n // Check if tailscale is installed and running\n const checkCmd = `\n command -v tailscale &>/dev/null || echo \"NOT_INSTALLED\"\n tailscale status --json 2>/dev/null || echo \"NOT_RUNNING\"\n `;\n\n const result = await execSSH(checkCmd, {\n host,\n user: \"root\",\n timeout: 10000,\n ...sshOptions\n });\n\n const lines = result.trim().split(\"\\n\");\n\n if (lines[0]?.includes(\"NOT_INSTALLED\")) {\n return {\n configured: false,\n message: \"Tailscale not installed\"\n };\n }\n\n const statusJson = lines[1] || \"\";\n\n if (statusJson.includes(\"NOT_RUNNING\")) {\n return {\n configured: false,\n message: \"Tailscale installed but not running\"\n };\n }\n\n // Parse status JSON\n const status = JSON.parse(statusJson);\n\n const tailscaleIp = status.TailnetIPs?.[0] || status.IPv4;\n const hostname = status.HostName?.HostName || status.HostName;\n\n return {\n configured: true,\n tailscaleIp,\n hostname,\n message: `Tailscale connected as ${hostname || \"unknown\"} (${tailscaleIp || \"no IP\"})`\n };\n } catch (error) {\n return {\n configured: false,\n message: `Could not check Tailscale status: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n}\n",
|
|
24
|
+
"/**\n * Git Onboarding\n *\n * Configure Git credentials on remote servers.\n * Sets up GitHub token for gh cli and git credential helper.\n */\n\nimport type { SSHOptions } from \"@ebowwa/terminal/types\";\n\nexport interface GitConfig {\n username?: string;\n email?: string;\n githubToken?: string;\n}\n\n/**\n * Configure Git on a remote server\n *\n * @param host - Server IP or hostname\n * @param config - Git configuration\n * @param sshOptions - SSH options\n * @returns Success status\n */\nexport async function onboardGit(\n host: string,\n config: GitConfig,\n sshOptions: Partial<SSHOptions> = {}\n): Promise<{ success: boolean; message: string }> {\n const { execSSH } = await import(\"@ebowwa/terminal/client\");\n\n const { username = \"root\", email, githubToken } = config;\n\n try {\n const commands: string[] = [];\n\n // Configure git user\n commands.push(`git config --global user.name \"${username}\"`);\n\n if (email) {\n commands.push(`git config --global user.email \"${email}\"`);\n }\n\n // Configure credential helper\n commands.push(`\n git config --global credential.helper store\n mkdir -p ~/.config/gh\n `);\n\n // Configure GitHub CLI token if provided\n if (githubToken) {\n commands.push(`\n echo \"github.com:\" ${username}:${githubToken} > ~/.git-credentials\n chmod 600 ~/.git-credentials\n echo \"GITHUB_TOKEN=${githubToken}\" > ~/.config/gh/hosts.yml\n chmod 600 ~/.config/gh/hosts.yml\n `);\n }\n\n const cmd = commands.join(\" && \");\n\n await execSSH(cmd, {\n host,\n user: \"root\",\n timeout: 10000,\n ...sshOptions\n });\n\n return {\n success: true,\n message: `Git configured for ${username}${email ? ` (${email})` : \"\"}`\n };\n } catch (error) {\n return {\n success: false,\n message: `Git configuration failed: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n}\n\n/**\n * Check Git status on a remote server\n *\n * @param host - Server IP or hostname\n * @param sshOptions - SSH options\n * @returns Git status\n */\nexport async function checkGitStatus(\n host: string,\n sshOptions: Partial<SSHOptions> = {}\n): Promise<{ configured: boolean; username?: string; email?: string; hasToken: boolean; message: string }> {\n const { execSSH } = await import(\"@ebowwa/terminal/client\");\n\n try {\n const checkCmd = `\n git config --global user.name 2>/dev/null || echo \"NOT_SET\"\n git config --global user.email 2>/dev/null || echo \"NOT_SET\"\n test -f ~/.git-credentials && echo \"HAS_CREDS\" || echo \"NO_CREDS\"\n test -f ~/.config/gh/hosts.yml && echo \"HAS_GH_TOKEN\" || echo \"NO_GH_TOKEN\"\n `;\n\n const result = await execSSH(checkCmd, {\n host,\n user: \"root\",\n timeout: 5000,\n ...sshOptions\n });\n\n const lines = result.trim().split(\"\\n\");\n\n const username = lines[0]?.trim();\n const email = lines[1]?.trim();\n const hasCreds = lines[2]?.includes(\"HAS_CREDS\");\n const hasGhToken = lines[3]?.includes(\"HAS_GH_TOKEN\");\n\n const configured = username !== \"NOT_SET\";\n\n return {\n configured,\n username: username !== \"NOT_SET\" ? username : undefined,\n email: email !== \"NOT_SET\" ? email : undefined,\n hasToken: hasCreds || hasGhToken,\n message: configured\n ? `Git configured: ${username}${email ? ` <${email}>` : \"\"}`\n : \"Git not configured\"\n };\n } catch (error) {\n return {\n configured: false,\n hasToken: false,\n message: `Could not check Git status: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n}\n",
|
|
25
|
+
"/**\n * Claude Code Onboarding\n *\n * Install and configure Claude Code on remote servers.\n * Uses official installer: curl -fsSL https://claude.ai/install.sh | bash\n */\n\nimport type { SSHOptions } from \"@ebowwa/terminal/types\";\n\nexport interface ClaudeConfig {\n /** Skip installation if already installed */\n skipIfInstalled?: boolean;\n}\n\n/**\n * Install Claude Code on a remote server\n *\n * @param host - Server IP or hostname\n * @param config - Claude configuration\n * @param sshOptions - SSH options\n * @returns Success status\n */\nexport async function onboardClaude(\n host: string,\n config: ClaudeConfig = {},\n sshOptions: Partial<SSHOptions> = {}\n): Promise<{ success: boolean; message: string; version?: string }> {\n const { execSSH } = await import(\"@ebowwa/terminal/client\");\n\n try {\n // Check if already installed\n if (config.skipIfInstalled !== false) {\n const checkResult = await execSSH(\n 'export PATH=\"$HOME/.local/bin:$PATH\" && claude --version 2>/dev/null || echo \"NOT_INSTALLED\"',\n {\n host,\n user: \"root\",\n timeout: 5000,\n ...sshOptions\n }\n );\n\n if (!checkResult.includes(\"NOT_INSTALLED\")) {\n const version = checkResult.trim();\n return {\n success: true,\n message: `Claude Code already installed (${version})`,\n version\n };\n }\n }\n\n // Install Claude Code using official installer\n const installCmd = `\n curl -fsSL https://claude.ai/install.sh | bash && \\\n echo 'export PATH=\"$HOME/.local/bin:$PATH\"' >> ~/.bashrc\n `;\n\n await execSSH(installCmd, {\n host,\n user: \"root\",\n timeout: 60000, // 60 seconds for download\n ...sshOptions\n });\n\n // Verify installation\n const verifyResult = await execSSH(\n 'export PATH=\"$HOME/.local/bin:$PATH\" && claude --version',\n {\n host,\n user: \"root\",\n timeout: 5000,\n ...sshOptions\n }\n );\n\n const version = verifyResult.trim();\n\n return {\n success: true,\n message: `Claude Code installed (${version})`,\n version\n };\n } catch (error) {\n return {\n success: false,\n message: `Claude Code installation failed: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n}\n\n/**\n * Check Claude Code status on a remote server\n *\n * @param host - Server IP or hostname\n * @param sshOptions - SSH options\n * @returns Claude status\n */\nexport async function checkClaudeStatus(\n host: string,\n sshOptions: Partial<SSHOptions> = {}\n): Promise<{ configured: boolean; version?: string; path?: string; message: string }> {\n const { execSSH } = await import(\"@ebowwa/terminal/client\");\n\n try {\n const checkCmd = `\n export PATH=\"$HOME/.local/bin:$PATH\" && \\\n claude --version 2>/dev/null || echo \"NOT_INSTALLED\"\n `;\n\n const result = await execSSH(checkCmd, {\n host,\n user: \"root\",\n timeout: 5000,\n ...sshOptions\n });\n\n if (result.includes(\"NOT_INSTALLED\")) {\n return {\n configured: false,\n message: \"Claude Code not installed\"\n };\n }\n\n const version = result.trim();\n\n // Check if PATH is configured in .bashrc\n const pathCheck = await execSSH(\n 'grep -q \".local/bin\" ~/.bashrc 2>/dev/null && echo \"IN_PATH\" || echo \"NOT_IN_PATH\"',\n {\n host,\n user: \"root\",\n timeout: 5000,\n ...sshOptions\n }\n );\n\n const inPath = pathCheck.includes(\"IN_PATH\");\n\n return {\n configured: true,\n version,\n path: inPath ? \"~/.local/bin (in PATH)\" : \"~/.local/bin (not in PATH)\",\n message: `Claude Code ${version} installed${inPath ? \"\" : \" (add to PATH)\"}`\n };\n } catch (error) {\n return {\n configured: false,\n message: `Could not check Claude status: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n}\n",
|
|
26
|
+
"/**\n * Server Onboarding\n *\n * Main onboarding orchestration.\n * Coordinates Doppler, Tailscale, and Git onboarding.\n */\n\nimport type { SSHOptions } from \"@ebowwa/terminal/types\";\nimport type {\n OnboardingConfig,\n OnboardingStatus,\n OnboardingResult,\n BatchOnboardingResult,\n} from \"./types\";\nimport { checkDopplerStatus, onboardDoppler } from \"./doppler\";\nimport { checkTailscaleStatus, onboardTailscale } from \"./tailscale\";\nimport { checkGitStatus, onboardGit } from \"./git\";\nimport { checkClaudeStatus, onboardClaude } from \"./claude\";\n\n/**\n * Onboard a single server with all configured services\n *\n * @param config - Onboarding configuration\n * @param sshOptions - Additional SSH options\n * @returns Onboarding result\n */\nexport async function onboardServer(\n config: OnboardingConfig,\n sshOptions: Partial<SSHOptions> = {}\n): Promise<OnboardingResult> {\n const { host, user = \"root\", doppler, tailscale, git, claude } = config;\n\n const configured: (\"doppler\" | \"tailscale\" | \"git\" | \"claude\")[] = [];\n const failed: Array<{\n service: \"doppler\" | \"tailscale\" | \"git\" | \"claude\";\n error: string;\n }> = [];\n\n const baseSshOptions: Partial<SSHOptions> = {\n user,\n ...sshOptions\n };\n\n // Onboard Doppler\n if (doppler) {\n const result = await onboardDoppler(host, doppler, baseSshOptions);\n if (result.success) {\n configured.push(\"doppler\");\n } else {\n failed.push({ service: \"doppler\", error: result.message });\n }\n }\n\n // Onboard Tailscale\n if (tailscale) {\n const result = await onboardTailscale(host, tailscale, baseSshOptions);\n if (result.success) {\n configured.push(\"tailscale\");\n } else {\n failed.push({ service: \"tailscale\", error: result.message });\n }\n }\n\n // Onboard Git\n if (git) {\n const result = await onboardGit(host, git, baseSshOptions);\n if (result.success) {\n configured.push(\"git\");\n } else {\n failed.push({ service: \"git\", error: result.message });\n }\n }\n\n // Onboard Claude Code (always install by default - core platform tool)\n {\n const result = await onboardClaude(host, claude || {}, baseSshOptions);\n if (result.success) {\n configured.push(\"claude\");\n } else {\n failed.push({ service: \"claude\", error: result.message });\n }\n }\n\n return {\n host,\n configured,\n failed,\n success: failed.length === 0,\n completedAt: new Date().toISOString(),\n };\n}\n\n/**\n * Check onboarding status of a server\n *\n * @param host - Server IP or hostname\n * @param sshOptions - SSH options\n * @returns Onboarding status\n */\nexport async function checkOnboardingStatus(\n host: string,\n sshOptions: Partial<SSHOptions> = {}\n): Promise<OnboardingStatus> {\n const user = \"root\";\n\n const [dopplerStatus, tailscaleStatus, gitStatus, claudeStatus] = await Promise.all([\n checkDopplerStatus(host, { user, ...sshOptions }),\n checkTailscaleStatus(host, { user, ...sshOptions }),\n checkGitStatus(host, { user, ...sshOptions }),\n checkClaudeStatus(host, { user, ...sshOptions }),\n ]);\n\n const services = {\n doppler: {\n service: \"doppler\",\n configured: dopplerStatus.configured,\n message: dopplerStatus.message,\n details: dopplerStatus.project\n ? { project: dopplerStatus.project, config: dopplerStatus.config }\n : undefined,\n } as const,\n tailscale: {\n service: \"tailscale\",\n configured: tailscaleStatus.configured,\n message: tailscaleStatus.message,\n details: tailscaleStatus.tailscaleIp\n ? { tailscaleIp: tailscaleStatus.tailscaleIp, hostname: tailscaleStatus.hostname }\n : undefined,\n } as const,\n git: {\n service: \"git\",\n configured: gitStatus.configured,\n message: gitStatus.message,\n details: gitStatus.username\n ? { username: gitStatus.username, email: gitStatus.email }\n : undefined,\n } as const,\n claude: {\n service: \"claude\",\n configured: claudeStatus.configured,\n message: claudeStatus.message,\n details: claudeStatus.version\n ? { version: claudeStatus.version, path: claudeStatus.path }\n : undefined,\n } as const,\n };\n\n const complete = services.doppler.configured && services.tailscale.configured && services.git.configured && services.claude.configured;\n\n return {\n host,\n services,\n complete,\n checkedAt: new Date().toISOString(),\n };\n}\n\n/**\n * Onboard multiple servers in parallel\n *\n * @param hosts - List of server IPs/hostnames\n * @param sharedConfig - Shared onboarding config for all servers\n * @param sshOptions - SSH options\n * @returns Batch onboarding result\n */\nexport async function onboardBatch(\n hosts: string[],\n sharedConfig: Omit<OnboardingConfig, \"host\">,\n sshOptions: Partial<SSHOptions> = {}\n): Promise<BatchOnboardingResult> {\n // Onboard all servers in parallel\n const results = await Promise.all(\n hosts.map((host) =>\n onboardServer({ ...sharedConfig, host }, sshOptions)\n )\n );\n\n // Calculate summary\n const succeeded = results.filter((r) => r.success).length;\n const failed = results.filter((r) => !r.success).length;\n const partial = results.filter((r) => !r.success && r.configured.length > 0).length;\n\n return {\n results,\n summary: {\n total: results.length,\n succeeded,\n failed,\n partial,\n },\n };\n}\n\n/**\n * Quick onboarding check for multiple servers\n *\n * @param hosts - List of server IPs/hostnames\n * @param sshOptions - SSH options\n * @returns Map of host to onboarding status\n */\nexport async function checkBatchStatus(\n hosts: string[],\n sshOptions: Partial<SSHOptions> = {}\n): Promise<Map<string, OnboardingStatus>> {\n const statuses = await Promise.all(\n hosts.map(async (host) => {\n const status = await checkOnboardingStatus(host, sshOptions);\n return { host, status };\n })\n );\n\n return new Map(statuses.map(({ host, status }) => [host, status]));\n}\n"
|
|
27
|
+
],
|
|
28
|
+
"mappings": "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",
|
|
29
|
+
"debugId": "7863C6F3A6EF0C0064756E2164756E21",
|
|
30
|
+
"names": []
|
|
31
|
+
}
|