@ebowwa/hetzner 0.3.1 → 0.3.2
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/actions.d.ts +355 -0
- package/dist/auth.d.ts +6 -0
- package/dist/bootstrap/cloud-init.d.ts +78 -0
- package/dist/bootstrap/firewall.d.ts +118 -0
- package/dist/bootstrap/genesis.d.ts +82 -0
- package/dist/bootstrap/index.d.ts +29 -0
- package/dist/bootstrap/kernel-hardening.d.ts +69 -0
- package/dist/bootstrap/security-audit.d.ts +45 -0
- package/dist/bootstrap/ssh-hardening.d.ts +67 -0
- package/dist/client.d.ts +62 -0
- package/dist/config.d.ts +4 -0
- package/dist/cpufeatures-mvwrkyaq.node +0 -0
- package/dist/errors.d.ts +170 -0
- package/dist/index.d.ts +21 -0
- package/dist/onboarding/claude.d.ts +37 -0
- package/dist/onboarding/cpufeatures-mvwrkyaq.node +0 -0
- package/dist/onboarding/doppler.d.ts +37 -0
- package/dist/onboarding/git.d.ts +38 -0
- package/dist/onboarding/index.d.ts +19 -0
- package/dist/onboarding/onboarding.d.ts +41 -0
- package/dist/onboarding/sshcrypto-6mayxj08.node +0 -0
- package/dist/onboarding/tailscale.d.ts +38 -0
- package/dist/onboarding/types.d.ts +111 -0
- package/dist/pricing.d.ts +330 -0
- package/dist/schemas.d.ts +6629 -0
- package/dist/server-status.d.ts +25 -0
- package/dist/servers.d.ts +164 -0
- package/dist/ssh-keys.d.ts +35 -0
- package/dist/ssh-setup.d.ts +47 -0
- package/dist/sshcrypto-6mayxj08.node +0 -0
- package/dist/types.d.ts +303 -0
- package/dist/volumes.d.ts +105 -0
- package/package.json +1 -50
- package/dist/bootstrap/index.js.map +0 -15
- package/dist/index.js.map +0 -31
- package/dist/onboarding/index.js.map +0 -14
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kernel Hardening Cloud-Init Components
|
|
3
|
+
*
|
|
4
|
+
* Composable cloud-init blocks for securing the Linux kernel on new servers.
|
|
5
|
+
* Implements 2026 best practices for network stack hardening, IP spoofing
|
|
6
|
+
* protection, SYN flood mitigation, and secure core dump policies.
|
|
7
|
+
*
|
|
8
|
+
* Background: Public-facing VPS servers are constantly probed and attacked.
|
|
9
|
+
* Default Linux kernel settings prioritize compatibility over security. This
|
|
10
|
+
* module applies CIS Benchmark-aligned hardening via /etc/sysctl.d/ which
|
|
11
|
+
* persists across reboots and overrides defaults.
|
|
12
|
+
*
|
|
13
|
+
* Three composable functions return cloud-init line arrays for splicing into
|
|
14
|
+
* the appropriate YAML sections:
|
|
15
|
+
* - kernelHardeningPackages() → packages: section (currently empty, reserved)
|
|
16
|
+
* - kernelHardeningWriteFiles() → write_files: section (drops sysctl config)
|
|
17
|
+
* - kernelHardeningRunCmd() → runcmd: section (applies settings immediately)
|
|
18
|
+
*
|
|
19
|
+
* Security Measures Implemented:
|
|
20
|
+
* 1. Network Stack Hardening: SYN cookies, ICMP rate limits, martian packet logging
|
|
21
|
+
* 2. IP Spoofing Protection: Reverse path filtering, source address verification
|
|
22
|
+
* 3. SYN Flood Protection: TCP SYN cookies, reuse time_wait connections
|
|
23
|
+
* 4. Core Dump Restrictions: Disable setuid dumps, limit core dump size to 0
|
|
24
|
+
* 5. File Permissions: Hard links, symlinks, FIFO protection
|
|
25
|
+
* 6. Memory Protection: ASLR, randomize_va_space
|
|
26
|
+
*
|
|
27
|
+
* References:
|
|
28
|
+
* - CIS Benchmark for Ubuntu Linux 24.04
|
|
29
|
+
* - NIST SP 800-53 Revision 5
|
|
30
|
+
* - https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* Packages required for kernel hardening.
|
|
34
|
+
* Returns cloud-init YAML lines for the `packages:` section.
|
|
35
|
+
*
|
|
36
|
+
* Note: All kernel hardening is done via sysctl configuration, which uses
|
|
37
|
+
* built-in kernel functionality. No additional packages are required.
|
|
38
|
+
* This function is reserved for future expansion (e.g., auditd, kexec-tools).
|
|
39
|
+
*/
|
|
40
|
+
export declare function kernelHardeningPackages(): string[];
|
|
41
|
+
/**
|
|
42
|
+
* Kernel sysctl configuration file for comprehensive hardening.
|
|
43
|
+
* Returns cloud-init YAML lines for the `write_files:` section.
|
|
44
|
+
*
|
|
45
|
+
* Drops /etc/sysctl.d/99-security-hardening.conf which:
|
|
46
|
+
* - Takes precedence over /etc/sysctl.conf (99- prefix ensures last load)
|
|
47
|
+
* - Persists across reboots (sysctl.d files are applied on boot)
|
|
48
|
+
* - Can be applied immediately via `sysctl --system` (see runcmd)
|
|
49
|
+
*
|
|
50
|
+
* Settings organized by category:
|
|
51
|
+
* 1. IP Spoofing Protection: rp_filter, secure redirects
|
|
52
|
+
* 2. SYN Flood Protection: syncookies, tcp_tw_reuse
|
|
53
|
+
* 3. Network Stack: ICMP rate limits, martian logging, ignore broadcasts
|
|
54
|
+
* 4. Core Dumps: Disabled for setuid programs, limited for all processes
|
|
55
|
+
* 5. Memory Protection: ASLR, randomize_va_space
|
|
56
|
+
* 6. Filesystem: Hard link/symlink protection
|
|
57
|
+
*/
|
|
58
|
+
export declare function kernelHardeningWriteFiles(): string[];
|
|
59
|
+
/**
|
|
60
|
+
* Commands to apply kernel hardening settings immediately at first boot.
|
|
61
|
+
* Returns cloud-init YAML lines for the `runcmd:` section.
|
|
62
|
+
*
|
|
63
|
+
* Order matters:
|
|
64
|
+
* 1. Load all sysctl settings from /etc/sysctl.d/*.conf
|
|
65
|
+
* 2. Apply settings immediately (don't wait for reboot)
|
|
66
|
+
* 3. Log applied settings for audit trail
|
|
67
|
+
* 4. Display summary for cloud-init output verification
|
|
68
|
+
*/
|
|
69
|
+
export declare function kernelHardeningRunCmd(): string[];
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Audit Cloud-Init Components
|
|
3
|
+
*
|
|
4
|
+
* Composable cloud-init blocks for running post-bootstrap security audits.
|
|
5
|
+
* Generates comprehensive security reports for verification and compliance.
|
|
6
|
+
*
|
|
7
|
+
* This module runs LAST in the bootstrap sequence, after all other security
|
|
8
|
+
* hardening is applied. It captures the state of the system for verification.
|
|
9
|
+
*
|
|
10
|
+
* Three composable functions return cloud-init line arrays for splicing into
|
|
11
|
+
* the appropriate YAML sections:
|
|
12
|
+
* - securityAuditPackages() → packages: section
|
|
13
|
+
* - securityAuditWriteFiles() → write_files: section
|
|
14
|
+
* - securityAuditRunCmd() → runcmd: section
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Packages required for security auditing.
|
|
18
|
+
* Returns cloud-init YAML lines for the `packages:` section.
|
|
19
|
+
*
|
|
20
|
+
* - lynis: Comprehensive security auditing tool
|
|
21
|
+
*/
|
|
22
|
+
export declare function securityAuditPackages(): string[];
|
|
23
|
+
/**
|
|
24
|
+
* Files to write at first boot for security auditing.
|
|
25
|
+
* Returns cloud-init YAML lines for the `write_files:` section.
|
|
26
|
+
*
|
|
27
|
+
* Drops 1 file onto the server:
|
|
28
|
+
*
|
|
29
|
+
* 1. /opt/monitoring/security-audit.sh
|
|
30
|
+
* - Collects security metrics (UFW, fail2ban, sshd, sysctl)
|
|
31
|
+
* - Runs Lynis audit with warnings-only output
|
|
32
|
+
* - Generates JSON report at /var/log/security-audit.json
|
|
33
|
+
* - Logs summary to /var/log/security-audit.log
|
|
34
|
+
*/
|
|
35
|
+
export declare function securityAuditWriteFiles(): string[];
|
|
36
|
+
/**
|
|
37
|
+
* Commands to run security audit at first boot.
|
|
38
|
+
* Returns cloud-init YAML lines for the `runcmd:` section.
|
|
39
|
+
*
|
|
40
|
+
* Order matters:
|
|
41
|
+
* 1. Create /opt/monitoring directory (audit script target)
|
|
42
|
+
* 2. Run security audit script (captures state after all hardening)
|
|
43
|
+
* 3. Log audit completion for verification
|
|
44
|
+
*/
|
|
45
|
+
export declare function securityAuditRunCmd(): string[];
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSH Hardening Cloud-Init Components
|
|
3
|
+
*
|
|
4
|
+
* Composable cloud-init blocks for securing sshd on new servers.
|
|
5
|
+
* Includes: hardened sshd config, fail2ban, and health monitoring.
|
|
6
|
+
*
|
|
7
|
+
* Background: Hetzner public IPs get brute-forced constantly (~5k failed SSH
|
|
8
|
+
* logins per 24h observed on genesis). Without hardening, the default sshd
|
|
9
|
+
* MaxStartups (10:30:100) gets overwhelmed and legitimate connections time out
|
|
10
|
+
* with "Timed out while waiting for handshake".
|
|
11
|
+
*
|
|
12
|
+
* This module is imported by both cloud-init.ts (seed/worker nodes) and
|
|
13
|
+
* genesis.ts (control plane) so every new server gets hardened at first boot.
|
|
14
|
+
*
|
|
15
|
+
* Three composable functions return cloud-init line arrays for splicing into
|
|
16
|
+
* the appropriate YAML sections:
|
|
17
|
+
* - sshdHardeningPackages() → packages: section
|
|
18
|
+
* - sshdHardeningWriteFiles() → write_files: section
|
|
19
|
+
* - sshdHardeningRunCmd() → runcmd: section
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Packages required for SSH hardening.
|
|
23
|
+
* Returns cloud-init YAML lines for the `packages:` section.
|
|
24
|
+
*
|
|
25
|
+
* - fail2ban: bans IPs after repeated failed SSH attempts (3 tries → 1hr ban)
|
|
26
|
+
*/
|
|
27
|
+
export declare function sshdHardeningPackages(): string[];
|
|
28
|
+
/**
|
|
29
|
+
* Files to write at first boot for SSH hardening.
|
|
30
|
+
* Returns cloud-init YAML lines for the `write_files:` section.
|
|
31
|
+
*
|
|
32
|
+
* Drops 5 files onto the server:
|
|
33
|
+
*
|
|
34
|
+
* 1. /etc/ssh/sshd_config.d/hardened.conf
|
|
35
|
+
* - Disables password auth entirely (key-only)
|
|
36
|
+
* - Raises MaxStartups from default 10:30:100 → 20:50:60 so brute-force
|
|
37
|
+
* traffic doesn't starve legitimate connections
|
|
38
|
+
* - Reduces LoginGraceTime from 2min → 30s (attackers hold slots open)
|
|
39
|
+
* - Limits MaxAuthTries to 3 per connection
|
|
40
|
+
* - Enables keepalive (30s interval, 3 missed = disconnect)
|
|
41
|
+
*
|
|
42
|
+
* 2. /etc/fail2ban/jail.local
|
|
43
|
+
* - Monitors sshd via systemd journal
|
|
44
|
+
* - Bans IP for 1 hour after 3 failures within 10 minutes
|
|
45
|
+
* - Uses nftables (Ubuntu 24.04 default firewall backend)
|
|
46
|
+
*
|
|
47
|
+
* 3. /opt/monitoring/sshd-health.sh
|
|
48
|
+
* - Collects sshd + fail2ban + system metrics into JSON
|
|
49
|
+
* - Writes to /var/log/sshd-health.json (read by the app via SSH)
|
|
50
|
+
* - Auto-restarts sshd if it detects it's down
|
|
51
|
+
*
|
|
52
|
+
* 4. /etc/systemd/system/sshd-health.service (oneshot runner)
|
|
53
|
+
* 5. /etc/systemd/system/sshd-health.timer (runs every 60 seconds)
|
|
54
|
+
*/
|
|
55
|
+
export declare function sshdHardeningWriteFiles(): string[];
|
|
56
|
+
/**
|
|
57
|
+
* Commands to activate all SSH hardening services at first boot.
|
|
58
|
+
* Returns cloud-init YAML lines for the `runcmd:` section.
|
|
59
|
+
*
|
|
60
|
+
* Order matters:
|
|
61
|
+
* 1. Create /opt/monitoring dir (health script target)
|
|
62
|
+
* 2. Reload sshd to pick up hardened.conf (fallback: full restart)
|
|
63
|
+
* 3. Enable + start fail2ban (reads jail.local immediately)
|
|
64
|
+
* 4. Reload systemd to pick up the health service/timer units
|
|
65
|
+
* 5. Enable + start the health timer (begins 60s monitoring loop)
|
|
66
|
+
*/
|
|
67
|
+
export declare function sshdHardeningRunCmd(): string[];
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hetzner Cloud API client
|
|
3
|
+
* For server-side use only (requires API token)
|
|
4
|
+
*
|
|
5
|
+
* TODO: RE-REVIEW https://docs.hetzner.cloud/reference/cloud#authentication
|
|
6
|
+
* - https://tailscale.com/kb/1150/cloud-hetzner
|
|
7
|
+
*/
|
|
8
|
+
import { ServerOperations } from "./servers.js";
|
|
9
|
+
import { ActionOperations } from "./actions.js";
|
|
10
|
+
import { PricingOperations } from "./pricing.js";
|
|
11
|
+
import { SSHKeyOperations } from "./ssh-keys.js";
|
|
12
|
+
import { VolumeOperations } from "./volumes.js";
|
|
13
|
+
import type { RateLimitInfo } from "./types.js";
|
|
14
|
+
export declare class HetznerClient {
|
|
15
|
+
private apiToken;
|
|
16
|
+
constructor(apiToken?: string);
|
|
17
|
+
get isAuthenticated(): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Make a request to the Hetzner Cloud API
|
|
20
|
+
*
|
|
21
|
+
* @param endpoint - API endpoint (e.g., "/servers")
|
|
22
|
+
* @param options - RequestInit options
|
|
23
|
+
* @returns Parsed JSON response
|
|
24
|
+
* @throws {HetznerAPIError} On API errors
|
|
25
|
+
*/
|
|
26
|
+
request<T>(endpoint: string, options?: RequestInit): Promise<T>;
|
|
27
|
+
/**
|
|
28
|
+
* Validate Hetzner API response with Zod schema
|
|
29
|
+
*
|
|
30
|
+
* @param schema - Zod schema to validate against
|
|
31
|
+
* @param data - Data to validate
|
|
32
|
+
* @returns Validated data
|
|
33
|
+
*/
|
|
34
|
+
private validateResponse;
|
|
35
|
+
/**
|
|
36
|
+
* Handle rate limit information from response headers
|
|
37
|
+
*
|
|
38
|
+
* @param rateLimit - Rate limit info from response
|
|
39
|
+
*/
|
|
40
|
+
private handleRateLimit;
|
|
41
|
+
/**
|
|
42
|
+
* Get current rate limit information
|
|
43
|
+
*
|
|
44
|
+
* Makes a lightweight request to check rate limit status
|
|
45
|
+
*
|
|
46
|
+
* @returns Rate limit info or null if not available
|
|
47
|
+
*/
|
|
48
|
+
getRateLimit(): Promise<RateLimitInfo | null>;
|
|
49
|
+
readonly servers: ServerOperations;
|
|
50
|
+
readonly actions: ActionOperations;
|
|
51
|
+
readonly pricing: PricingOperations;
|
|
52
|
+
readonly ssh_keys: SSHKeyOperations;
|
|
53
|
+
readonly volumes: VolumeOperations;
|
|
54
|
+
listServers(): Promise<import("./types.js").HetznerServer[]>;
|
|
55
|
+
getServer(id: number): Promise<import("./types.js").HetznerServer>;
|
|
56
|
+
createServer(options: import("./types.js").CreateServerOptions): Promise<import("./types.js").CreateServerResponse>;
|
|
57
|
+
deleteServer(id: number): Promise<import("./types.js").HetznerAction>;
|
|
58
|
+
powerOn(id: number): Promise<import("./types.js").HetznerAction>;
|
|
59
|
+
powerOff(id: number): Promise<import("./types.js").HetznerAction>;
|
|
60
|
+
reboot(id: number): Promise<import("./types.js").HetznerAction>;
|
|
61
|
+
}
|
|
62
|
+
export type * from "./types.js";
|
package/dist/config.d.ts
ADDED
|
Binary file
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hetzner Cloud API error types and utilities
|
|
3
|
+
*/
|
|
4
|
+
import type { RateLimitInfo, ActionError } from "./types.js";
|
|
5
|
+
export type { ActionError };
|
|
6
|
+
/**
|
|
7
|
+
* Hetzner API error codes
|
|
8
|
+
* @see https://docs.hetzner.cloud/#errors
|
|
9
|
+
*/
|
|
10
|
+
export declare enum HetznerErrorCode {
|
|
11
|
+
Unauthorized = "unauthorized",
|
|
12
|
+
InvalidInput = "invalid_input",
|
|
13
|
+
JSONError = "json_error",
|
|
14
|
+
Forbidden = "forbidden",
|
|
15
|
+
NotFound = "not_found",
|
|
16
|
+
ResourceLocked = "locked",
|
|
17
|
+
ResourceLimitExceeded = "resource_limit_exceeded",
|
|
18
|
+
UniquenessError = "uniqueness_error",
|
|
19
|
+
RateLimitExceeded = "rate_limit_exceeded",
|
|
20
|
+
Conflict = "conflict",
|
|
21
|
+
ServiceError = "service_error",
|
|
22
|
+
ServerNotStopped = "server_not_stopped",
|
|
23
|
+
ServerAlreadyStopped = "server_already_stopped",
|
|
24
|
+
InvalidServerType = "invalid_server_type",
|
|
25
|
+
IpNotOwned = "ip_not_owned",
|
|
26
|
+
IpAlreadyAssigned = "ip_already_assigned",
|
|
27
|
+
VolumeAlreadyAttached = "volume_already_attached",
|
|
28
|
+
VolumeSizeNotMultiple = "volume_size_not_multiple",
|
|
29
|
+
FirewallInUse = "firewall_in_use",
|
|
30
|
+
CertificateValidationFailed = "certificate_validation_failed",
|
|
31
|
+
CertificatePending = "certificate_pending"
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Base Hetzner API error
|
|
35
|
+
*/
|
|
36
|
+
export declare class HetznerAPIError extends Error {
|
|
37
|
+
code?: string;
|
|
38
|
+
details?: unknown;
|
|
39
|
+
constructor(message: string, code?: string, details?: unknown);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Authentication error (401)
|
|
43
|
+
*/
|
|
44
|
+
export declare class HetznerUnauthorizedError extends HetznerAPIError {
|
|
45
|
+
constructor(message?: string);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Forbidden error (403)
|
|
49
|
+
*/
|
|
50
|
+
export declare class HetznerForbiddenError extends HetznerAPIError {
|
|
51
|
+
constructor(message?: string);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Resource not found error (404)
|
|
55
|
+
*/
|
|
56
|
+
export declare class HetznerNotFoundError extends HetznerAPIError {
|
|
57
|
+
constructor(resource: string, id: number | string);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Rate limit exceeded error (429)
|
|
61
|
+
*/
|
|
62
|
+
export declare class HetznerRateLimitError extends HetznerAPIError {
|
|
63
|
+
rateLimitInfo?: RateLimitInfo;
|
|
64
|
+
constructor(message?: string, rateLimitInfo?: RateLimitInfo);
|
|
65
|
+
/**
|
|
66
|
+
* Get the number of milliseconds until the rate limit resets
|
|
67
|
+
*/
|
|
68
|
+
get resetInMs(): number;
|
|
69
|
+
/**
|
|
70
|
+
* Get a human-readable reset time
|
|
71
|
+
*/
|
|
72
|
+
get resetTime(): string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Resource locked error
|
|
76
|
+
*/
|
|
77
|
+
export declare class HetznerResourceLockedError extends HetznerAPIError {
|
|
78
|
+
actionInProgress?: string;
|
|
79
|
+
constructor(resource: string, id: number | string, actionInProgress?: string);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Resource limit exceeded error
|
|
83
|
+
*/
|
|
84
|
+
export declare class HetznerResourceLimitError extends HetznerAPIError {
|
|
85
|
+
constructor(resource: string, limit: number);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Invalid input error
|
|
89
|
+
*/
|
|
90
|
+
export declare class HetznerInvalidInputError extends HetznerAPIError {
|
|
91
|
+
fields?: Record<string, string>;
|
|
92
|
+
constructor(message: string, fields?: Record<string, string>);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Conflict error
|
|
96
|
+
*/
|
|
97
|
+
export declare class HetznerConflictError extends HetznerAPIError {
|
|
98
|
+
constructor(message: string, details?: unknown);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Service error (5xx)
|
|
102
|
+
*/
|
|
103
|
+
export declare class HetznerServiceError extends HetznerAPIError {
|
|
104
|
+
statusCode?: number;
|
|
105
|
+
constructor(message: string, statusCode?: number);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Action failed error
|
|
109
|
+
*/
|
|
110
|
+
export declare class HetznerActionError extends HetznerAPIError {
|
|
111
|
+
actionError: ActionError;
|
|
112
|
+
actionId: number;
|
|
113
|
+
constructor(actionError: ActionError, actionId: number);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Timeout error for action polling
|
|
117
|
+
*/
|
|
118
|
+
export declare class HetznerTimeoutError extends HetznerAPIError {
|
|
119
|
+
lastProgress: number;
|
|
120
|
+
constructor(actionId: number, timeout: number, lastProgress: number);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Parse Hetzner API error response and create appropriate error
|
|
124
|
+
*/
|
|
125
|
+
export declare function createHetznerError(statusCode: number, body: {
|
|
126
|
+
error?: {
|
|
127
|
+
code: string;
|
|
128
|
+
message: string;
|
|
129
|
+
details?: unknown;
|
|
130
|
+
};
|
|
131
|
+
}): HetznerAPIError;
|
|
132
|
+
/**
|
|
133
|
+
* Check if an error is retryable
|
|
134
|
+
*/
|
|
135
|
+
export declare function isRetryableError(error: unknown): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Check if an error is a rate limit error
|
|
138
|
+
*/
|
|
139
|
+
export declare function isRateLimitError(error: unknown): error is HetznerRateLimitError;
|
|
140
|
+
/**
|
|
141
|
+
* Check if an error is a resource locked error
|
|
142
|
+
*/
|
|
143
|
+
export declare function isResourceLockedError(error: unknown): error is HetznerResourceLockedError;
|
|
144
|
+
/**
|
|
145
|
+
* Calculate retry delay with exponential backoff
|
|
146
|
+
*/
|
|
147
|
+
export declare function calculateRetryDelay(attempt: number, baseDelay?: number, maxDelay?: number): number;
|
|
148
|
+
/**
|
|
149
|
+
* Error handler function type
|
|
150
|
+
*/
|
|
151
|
+
export type ErrorHandler = (error: HetznerAPIError) => void | Promise<void>;
|
|
152
|
+
/**
|
|
153
|
+
* Error handler options
|
|
154
|
+
*/
|
|
155
|
+
export interface ErrorHandlerContext {
|
|
156
|
+
/** Maximum number of retry attempts */
|
|
157
|
+
maxRetries?: number;
|
|
158
|
+
/** Base delay for exponential backoff in milliseconds */
|
|
159
|
+
baseDelay?: number;
|
|
160
|
+
/** Maximum delay between retries in milliseconds */
|
|
161
|
+
maxDelay?: number;
|
|
162
|
+
/** Optional error handler callback */
|
|
163
|
+
onError?: ErrorHandler;
|
|
164
|
+
/** Whether to log errors */
|
|
165
|
+
logErrors?: boolean;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Default error handler that logs to console
|
|
169
|
+
*/
|
|
170
|
+
export declare function defaultErrorHandler(error: HetznerAPIError): void;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hetzner Cloud API client
|
|
3
|
+
* For server-side use only (requires API token)
|
|
4
|
+
*
|
|
5
|
+
* TODO:
|
|
6
|
+
* - Certificate actions: https://docs.hetzner.cloud/reference/cloud#certificate-actions
|
|
7
|
+
* - DNS operations
|
|
8
|
+
*/
|
|
9
|
+
export { HetznerClient } from "./client.js";
|
|
10
|
+
export { ServerOperations } from "./servers.js";
|
|
11
|
+
export { VolumeOperations } from "./volumes.js";
|
|
12
|
+
export { ActionOperations } from "./actions.js";
|
|
13
|
+
export { SSHKeyOperations } from "./ssh-keys.js";
|
|
14
|
+
export { getTokenFromCLI, isAuthenticated, resolveApiToken } from "./auth.js";
|
|
15
|
+
export { HETZNER_API_BASE } from "./config.js";
|
|
16
|
+
export * from "./types.js";
|
|
17
|
+
export * from "./schemas.js";
|
|
18
|
+
export * from "./errors.js";
|
|
19
|
+
export { waitForAction, waitForMultipleActions, waitForMultipleActionsWithLimit, batchCheckActions, getActionTimeout, isActionRunning, isActionSuccess, isActionError, formatActionProgress, getActionDescription, getPollInterval, getAdaptivePollInterval, waitForActionAdaptive, parseRateLimitHeaders, isRateLimitLow, formatRateLimitStatus, waitForRateLimitReset, createProgressLogger, ACTION_TIMEOUTS, } from "./actions.js";
|
|
20
|
+
export * from "./bootstrap/index.js";
|
|
21
|
+
export * from "./onboarding/index.js";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code Onboarding
|
|
3
|
+
*
|
|
4
|
+
* Install and configure Claude Code on remote servers.
|
|
5
|
+
* Uses official installer: curl -fsSL https://claude.ai/install.sh | bash
|
|
6
|
+
*/
|
|
7
|
+
import type { SSHOptions } from "@ebowwa/terminal/types";
|
|
8
|
+
export interface ClaudeConfig {
|
|
9
|
+
/** Skip installation if already installed */
|
|
10
|
+
skipIfInstalled?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Install Claude Code on a remote server
|
|
14
|
+
*
|
|
15
|
+
* @param host - Server IP or hostname
|
|
16
|
+
* @param config - Claude configuration
|
|
17
|
+
* @param sshOptions - SSH options
|
|
18
|
+
* @returns Success status
|
|
19
|
+
*/
|
|
20
|
+
export declare function onboardClaude(host: string, config?: ClaudeConfig, sshOptions?: Partial<SSHOptions>): Promise<{
|
|
21
|
+
success: boolean;
|
|
22
|
+
message: string;
|
|
23
|
+
version?: string;
|
|
24
|
+
}>;
|
|
25
|
+
/**
|
|
26
|
+
* Check Claude Code status on a remote server
|
|
27
|
+
*
|
|
28
|
+
* @param host - Server IP or hostname
|
|
29
|
+
* @param sshOptions - SSH options
|
|
30
|
+
* @returns Claude status
|
|
31
|
+
*/
|
|
32
|
+
export declare function checkClaudeStatus(host: string, sshOptions?: Partial<SSHOptions>): Promise<{
|
|
33
|
+
configured: boolean;
|
|
34
|
+
version?: string;
|
|
35
|
+
path?: string;
|
|
36
|
+
message: string;
|
|
37
|
+
}>;
|
|
Binary file
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Doppler Onboarding
|
|
3
|
+
*
|
|
4
|
+
* Configure Doppler CLI service token on remote servers.
|
|
5
|
+
* This enables doppler run to inject secrets into processes.
|
|
6
|
+
*/
|
|
7
|
+
import type { SSHOptions } from "@ebowwa/terminal/types";
|
|
8
|
+
export interface DopplerConfig {
|
|
9
|
+
token: string;
|
|
10
|
+
project?: string;
|
|
11
|
+
config?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Configure Doppler on a remote server
|
|
15
|
+
*
|
|
16
|
+
* @param host - Server IP or hostname
|
|
17
|
+
* @param config - Doppler configuration
|
|
18
|
+
* @param sshOptions - SSH options
|
|
19
|
+
* @returns Success status
|
|
20
|
+
*/
|
|
21
|
+
export declare function onboardDoppler(host: string, config: DopplerConfig, sshOptions?: Partial<SSHOptions>): Promise<{
|
|
22
|
+
success: boolean;
|
|
23
|
+
message: string;
|
|
24
|
+
}>;
|
|
25
|
+
/**
|
|
26
|
+
* Check Doppler status on a remote server
|
|
27
|
+
*
|
|
28
|
+
* @param host - Server IP or hostname
|
|
29
|
+
* @param sshOptions - SSH options
|
|
30
|
+
* @returns Doppler status
|
|
31
|
+
*/
|
|
32
|
+
export declare function checkDopplerStatus(host: string, sshOptions?: Partial<SSHOptions>): Promise<{
|
|
33
|
+
configured: boolean;
|
|
34
|
+
project?: string;
|
|
35
|
+
config?: string;
|
|
36
|
+
message: string;
|
|
37
|
+
}>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git Onboarding
|
|
3
|
+
*
|
|
4
|
+
* Configure Git credentials on remote servers.
|
|
5
|
+
* Sets up GitHub token for gh cli and git credential helper.
|
|
6
|
+
*/
|
|
7
|
+
import type { SSHOptions } from "@ebowwa/terminal/types";
|
|
8
|
+
export interface GitConfig {
|
|
9
|
+
username?: string;
|
|
10
|
+
email?: string;
|
|
11
|
+
githubToken?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Configure Git on a remote server
|
|
15
|
+
*
|
|
16
|
+
* @param host - Server IP or hostname
|
|
17
|
+
* @param config - Git configuration
|
|
18
|
+
* @param sshOptions - SSH options
|
|
19
|
+
* @returns Success status
|
|
20
|
+
*/
|
|
21
|
+
export declare function onboardGit(host: string, config: GitConfig, sshOptions?: Partial<SSHOptions>): Promise<{
|
|
22
|
+
success: boolean;
|
|
23
|
+
message: string;
|
|
24
|
+
}>;
|
|
25
|
+
/**
|
|
26
|
+
* Check Git status on a remote server
|
|
27
|
+
*
|
|
28
|
+
* @param host - Server IP or hostname
|
|
29
|
+
* @param sshOptions - SSH options
|
|
30
|
+
* @returns Git status
|
|
31
|
+
*/
|
|
32
|
+
export declare function checkGitStatus(host: string, sshOptions?: Partial<SSHOptions>): Promise<{
|
|
33
|
+
configured: boolean;
|
|
34
|
+
username?: string;
|
|
35
|
+
email?: string;
|
|
36
|
+
hasToken: boolean;
|
|
37
|
+
message: string;
|
|
38
|
+
}>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hetzner Onboarding Module
|
|
3
|
+
*
|
|
4
|
+
* Post-boot configuration for newly provisioned servers.
|
|
5
|
+
* Handles services that require secrets/tokens:
|
|
6
|
+
* - Doppler (secrets management)
|
|
7
|
+
* - Tailscale (VPN)
|
|
8
|
+
* - Git (credentials)
|
|
9
|
+
* - Claude Code (AI assistant)
|
|
10
|
+
*
|
|
11
|
+
* This is Phase 2 of the bootstrap process, running after
|
|
12
|
+
* cloud-init completes the initial installation.
|
|
13
|
+
*/
|
|
14
|
+
export type { OnboardingConfig, OnboardingStatus, OnboardingResult, BatchOnboardingResult, ServiceStatus } from "./types";
|
|
15
|
+
export { onboardDoppler, checkDopplerStatus } from "./doppler";
|
|
16
|
+
export { onboardTailscale, checkTailscaleStatus } from "./tailscale";
|
|
17
|
+
export { onboardGit, checkGitStatus } from "./git";
|
|
18
|
+
export { onboardClaude, checkClaudeStatus } from "./claude";
|
|
19
|
+
export { onboardServer, checkOnboardingStatus, onboardBatch } from "./onboarding";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server Onboarding
|
|
3
|
+
*
|
|
4
|
+
* Main onboarding orchestration.
|
|
5
|
+
* Coordinates Doppler, Tailscale, and Git onboarding.
|
|
6
|
+
*/
|
|
7
|
+
import type { SSHOptions } from "@ebowwa/terminal/types";
|
|
8
|
+
import type { OnboardingConfig, OnboardingStatus, OnboardingResult, BatchOnboardingResult } from "./types";
|
|
9
|
+
/**
|
|
10
|
+
* Onboard a single server with all configured services
|
|
11
|
+
*
|
|
12
|
+
* @param config - Onboarding configuration
|
|
13
|
+
* @param sshOptions - Additional SSH options
|
|
14
|
+
* @returns Onboarding result
|
|
15
|
+
*/
|
|
16
|
+
export declare function onboardServer(config: OnboardingConfig, sshOptions?: Partial<SSHOptions>): Promise<OnboardingResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Check onboarding status of a server
|
|
19
|
+
*
|
|
20
|
+
* @param host - Server IP or hostname
|
|
21
|
+
* @param sshOptions - SSH options
|
|
22
|
+
* @returns Onboarding status
|
|
23
|
+
*/
|
|
24
|
+
export declare function checkOnboardingStatus(host: string, sshOptions?: Partial<SSHOptions>): Promise<OnboardingStatus>;
|
|
25
|
+
/**
|
|
26
|
+
* Onboard multiple servers in parallel
|
|
27
|
+
*
|
|
28
|
+
* @param hosts - List of server IPs/hostnames
|
|
29
|
+
* @param sharedConfig - Shared onboarding config for all servers
|
|
30
|
+
* @param sshOptions - SSH options
|
|
31
|
+
* @returns Batch onboarding result
|
|
32
|
+
*/
|
|
33
|
+
export declare function onboardBatch(hosts: string[], sharedConfig: Omit<OnboardingConfig, "host">, sshOptions?: Partial<SSHOptions>): Promise<BatchOnboardingResult>;
|
|
34
|
+
/**
|
|
35
|
+
* Quick onboarding check for multiple servers
|
|
36
|
+
*
|
|
37
|
+
* @param hosts - List of server IPs/hostnames
|
|
38
|
+
* @param sshOptions - SSH options
|
|
39
|
+
* @returns Map of host to onboarding status
|
|
40
|
+
*/
|
|
41
|
+
export declare function checkBatchStatus(hosts: string[], sshOptions?: Partial<SSHOptions>): Promise<Map<string, OnboardingStatus>>;
|
|
Binary file
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tailscale Onboarding
|
|
3
|
+
*
|
|
4
|
+
* Join Tailscale network on remote servers.
|
|
5
|
+
* Enables secure VPN access to servers.
|
|
6
|
+
*/
|
|
7
|
+
import type { SSHOptions } from "@ebowwa/terminal/types";
|
|
8
|
+
export interface TailscaleConfig {
|
|
9
|
+
authKey: string;
|
|
10
|
+
hostname?: string;
|
|
11
|
+
tags?: string[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Join Tailscale network on a remote server
|
|
15
|
+
*
|
|
16
|
+
* @param host - Server IP or hostname
|
|
17
|
+
* @param config - Tailscale configuration
|
|
18
|
+
* @param sshOptions - SSH options
|
|
19
|
+
* @returns Success status with Tailscale IP
|
|
20
|
+
*/
|
|
21
|
+
export declare function onboardTailscale(host: string, config: TailscaleConfig, sshOptions?: Partial<SSHOptions>): Promise<{
|
|
22
|
+
success: boolean;
|
|
23
|
+
message: string;
|
|
24
|
+
tailscaleIp?: string;
|
|
25
|
+
}>;
|
|
26
|
+
/**
|
|
27
|
+
* Check Tailscale status on a remote server
|
|
28
|
+
*
|
|
29
|
+
* @param host - Server IP or hostname
|
|
30
|
+
* @param sshOptions - SSH options
|
|
31
|
+
* @returns Tailscale status
|
|
32
|
+
*/
|
|
33
|
+
export declare function checkTailscaleStatus(host: string, sshOptions?: Partial<SSHOptions>): Promise<{
|
|
34
|
+
configured: boolean;
|
|
35
|
+
tailscaleIp?: string;
|
|
36
|
+
hostname?: string;
|
|
37
|
+
message: string;
|
|
38
|
+
}>;
|