@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
package/onboarding/git.ts
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
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
|
-
|
|
8
|
-
import type { SSHOptions } from "@ebowwa/terminal/types";
|
|
9
|
-
|
|
10
|
-
export interface GitConfig {
|
|
11
|
-
username?: string;
|
|
12
|
-
email?: string;
|
|
13
|
-
githubToken?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Configure Git on a remote server
|
|
18
|
-
*
|
|
19
|
-
* @param host - Server IP or hostname
|
|
20
|
-
* @param config - Git configuration
|
|
21
|
-
* @param sshOptions - SSH options
|
|
22
|
-
* @returns Success status
|
|
23
|
-
*/
|
|
24
|
-
export async function onboardGit(
|
|
25
|
-
host: string,
|
|
26
|
-
config: GitConfig,
|
|
27
|
-
sshOptions: Partial<SSHOptions> = {}
|
|
28
|
-
): Promise<{ success: boolean; message: string }> {
|
|
29
|
-
const { execSSH } = await import("@ebowwa/terminal/client");
|
|
30
|
-
|
|
31
|
-
const { username = "root", email, githubToken } = config;
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
const commands: string[] = [];
|
|
35
|
-
|
|
36
|
-
// Configure git user
|
|
37
|
-
commands.push(`git config --global user.name "${username}"`);
|
|
38
|
-
|
|
39
|
-
if (email) {
|
|
40
|
-
commands.push(`git config --global user.email "${email}"`);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Configure credential helper
|
|
44
|
-
commands.push(`
|
|
45
|
-
git config --global credential.helper store
|
|
46
|
-
mkdir -p ~/.config/gh
|
|
47
|
-
`);
|
|
48
|
-
|
|
49
|
-
// Configure GitHub CLI token if provided
|
|
50
|
-
if (githubToken) {
|
|
51
|
-
commands.push(`
|
|
52
|
-
echo "github.com:" ${username}:${githubToken} > ~/.git-credentials
|
|
53
|
-
chmod 600 ~/.git-credentials
|
|
54
|
-
echo "GITHUB_TOKEN=${githubToken}" > ~/.config/gh/hosts.yml
|
|
55
|
-
chmod 600 ~/.config/gh/hosts.yml
|
|
56
|
-
`);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const cmd = commands.join(" && ");
|
|
60
|
-
|
|
61
|
-
await execSSH(cmd, {
|
|
62
|
-
host,
|
|
63
|
-
user: "root",
|
|
64
|
-
timeout: 10000,
|
|
65
|
-
...sshOptions
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
return {
|
|
69
|
-
success: true,
|
|
70
|
-
message: `Git configured for ${username}${email ? ` (${email})` : ""}`
|
|
71
|
-
};
|
|
72
|
-
} catch (error) {
|
|
73
|
-
return {
|
|
74
|
-
success: false,
|
|
75
|
-
message: `Git configuration failed: ${error instanceof Error ? error.message : String(error)}`
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Check Git status on a remote server
|
|
82
|
-
*
|
|
83
|
-
* @param host - Server IP or hostname
|
|
84
|
-
* @param sshOptions - SSH options
|
|
85
|
-
* @returns Git status
|
|
86
|
-
*/
|
|
87
|
-
export async function checkGitStatus(
|
|
88
|
-
host: string,
|
|
89
|
-
sshOptions: Partial<SSHOptions> = {}
|
|
90
|
-
): Promise<{ configured: boolean; username?: string; email?: string; hasToken: boolean; message: string }> {
|
|
91
|
-
const { execSSH } = await import("@ebowwa/terminal/client");
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
const checkCmd = `
|
|
95
|
-
git config --global user.name 2>/dev/null || echo "NOT_SET"
|
|
96
|
-
git config --global user.email 2>/dev/null || echo "NOT_SET"
|
|
97
|
-
test -f ~/.git-credentials && echo "HAS_CREDS" || echo "NO_CREDS"
|
|
98
|
-
test -f ~/.config/gh/hosts.yml && echo "HAS_GH_TOKEN" || echo "NO_GH_TOKEN"
|
|
99
|
-
`;
|
|
100
|
-
|
|
101
|
-
const result = await execSSH(checkCmd, {
|
|
102
|
-
host,
|
|
103
|
-
user: "root",
|
|
104
|
-
timeout: 5000,
|
|
105
|
-
...sshOptions
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
const lines = result.trim().split("\n");
|
|
109
|
-
|
|
110
|
-
const username = lines[0]?.trim();
|
|
111
|
-
const email = lines[1]?.trim();
|
|
112
|
-
const hasCreds = lines[2]?.includes("HAS_CREDS");
|
|
113
|
-
const hasGhToken = lines[3]?.includes("HAS_GH_TOKEN");
|
|
114
|
-
|
|
115
|
-
const configured = username !== "NOT_SET";
|
|
116
|
-
|
|
117
|
-
return {
|
|
118
|
-
configured,
|
|
119
|
-
username: username !== "NOT_SET" ? username : undefined,
|
|
120
|
-
email: email !== "NOT_SET" ? email : undefined,
|
|
121
|
-
hasToken: hasCreds || hasGhToken,
|
|
122
|
-
message: configured
|
|
123
|
-
? `Git configured: ${username}${email ? ` <${email}>` : ""}`
|
|
124
|
-
: "Git not configured"
|
|
125
|
-
};
|
|
126
|
-
} catch (error) {
|
|
127
|
-
return {
|
|
128
|
-
configured: false,
|
|
129
|
-
hasToken: false,
|
|
130
|
-
message: `Could not check Git status: ${error instanceof Error ? error.message : String(error)}`
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
}
|
package/onboarding/index.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
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
|
-
*
|
|
10
|
-
* This is Phase 2 of the bootstrap process, running after
|
|
11
|
-
* cloud-init completes the initial installation.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
export { OnboardingConfig, OnboardingStatus, OnboardingResult } from "./types.js";
|
|
15
|
-
export { onboardDoppler, checkDopplerStatus } from "./doppler.js";
|
|
16
|
-
export { onboardTailscale, checkTailscaleStatus } from "./tailscale.js";
|
|
17
|
-
export { onboardGit, checkGitStatus } from "./git.js";
|
|
18
|
-
export { onboardServer, checkOnboardingStatus, onboardBatch } from "./onboarding.js";
|
package/onboarding/onboarding.ts
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Server Onboarding
|
|
3
|
-
*
|
|
4
|
-
* Main onboarding orchestration.
|
|
5
|
-
* Coordinates Doppler, Tailscale, and Git onboarding.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { SSHOptions } from "@ebowwa/terminal/types";
|
|
9
|
-
import type {
|
|
10
|
-
OnboardingConfig,
|
|
11
|
-
OnboardingStatus,
|
|
12
|
-
OnboardingResult,
|
|
13
|
-
BatchOnboardingResult,
|
|
14
|
-
} from "./types.js";
|
|
15
|
-
import { checkDopplerStatus, onboardDoppler } from "./doppler.js";
|
|
16
|
-
import { checkTailscaleStatus, onboardTailscale } from "./tailscale.js";
|
|
17
|
-
import { checkGitStatus, onboardGit } from "./git.js";
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Onboard a single server with all configured services
|
|
21
|
-
*
|
|
22
|
-
* @param config - Onboarding configuration
|
|
23
|
-
* @param sshOptions - Additional SSH options
|
|
24
|
-
* @returns Onboarding result
|
|
25
|
-
*/
|
|
26
|
-
export async function onboardServer(
|
|
27
|
-
config: OnboardingConfig,
|
|
28
|
-
sshOptions: Partial<SSHOptions> = {}
|
|
29
|
-
): Promise<OnboardingResult> {
|
|
30
|
-
const { host, user = "root", doppler, tailscale, git } = config;
|
|
31
|
-
|
|
32
|
-
const configured: ("doppler" | "tailscale" | "git")[] = [];
|
|
33
|
-
const failed: Array<{
|
|
34
|
-
service: "doppler" | "tailscale" | "git";
|
|
35
|
-
error: string;
|
|
36
|
-
}> = [];
|
|
37
|
-
|
|
38
|
-
const baseSshOptions: Partial<SSHOptions> = {
|
|
39
|
-
user,
|
|
40
|
-
...sshOptions
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
// Onboard Doppler
|
|
44
|
-
if (doppler) {
|
|
45
|
-
const result = await onboardDoppler(host, doppler, baseSshOptions);
|
|
46
|
-
if (result.success) {
|
|
47
|
-
configured.push("doppler");
|
|
48
|
-
} else {
|
|
49
|
-
failed.push({ service: "doppler", error: result.message });
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Onboard Tailscale
|
|
54
|
-
if (tailscale) {
|
|
55
|
-
const result = await onboardTailscale(host, tailscale, baseSshOptions);
|
|
56
|
-
if (result.success) {
|
|
57
|
-
configured.push("tailscale");
|
|
58
|
-
} else {
|
|
59
|
-
failed.push({ service: "tailscale", error: result.message });
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Onboard Git
|
|
64
|
-
if (git) {
|
|
65
|
-
const result = await onboardGit(host, git, baseSshOptions);
|
|
66
|
-
if (result.success) {
|
|
67
|
-
configured.push("git");
|
|
68
|
-
} else {
|
|
69
|
-
failed.push({ service: "git", error: result.message });
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return {
|
|
74
|
-
host,
|
|
75
|
-
configured,
|
|
76
|
-
failed,
|
|
77
|
-
success: failed.length === 0,
|
|
78
|
-
completedAt: new Date().toISOString(),
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Check onboarding status of a server
|
|
84
|
-
*
|
|
85
|
-
* @param host - Server IP or hostname
|
|
86
|
-
* @param sshOptions - SSH options
|
|
87
|
-
* @returns Onboarding status
|
|
88
|
-
*/
|
|
89
|
-
export async function checkOnboardingStatus(
|
|
90
|
-
host: string,
|
|
91
|
-
sshOptions: Partial<SSHOptions> = {}
|
|
92
|
-
): Promise<OnboardingStatus> {
|
|
93
|
-
const user = "root";
|
|
94
|
-
|
|
95
|
-
const [dopplerStatus, tailscaleStatus, gitStatus] = await Promise.all([
|
|
96
|
-
checkDopplerStatus(host, { user, ...sshOptions }),
|
|
97
|
-
checkTailscaleStatus(host, { user, ...sshOptions }),
|
|
98
|
-
checkGitStatus(host, { user, ...sshOptions }),
|
|
99
|
-
]);
|
|
100
|
-
|
|
101
|
-
const services = {
|
|
102
|
-
doppler: {
|
|
103
|
-
service: "doppler",
|
|
104
|
-
configured: dopplerStatus.configured,
|
|
105
|
-
message: dopplerStatus.message,
|
|
106
|
-
details: dopplerStatus.project
|
|
107
|
-
? { project: dopplerStatus.project, config: dopplerStatus.config }
|
|
108
|
-
: undefined,
|
|
109
|
-
} as const,
|
|
110
|
-
tailscale: {
|
|
111
|
-
service: "tailscale",
|
|
112
|
-
configured: tailscaleStatus.configured,
|
|
113
|
-
message: tailscaleStatus.message,
|
|
114
|
-
details: tailscaleStatus.tailscaleIp
|
|
115
|
-
? { tailscaleIp: tailscaleStatus.tailscaleIp, hostname: tailscaleStatus.hostname }
|
|
116
|
-
: undefined,
|
|
117
|
-
} as const,
|
|
118
|
-
git: {
|
|
119
|
-
service: "git",
|
|
120
|
-
configured: gitStatus.configured,
|
|
121
|
-
message: gitStatus.message,
|
|
122
|
-
details: gitStatus.username
|
|
123
|
-
? { username: gitStatus.username, email: gitStatus.email }
|
|
124
|
-
: undefined,
|
|
125
|
-
} as const,
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
const complete = services.doppler.configured && services.tailscale.configured && services.git.configured;
|
|
129
|
-
|
|
130
|
-
return {
|
|
131
|
-
host,
|
|
132
|
-
services,
|
|
133
|
-
complete,
|
|
134
|
-
checkedAt: new Date().toISOString(),
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Onboard multiple servers in parallel
|
|
140
|
-
*
|
|
141
|
-
* @param hosts - List of server IPs/hostnames
|
|
142
|
-
* @param sharedConfig - Shared onboarding config for all servers
|
|
143
|
-
* @param sshOptions - SSH options
|
|
144
|
-
* @returns Batch onboarding result
|
|
145
|
-
*/
|
|
146
|
-
export async function onboardBatch(
|
|
147
|
-
hosts: string[],
|
|
148
|
-
sharedConfig: Omit<OnboardingConfig, "host">,
|
|
149
|
-
sshOptions: Partial<SSHOptions> = {}
|
|
150
|
-
): Promise<BatchOnboardingResult> {
|
|
151
|
-
// Onboard all servers in parallel
|
|
152
|
-
const results = await Promise.all(
|
|
153
|
-
hosts.map((host) =>
|
|
154
|
-
onboardServer({ ...sharedConfig, host }, sshOptions)
|
|
155
|
-
)
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
// Calculate summary
|
|
159
|
-
const succeeded = results.filter((r) => r.success).length;
|
|
160
|
-
const failed = results.filter((r) => !r.success).length;
|
|
161
|
-
const partial = results.filter((r) => !r.success && r.configured.length > 0).length;
|
|
162
|
-
|
|
163
|
-
return {
|
|
164
|
-
results,
|
|
165
|
-
summary: {
|
|
166
|
-
total: results.length,
|
|
167
|
-
succeeded,
|
|
168
|
-
failed,
|
|
169
|
-
partial,
|
|
170
|
-
},
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Quick onboarding check for multiple servers
|
|
176
|
-
*
|
|
177
|
-
* @param hosts - List of server IPs/hostnames
|
|
178
|
-
* @param sshOptions - SSH options
|
|
179
|
-
* @returns Map of host to onboarding status
|
|
180
|
-
*/
|
|
181
|
-
export async function checkBatchStatus(
|
|
182
|
-
hosts: string[],
|
|
183
|
-
sshOptions: Partial<SSHOptions> = {}
|
|
184
|
-
): Promise<Map<string, OnboardingStatus>> {
|
|
185
|
-
const statuses = await Promise.all(
|
|
186
|
-
hosts.map(async (host) => {
|
|
187
|
-
const status = await checkOnboardingStatus(host, sshOptions);
|
|
188
|
-
return { host, status };
|
|
189
|
-
})
|
|
190
|
-
);
|
|
191
|
-
|
|
192
|
-
return new Map(statuses.map(({ host, status }) => [host, status]));
|
|
193
|
-
}
|
package/onboarding/tailscale.ts
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tailscale Onboarding
|
|
3
|
-
*
|
|
4
|
-
* Join Tailscale network on remote servers.
|
|
5
|
-
* Enables secure VPN access to servers.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { SSHOptions } from "@ebowwa/terminal/types";
|
|
9
|
-
|
|
10
|
-
export interface TailscaleConfig {
|
|
11
|
-
authKey: string;
|
|
12
|
-
hostname?: string;
|
|
13
|
-
tags?: string[];
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Join Tailscale network on a remote server
|
|
18
|
-
*
|
|
19
|
-
* @param host - Server IP or hostname
|
|
20
|
-
* @param config - Tailscale configuration
|
|
21
|
-
* @param sshOptions - SSH options
|
|
22
|
-
* @returns Success status with Tailscale IP
|
|
23
|
-
*/
|
|
24
|
-
export async function onboardTailscale(
|
|
25
|
-
host: string,
|
|
26
|
-
config: TailscaleConfig,
|
|
27
|
-
sshOptions: Partial<SSHOptions> = {}
|
|
28
|
-
): Promise<{ success: boolean; message: string; tailscaleIp?: string }> {
|
|
29
|
-
const { execSSH } = await import("@ebowwa/terminal/client");
|
|
30
|
-
|
|
31
|
-
const { authKey, hostname, tags = [] } = config;
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
// Step 1: Install Tailscale if not present
|
|
35
|
-
const installCmd = `
|
|
36
|
-
if ! command -v tailscale &>/dev/null; then
|
|
37
|
-
curl -fsSL https://tailscale.com/install.sh | sh
|
|
38
|
-
fi
|
|
39
|
-
`;
|
|
40
|
-
|
|
41
|
-
await execSSH(installCmd, {
|
|
42
|
-
host,
|
|
43
|
-
user: "root",
|
|
44
|
-
timeout: 60000, // 1 minute for install
|
|
45
|
-
...sshOptions
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
// Step 2: Build tailscale up command
|
|
49
|
-
const upArgs = ["up", "--authkey", authKey];
|
|
50
|
-
|
|
51
|
-
if (hostname) {
|
|
52
|
-
upArgs.push("--hostname", hostname);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (tags.length > 0) {
|
|
56
|
-
upArgs.push("--tags", tags.join(","));
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const upCmd = `tailscale ${upArgs.join(" ")}`;
|
|
60
|
-
|
|
61
|
-
// Step 3: Run tailscale up
|
|
62
|
-
await execSSH(upCmd, {
|
|
63
|
-
host,
|
|
64
|
-
user: "root",
|
|
65
|
-
timeout: 30000,
|
|
66
|
-
...sshOptions
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
// Step 4: Get Tailscale IP
|
|
70
|
-
const ipCmd = "tailscale ip -4 2>/dev/null || tailscale ip 2>/dev/null || echo 'PENDING'";
|
|
71
|
-
|
|
72
|
-
const ipResult = await execSSH(ipCmd, {
|
|
73
|
-
host,
|
|
74
|
-
user: "root",
|
|
75
|
-
timeout: 5000,
|
|
76
|
-
...sshOptions
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
const tailscaleIp = ipResult.trim();
|
|
80
|
-
|
|
81
|
-
return {
|
|
82
|
-
success: true,
|
|
83
|
-
message: hostname
|
|
84
|
-
? `Tailscale joined as ${hostname}`
|
|
85
|
-
: "Tailscale joined",
|
|
86
|
-
tailscaleIp: tailscaleIp !== "PENDING" ? tailscaleIp : undefined
|
|
87
|
-
};
|
|
88
|
-
} catch (error) {
|
|
89
|
-
return {
|
|
90
|
-
success: false,
|
|
91
|
-
message: `Tailscale onboarding failed: ${error instanceof Error ? error.message : String(error)}`
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Check Tailscale status on a remote server
|
|
98
|
-
*
|
|
99
|
-
* @param host - Server IP or hostname
|
|
100
|
-
* @param sshOptions - SSH options
|
|
101
|
-
* @returns Tailscale status
|
|
102
|
-
*/
|
|
103
|
-
export async function checkTailscaleStatus(
|
|
104
|
-
host: string,
|
|
105
|
-
sshOptions: Partial<SSHOptions> = {}
|
|
106
|
-
): Promise<{ configured: boolean; tailscaleIp?: string; hostname?: string; message: string }> {
|
|
107
|
-
const { execSSH } = await import("@ebowwa/terminal/client");
|
|
108
|
-
|
|
109
|
-
try {
|
|
110
|
-
// Check if tailscale is installed and running
|
|
111
|
-
const checkCmd = `
|
|
112
|
-
command -v tailscale &>/dev/null || echo "NOT_INSTALLED"
|
|
113
|
-
tailscale status --json 2>/dev/null || echo "NOT_RUNNING"
|
|
114
|
-
`;
|
|
115
|
-
|
|
116
|
-
const result = await execSSH(checkCmd, {
|
|
117
|
-
host,
|
|
118
|
-
user: "root",
|
|
119
|
-
timeout: 10000,
|
|
120
|
-
...sshOptions
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
const lines = result.trim().split("\n");
|
|
124
|
-
|
|
125
|
-
if (lines[0]?.includes("NOT_INSTALLED")) {
|
|
126
|
-
return {
|
|
127
|
-
configured: false,
|
|
128
|
-
message: "Tailscale not installed"
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const statusJson = lines[1] || "";
|
|
133
|
-
|
|
134
|
-
if (statusJson.includes("NOT_RUNNING")) {
|
|
135
|
-
return {
|
|
136
|
-
configured: false,
|
|
137
|
-
message: "Tailscale installed but not running"
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Parse status JSON
|
|
142
|
-
const status = JSON.parse(statusJson);
|
|
143
|
-
|
|
144
|
-
const tailscaleIp = status.TailnetIPs?.[0] || status.IPv4;
|
|
145
|
-
const hostname = status.HostName?.HostName || status.HostName;
|
|
146
|
-
|
|
147
|
-
return {
|
|
148
|
-
configured: true,
|
|
149
|
-
tailscaleIp,
|
|
150
|
-
hostname,
|
|
151
|
-
message: `Tailscale connected as ${hostname || "unknown"} (${tailscaleIp || "no IP"})`
|
|
152
|
-
};
|
|
153
|
-
} catch (error) {
|
|
154
|
-
return {
|
|
155
|
-
configured: false,
|
|
156
|
-
message: `Could not check Tailscale status: ${error instanceof Error ? error.message : String(error)}`
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
}
|
package/onboarding/types.ts
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Onboarding Types
|
|
3
|
-
*
|
|
4
|
-
* Type definitions for server onboarding operations.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Onboarding configuration for a server
|
|
9
|
-
*/
|
|
10
|
-
export interface OnboardingConfig {
|
|
11
|
-
/** Server IP or hostname */
|
|
12
|
-
host: string;
|
|
13
|
-
|
|
14
|
-
/** SSH user (default: root) */
|
|
15
|
-
user?: string;
|
|
16
|
-
|
|
17
|
-
/** SSH port (default: 22) */
|
|
18
|
-
port?: number;
|
|
19
|
-
|
|
20
|
-
/** Doppler configuration */
|
|
21
|
-
doppler?: {
|
|
22
|
-
/** Doppler service token */
|
|
23
|
-
token: string;
|
|
24
|
-
/** Doppler project (default: seed) */
|
|
25
|
-
project?: string;
|
|
26
|
-
/** Doppler config (default: prd) */
|
|
27
|
-
config?: string;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
/** Tailscale configuration */
|
|
31
|
-
tailscale?: {
|
|
32
|
-
/** Tailscale auth key */
|
|
33
|
-
authKey: string;
|
|
34
|
-
/** Tailscale hostname (optional) */
|
|
35
|
-
hostname?: string;
|
|
36
|
-
/** Tailscale tags (optional) */
|
|
37
|
-
tags?: string[];
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
/** Git configuration */
|
|
41
|
-
git?: {
|
|
42
|
-
/** Git username */
|
|
43
|
-
username?: string;
|
|
44
|
-
/** Git email */
|
|
45
|
-
email?: string;
|
|
46
|
-
/** GitHub token for gh cli */
|
|
47
|
-
githubToken?: string;
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Onboarding status for a single service
|
|
53
|
-
*/
|
|
54
|
-
export interface ServiceStatus {
|
|
55
|
-
/** Service name */
|
|
56
|
-
service: "doppler" | "tailscale" | "git";
|
|
57
|
-
/** Whether service is configured */
|
|
58
|
-
configured: boolean;
|
|
59
|
-
/** Status message */
|
|
60
|
-
message: string;
|
|
61
|
-
/** Configuration details (sanitized) */
|
|
62
|
-
details?: Record<string, unknown>;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Overall onboarding status
|
|
67
|
-
*/
|
|
68
|
-
export interface OnboardingStatus {
|
|
69
|
-
/** Server being checked */
|
|
70
|
-
host: string;
|
|
71
|
-
/** Status of each service */
|
|
72
|
-
services: {
|
|
73
|
-
doppler: ServiceStatus;
|
|
74
|
-
tailscale: ServiceStatus;
|
|
75
|
-
git: ServiceStatus;
|
|
76
|
-
};
|
|
77
|
-
/** Overall onboarding complete */
|
|
78
|
-
complete: boolean;
|
|
79
|
-
/** Timestamp */
|
|
80
|
-
checkedAt: string;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Result of an onboarding operation
|
|
85
|
-
*/
|
|
86
|
-
export interface OnboardingResult {
|
|
87
|
-
/** Server that was onboarded */
|
|
88
|
-
host: string;
|
|
89
|
-
/** Services that were configured */
|
|
90
|
-
configured: ("doppler" | "tailscale" | "git")[];
|
|
91
|
-
/** Services that failed */
|
|
92
|
-
failed: Array<{
|
|
93
|
-
service: "doppler" | "tailscale" | "git";
|
|
94
|
-
error: string;
|
|
95
|
-
}>;
|
|
96
|
-
/** Overall success */
|
|
97
|
-
success: boolean;
|
|
98
|
-
/** Timestamp */
|
|
99
|
-
completedAt: string;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Batch onboarding result
|
|
104
|
-
*/
|
|
105
|
-
export interface BatchOnboardingResult {
|
|
106
|
-
/** Results for each server */
|
|
107
|
-
results: OnboardingResult[];
|
|
108
|
-
/** Summary statistics */
|
|
109
|
-
summary: {
|
|
110
|
-
total: number;
|
|
111
|
-
succeeded: number;
|
|
112
|
-
failed: number;
|
|
113
|
-
partial: number;
|
|
114
|
-
};
|
|
115
|
-
}
|