gitops-ai 1.0.0 → 1.1.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/LICENSE +21 -0
- package/README.md +16 -14
- package/dist/commands/bootstrap.js +476 -72
- package/dist/commands/bootstrap.js.map +1 -1
- package/dist/core/bootstrap-runner.js +27 -10
- package/dist/core/bootstrap-runner.js.map +1 -1
- package/dist/core/cloudflare-oauth.d.ts +1 -0
- package/dist/core/cloudflare-oauth.js +307 -0
- package/dist/core/cloudflare-oauth.js.map +1 -0
- package/dist/core/dependencies.js +0 -12
- package/dist/core/dependencies.js.map +1 -1
- package/dist/core/flux.d.ts +1 -1
- package/dist/core/flux.js +57 -8
- package/dist/core/flux.js.map +1 -1
- package/dist/core/git-provider.d.ts +38 -0
- package/dist/core/git-provider.js +30 -0
- package/dist/core/git-provider.js.map +1 -0
- package/dist/core/github-oauth.d.ts +1 -0
- package/dist/core/github-oauth.js +108 -0
- package/dist/core/github-oauth.js.map +1 -0
- package/dist/core/github.d.ts +12 -0
- package/dist/core/github.js +188 -0
- package/dist/core/github.js.map +1 -0
- package/dist/core/gitlab-oauth.d.ts +1 -0
- package/dist/core/gitlab-oauth.js +190 -0
- package/dist/core/gitlab-oauth.js.map +1 -0
- package/dist/core/gitlab.d.ts +4 -9
- package/dist/core/gitlab.js +127 -56
- package/dist/core/gitlab.js.map +1 -1
- package/dist/core/kubernetes.d.ts +9 -0
- package/dist/core/kubernetes.js +51 -1
- package/dist/core/kubernetes.js.map +1 -1
- package/dist/schemas.d.ts +15 -4
- package/dist/schemas.js +17 -3
- package/dist/schemas.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { createServer, } from "node:http";
|
|
2
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
3
|
+
import { URL } from "node:url";
|
|
4
|
+
import { execSync } from "node:child_process";
|
|
5
|
+
import * as p from "@clack/prompts";
|
|
6
|
+
import pc from "picocolors";
|
|
7
|
+
import { isMacOS } from "../utils/platform.js";
|
|
8
|
+
const OAUTH_SCOPES = "api read_repository write_repository";
|
|
9
|
+
const CALLBACK_PATH = "/callback";
|
|
10
|
+
const LOGIN_TIMEOUT_MS = 120_000;
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Pre-registered OAuth application per host (like Vercel, gh CLI).
|
|
13
|
+
// Register once at: https://<host>/-/user_settings/applications
|
|
14
|
+
// Name: gitops-ai
|
|
15
|
+
// Redirect URI: http://127.0.0.1/callback
|
|
16
|
+
// Confidential: No
|
|
17
|
+
// Scopes: api
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
const BUILTIN_CLIENT_IDS = {
|
|
20
|
+
"gitlab.com": "0e183a7a911ca9b4e078a42bdc9e9ea6a2e821cd5303c3ceca6ce9be51f7e627",
|
|
21
|
+
};
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// PKCE helpers (RFC 7636)
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
function base64url(buf) {
|
|
26
|
+
return buf
|
|
27
|
+
.toString("base64")
|
|
28
|
+
.replace(/\+/g, "-")
|
|
29
|
+
.replace(/\//g, "_")
|
|
30
|
+
.replace(/=+$/, "");
|
|
31
|
+
}
|
|
32
|
+
function generateVerifier() {
|
|
33
|
+
return base64url(randomBytes(32));
|
|
34
|
+
}
|
|
35
|
+
function computeChallenge(verifier) {
|
|
36
|
+
return base64url(createHash("sha256").update(verifier).digest());
|
|
37
|
+
}
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Browser opener
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
function openUrl(url) {
|
|
42
|
+
const cmd = isMacOS() ? "open" : "xdg-open";
|
|
43
|
+
try {
|
|
44
|
+
execSync(`${cmd} '${url}'`, { stdio: "ignore" });
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
/* user will see the manual URL in the terminal */
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// Resolve client_id — built-in or env var, nothing else needed.
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
function getClientId(host) {
|
|
54
|
+
const fromEnv = process.env.GITLAB_OAUTH_APP_ID;
|
|
55
|
+
if (fromEnv)
|
|
56
|
+
return fromEnv;
|
|
57
|
+
const builtIn = BUILTIN_CLIENT_IDS[host];
|
|
58
|
+
if (builtIn)
|
|
59
|
+
return builtIn;
|
|
60
|
+
throw new Error(`No OAuth application configured for ${host}. ` +
|
|
61
|
+
`Set GITLAB_OAUTH_APP_ID env var or add the host to BUILTIN_CLIENT_IDS.`);
|
|
62
|
+
}
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// Main browser-login flow
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
export async function loginWithBrowser(host) {
|
|
67
|
+
const clientId = getClientId(host);
|
|
68
|
+
const verifier = generateVerifier();
|
|
69
|
+
const challenge = computeChallenge(verifier);
|
|
70
|
+
const state = base64url(randomBytes(16));
|
|
71
|
+
return new Promise((resolve, reject) => {
|
|
72
|
+
let timer;
|
|
73
|
+
const server = createServer(async (req, res) => {
|
|
74
|
+
const url = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
75
|
+
if (url.pathname !== CALLBACK_PATH) {
|
|
76
|
+
res.writeHead(404);
|
|
77
|
+
res.end();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const error = url.searchParams.get("error");
|
|
81
|
+
if (error) {
|
|
82
|
+
const desc = url.searchParams.get("error_description") ?? error;
|
|
83
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
84
|
+
res.end(htmlPage("Authentication Failed", escapeHtml(desc), true));
|
|
85
|
+
finish(new Error(`GitLab OAuth: ${desc}`));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (url.searchParams.get("state") !== state) {
|
|
89
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
90
|
+
res.end(htmlPage("Security Error", "State mismatch — possible CSRF.", true));
|
|
91
|
+
finish(new Error("OAuth state mismatch"));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const code = url.searchParams.get("code");
|
|
95
|
+
if (!code) {
|
|
96
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
97
|
+
res.end(htmlPage("Error", "No authorization code received.", true));
|
|
98
|
+
finish(new Error("Missing authorization code"));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
const addr = server.address();
|
|
103
|
+
const port = typeof addr === "object" && addr ? addr.port : 0;
|
|
104
|
+
const redirectUri = `http://127.0.0.1:${port}${CALLBACK_PATH}`;
|
|
105
|
+
const tokenRes = await fetch(`https://${host}/oauth/token`, {
|
|
106
|
+
method: "POST",
|
|
107
|
+
headers: { "Content-Type": "application/json" },
|
|
108
|
+
body: JSON.stringify({
|
|
109
|
+
client_id: clientId,
|
|
110
|
+
code,
|
|
111
|
+
grant_type: "authorization_code",
|
|
112
|
+
redirect_uri: redirectUri,
|
|
113
|
+
code_verifier: verifier,
|
|
114
|
+
}),
|
|
115
|
+
});
|
|
116
|
+
if (!tokenRes.ok) {
|
|
117
|
+
const body = await tokenRes.text();
|
|
118
|
+
throw new Error(`Token exchange failed (${tokenRes.status}): ${body}`);
|
|
119
|
+
}
|
|
120
|
+
const { access_token } = (await tokenRes.json());
|
|
121
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
122
|
+
res.end(htmlPage("Authenticated", "You can close this tab and return to the terminal.", false));
|
|
123
|
+
finish(null, access_token);
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
127
|
+
res.end(htmlPage("Error", "Token exchange failed. Check the terminal.", true));
|
|
128
|
+
finish(err);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
function finish(err, token) {
|
|
132
|
+
clearTimeout(timer);
|
|
133
|
+
server.close();
|
|
134
|
+
if (err)
|
|
135
|
+
reject(err);
|
|
136
|
+
else
|
|
137
|
+
resolve(token);
|
|
138
|
+
}
|
|
139
|
+
server.listen(0, "127.0.0.1", () => {
|
|
140
|
+
const addr = server.address();
|
|
141
|
+
const port = typeof addr === "object" && addr ? addr.port : 0;
|
|
142
|
+
const redirectUri = `http://127.0.0.1:${port}${CALLBACK_PATH}`;
|
|
143
|
+
const authUrl = new URL(`https://${host}/oauth/authorize`);
|
|
144
|
+
authUrl.searchParams.set("client_id", clientId);
|
|
145
|
+
authUrl.searchParams.set("redirect_uri", redirectUri);
|
|
146
|
+
authUrl.searchParams.set("response_type", "code");
|
|
147
|
+
authUrl.searchParams.set("scope", OAUTH_SCOPES);
|
|
148
|
+
authUrl.searchParams.set("code_challenge", challenge);
|
|
149
|
+
authUrl.searchParams.set("code_challenge_method", "S256");
|
|
150
|
+
authUrl.searchParams.set("state", state);
|
|
151
|
+
const urlStr = authUrl.toString();
|
|
152
|
+
p.log.info("Opening browser for GitLab authorization...");
|
|
153
|
+
p.log.info(pc.dim(`If the browser doesn't open, visit:\n${pc.cyan(urlStr)}`));
|
|
154
|
+
openUrl(urlStr);
|
|
155
|
+
});
|
|
156
|
+
timer = setTimeout(() => {
|
|
157
|
+
finish(new Error("Login timed out — no response within 2 minutes"));
|
|
158
|
+
}, LOGIN_TIMEOUT_MS);
|
|
159
|
+
server.on("error", (err) => {
|
|
160
|
+
finish(new Error(`Local OAuth server failed: ${err.message}`));
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
// Callback HTML pages
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
function escapeHtml(s) {
|
|
168
|
+
return s
|
|
169
|
+
.replace(/&/g, "&")
|
|
170
|
+
.replace(/</g, "<")
|
|
171
|
+
.replace(/>/g, ">")
|
|
172
|
+
.replace(/"/g, """);
|
|
173
|
+
}
|
|
174
|
+
function htmlPage(title, message, isError) {
|
|
175
|
+
const accent = isError ? "#f85149" : "#58a6ff";
|
|
176
|
+
return `<!DOCTYPE html>
|
|
177
|
+
<html><head><meta charset="utf-8"><title>GitOps AI — ${escapeHtml(title)}</title>
|
|
178
|
+
<style>
|
|
179
|
+
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
|
|
180
|
+
display:flex;align-items:center;justify-content:center;min-height:100vh;
|
|
181
|
+
margin:0;background:#0d1117;color:#e6edf3}
|
|
182
|
+
.c{text-align:center;padding:3rem;border-radius:12px;background:#161b22;
|
|
183
|
+
border:1px solid #30363d;max-width:420px}
|
|
184
|
+
h1{color:${accent};margin-bottom:.5rem}
|
|
185
|
+
p{color:#8b949e;line-height:1.6}
|
|
186
|
+
</style></head><body><div class="c">
|
|
187
|
+
<h1>${escapeHtml(title)}</h1><p>${message}</p>
|
|
188
|
+
</div></body></html>`;
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=gitlab-oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitlab-oauth.js","sourceRoot":"","sources":["../../src/core/gitlab-oauth.ts"],"names":[],"mappings":"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"}
|
package/dist/core/gitlab.d.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
id: string;
|
|
5
|
-
httpUrl: string;
|
|
6
|
-
pathWithNamespace: string;
|
|
1
|
+
import type { GitProvider } from "./git-provider.js";
|
|
2
|
+
export interface GitLabProvider extends GitProvider {
|
|
3
|
+
readonly type: "gitlab";
|
|
7
4
|
}
|
|
8
|
-
export declare function
|
|
9
|
-
export declare function createProject(name: string, namespaceId: string, host: string): Promise<ProjectInfo>;
|
|
10
|
-
export declare function configureGitCredentials(pat: string, cwd: string): void;
|
|
5
|
+
export declare function createGitLabProvider(): GitLabProvider;
|
package/dist/core/gitlab.js
CHANGED
|
@@ -1,65 +1,136 @@
|
|
|
1
|
-
import { exec,
|
|
1
|
+
import { exec, execSafe } from "../utils/shell.js";
|
|
2
2
|
import { log } from "../utils/log.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
import { loginWithBrowser } from "./gitlab-oauth.js";
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// REST helpers
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
async function apiFetch(path, token, host) {
|
|
8
|
+
const url = `https://${host}/api/v4${path}`;
|
|
9
|
+
let res = await fetch(url, {
|
|
10
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
11
|
+
});
|
|
12
|
+
// Fall back to PRIVATE-TOKEN header (PATs on older GitLab versions)
|
|
13
|
+
if (res.status === 401) {
|
|
14
|
+
res = await fetch(url, {
|
|
15
|
+
headers: { "PRIVATE-TOKEN": token },
|
|
16
|
+
});
|
|
13
17
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
export async function getProject(namespace, name, host) {
|
|
18
|
-
const encoded = `${namespace}/${name}`.replace(/\//g, "%2F");
|
|
19
|
-
const { stdout, exitCode } = execSafe(`glab api --hostname "${host}" "projects/${encoded}" 2>/dev/null`);
|
|
20
|
-
if (exitCode !== 0 || !stdout)
|
|
21
|
-
return null;
|
|
22
|
-
try {
|
|
23
|
-
const data = JSON.parse(stdout);
|
|
24
|
-
if (!data.id)
|
|
25
|
-
return null;
|
|
26
|
-
return {
|
|
27
|
-
id: String(data.id),
|
|
28
|
-
httpUrl: data.http_url_to_repo,
|
|
29
|
-
pathWithNamespace: data.path_with_namespace,
|
|
30
|
-
};
|
|
18
|
+
if (!res.ok) {
|
|
19
|
+
throw new Error(`GitLab API ${path}: ${res.status} ${res.statusText}`);
|
|
31
20
|
}
|
|
32
|
-
|
|
33
|
-
|
|
21
|
+
return res.json();
|
|
22
|
+
}
|
|
23
|
+
async function apiPost(path, token, host, body) {
|
|
24
|
+
const url = `https://${host}/api/v4${path}`;
|
|
25
|
+
const res = await fetch(url, {
|
|
26
|
+
method: "POST",
|
|
27
|
+
headers: {
|
|
28
|
+
Authorization: `Bearer ${token}`,
|
|
29
|
+
"Content-Type": "application/json",
|
|
30
|
+
},
|
|
31
|
+
body: JSON.stringify(body),
|
|
32
|
+
});
|
|
33
|
+
if (!res.ok) {
|
|
34
|
+
const text = await res.text();
|
|
35
|
+
throw new Error(`GitLab API POST ${path}: ${res.status} ${text}`);
|
|
34
36
|
}
|
|
37
|
+
return res.json();
|
|
35
38
|
}
|
|
36
|
-
export
|
|
37
|
-
const result = await execAsync([
|
|
38
|
-
"glab api --method POST",
|
|
39
|
-
`--hostname "${host}"`,
|
|
40
|
-
'"projects"',
|
|
41
|
-
`-f "name=${name}"`,
|
|
42
|
-
`-f "path=${name}"`,
|
|
43
|
-
`-f "namespace_id=${namespaceId}"`,
|
|
44
|
-
'-f "visibility=private"',
|
|
45
|
-
'-f "initialize_with_readme=false"',
|
|
46
|
-
].join(" "));
|
|
47
|
-
const data = JSON.parse(result);
|
|
39
|
+
export function createGitLabProvider() {
|
|
48
40
|
return {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
41
|
+
type: "gitlab",
|
|
42
|
+
defaultHost: "gitlab.com",
|
|
43
|
+
cliTool: "glab",
|
|
44
|
+
tokenLabel: "GitLab Personal Access Token (api, read_repository, write_repository)",
|
|
45
|
+
async fetchCurrentUser(token, host) {
|
|
46
|
+
const u = await apiFetch("/user", token, host);
|
|
47
|
+
return { username: u.username, name: u.name };
|
|
48
|
+
},
|
|
49
|
+
async fetchOrganizations(token, host) {
|
|
50
|
+
const groups = await apiFetch("/groups?per_page=100&min_access_level=30&top_level_only=true&order_by=name&sort=asc", token, host);
|
|
51
|
+
return groups.map((g) => ({
|
|
52
|
+
name: g.name,
|
|
53
|
+
path: g.path,
|
|
54
|
+
fullPath: g.full_path,
|
|
55
|
+
}));
|
|
56
|
+
},
|
|
57
|
+
async fetchNamespaceProjects(token, host, namespace) {
|
|
58
|
+
const encoded = encodeURIComponent(namespace);
|
|
59
|
+
let projects;
|
|
60
|
+
try {
|
|
61
|
+
projects = await apiFetch(`/groups/${encoded}/projects?per_page=100&order_by=updated_at&sort=desc&include_subgroups=false`, token, host);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
projects = await apiFetch(`/users/${encoded}/projects?per_page=100&order_by=updated_at&sort=desc`, token, host);
|
|
65
|
+
}
|
|
66
|
+
return projects.map((p) => ({
|
|
67
|
+
name: p.name,
|
|
68
|
+
description: p.description,
|
|
69
|
+
pathWithNamespace: p.path_with_namespace,
|
|
70
|
+
httpUrl: p.http_url_to_repo,
|
|
71
|
+
}));
|
|
72
|
+
},
|
|
73
|
+
async authenticate(token, host) {
|
|
74
|
+
const user = await this.fetchCurrentUser(token, host);
|
|
75
|
+
log.success(`Authenticated as: ${user.username}`);
|
|
76
|
+
return user.username;
|
|
77
|
+
},
|
|
78
|
+
async resolveNamespaceId(namespace, host, token) {
|
|
79
|
+
const encoded = encodeURIComponent(namespace);
|
|
80
|
+
try {
|
|
81
|
+
const ns = await apiFetch(`/namespaces/${encoded}`, token, host);
|
|
82
|
+
log.success(`Namespace ID: ${ns.id}`);
|
|
83
|
+
return String(ns.id);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
throw new Error(`Namespace '${namespace}' not found. Check the group or username.`);
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
async getProject(namespace, name, host, token) {
|
|
90
|
+
const encoded = encodeURIComponent(`${namespace}/${name}`);
|
|
91
|
+
try {
|
|
92
|
+
const p = await apiFetch(`/projects/${encoded}`, token, host);
|
|
93
|
+
return {
|
|
94
|
+
id: String(p.id),
|
|
95
|
+
httpUrl: p.http_url_to_repo,
|
|
96
|
+
pathWithNamespace: p.path_with_namespace,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
async createProject(name, namespaceId, host, token) {
|
|
104
|
+
const p = await apiPost("/projects", token, host, {
|
|
105
|
+
name,
|
|
106
|
+
path: name,
|
|
107
|
+
namespace_id: Number(namespaceId),
|
|
108
|
+
visibility: "private",
|
|
109
|
+
initialize_with_readme: false,
|
|
110
|
+
});
|
|
111
|
+
return {
|
|
112
|
+
id: String(p.id),
|
|
113
|
+
httpUrl: p.http_url_to_repo,
|
|
114
|
+
pathWithNamespace: p.path_with_namespace,
|
|
115
|
+
};
|
|
116
|
+
},
|
|
117
|
+
configureGitCredentials(token, cwd) {
|
|
118
|
+
const { exitCode, stdout } = execSafe("git remote get-url origin 2>/dev/null");
|
|
119
|
+
let host = "gitlab.com";
|
|
120
|
+
if (exitCode === 0 && stdout) {
|
|
121
|
+
const match = stdout.match(/https:\/\/([^/]+)\//);
|
|
122
|
+
if (match)
|
|
123
|
+
host = match[1];
|
|
124
|
+
}
|
|
125
|
+
exec(`git config --local --replace-all credential.helper '!f() { echo "username=oauth2"; echo "password=${token}"; }; f'`, { cwd });
|
|
126
|
+
log.success(`git credentials configured for ${host}`);
|
|
127
|
+
},
|
|
128
|
+
getAuthRemoteUrl(host, pathWithNamespace, token) {
|
|
129
|
+
return `https://oauth2:${token}@${host}/${pathWithNamespace}.git`;
|
|
130
|
+
},
|
|
131
|
+
async loginWithBrowser(host) {
|
|
132
|
+
return loginWithBrowser(host);
|
|
133
|
+
},
|
|
52
134
|
};
|
|
53
135
|
}
|
|
54
|
-
export function configureGitCredentials(pat, cwd) {
|
|
55
|
-
const { exitCode, stdout } = execSafe("git remote get-url origin 2>/dev/null");
|
|
56
|
-
let host = "gitlab.com";
|
|
57
|
-
if (exitCode === 0 && stdout) {
|
|
58
|
-
const match = stdout.match(/https:\/\/([^/]+)\//);
|
|
59
|
-
if (match)
|
|
60
|
-
host = match[1];
|
|
61
|
-
}
|
|
62
|
-
exec(`git config --local --replace-all credential.helper '!f() { echo "username=oauth2"; echo "password=${pat}"; }; f'`, { cwd });
|
|
63
|
-
log.success(`git credentials configured for ${host}`);
|
|
64
|
-
}
|
|
65
136
|
//# sourceMappingURL=gitlab.js.map
|
package/dist/core/gitlab.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitlab.js","sourceRoot":"","sources":["../../src/core/gitlab.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"gitlab.js","sourceRoot":"","sources":["../../src/core/gitlab.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
export declare function isClusterReachable(): boolean;
|
|
2
|
+
export interface ExistingCluster {
|
|
3
|
+
type: "k3d" | "k3s";
|
|
4
|
+
names: string[];
|
|
5
|
+
}
|
|
6
|
+
export declare function detectExistingClusters(): ExistingCluster | null;
|
|
7
|
+
export declare function listK3dClusters(): string[];
|
|
8
|
+
export declare function k3dClusterExists(clusterName: string): boolean;
|
|
9
|
+
export declare function k3sInstalled(): boolean;
|
|
2
10
|
export declare function createK3dCluster(clusterName: string): Promise<void>;
|
|
3
11
|
export declare function installK3s(): Promise<void>;
|
|
4
12
|
export declare function setupKubeconfig(clusterName: string): string;
|
|
@@ -8,3 +16,4 @@ export declare function createSecret(name: string, namespace: string, data: Reco
|
|
|
8
16
|
export declare function secretExists(name: string, namespace: string): boolean;
|
|
9
17
|
export declare function deleteSecret(name: string, namespace: string): Promise<void>;
|
|
10
18
|
export declare function createSecretFromFile(name: string, namespace: string, key: string, filePath: string): Promise<void>;
|
|
19
|
+
export declare function createSshSecret(name: string, namespace: string, privateKey: string, publicKey: string, knownHosts: string): Promise<void>;
|
package/dist/core/kubernetes.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
2
2
|
import { exec, execAsync, execSafe } from "../utils/shell.js";
|
|
3
3
|
import { isMacOS, isCI } from "../utils/platform.js";
|
|
4
4
|
import { log, withSpinner } from "../utils/log.js";
|
|
@@ -7,6 +7,35 @@ export function isClusterReachable() {
|
|
|
7
7
|
const { exitCode } = execSafe("kubectl cluster-info 2>/dev/null");
|
|
8
8
|
return exitCode === 0;
|
|
9
9
|
}
|
|
10
|
+
export function detectExistingClusters() {
|
|
11
|
+
if (isMacOS() || isCI()) {
|
|
12
|
+
const names = listK3dClusters();
|
|
13
|
+
if (names.length > 0)
|
|
14
|
+
return { type: "k3d", names };
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
if (k3sInstalled()) {
|
|
18
|
+
return { type: "k3s", names: ["k3s"] };
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
export function listK3dClusters() {
|
|
23
|
+
const { stdout, exitCode } = execSafe("k3d cluster list --no-headers 2>/dev/null");
|
|
24
|
+
if (exitCode !== 0 || !stdout.trim())
|
|
25
|
+
return [];
|
|
26
|
+
return stdout
|
|
27
|
+
.trim()
|
|
28
|
+
.split("\n")
|
|
29
|
+
.map((line) => line.split(/\s+/)[0])
|
|
30
|
+
.filter(Boolean);
|
|
31
|
+
}
|
|
32
|
+
export function k3dClusterExists(clusterName) {
|
|
33
|
+
return listK3dClusters().includes(clusterName);
|
|
34
|
+
}
|
|
35
|
+
export function k3sInstalled() {
|
|
36
|
+
const { exitCode } = execSafe("command -v k3s");
|
|
37
|
+
return exitCode === 0;
|
|
38
|
+
}
|
|
10
39
|
export async function createK3dCluster(clusterName) {
|
|
11
40
|
const { stdout } = execSafe("k3d cluster list 2>/dev/null");
|
|
12
41
|
if (stdout.includes(clusterName)) {
|
|
@@ -78,4 +107,25 @@ export async function createSecretFromFile(name, namespace, key, filePath) {
|
|
|
78
107
|
log.detail(`kubectl create secret generic ${name} --namespace=${namespace} --from-file=${key}`);
|
|
79
108
|
await execAsync(cmd);
|
|
80
109
|
}
|
|
110
|
+
export async function createSshSecret(name, namespace, privateKey, publicKey, knownHosts) {
|
|
111
|
+
const tmpDir = "/tmp/flux-ssh-secret";
|
|
112
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
113
|
+
try {
|
|
114
|
+
writeFileSync(`${tmpDir}/identity`, privateKey, { mode: 0o600 });
|
|
115
|
+
writeFileSync(`${tmpDir}/identity.pub`, publicKey);
|
|
116
|
+
writeFileSync(`${tmpDir}/known_hosts`, knownHosts);
|
|
117
|
+
const cmd = [
|
|
118
|
+
`kubectl create secret generic ${name}`,
|
|
119
|
+
`--namespace=${namespace}`,
|
|
120
|
+
`--from-file=identity="${tmpDir}/identity"`,
|
|
121
|
+
`--from-file=identity.pub="${tmpDir}/identity.pub"`,
|
|
122
|
+
`--from-file=known_hosts="${tmpDir}/known_hosts"`,
|
|
123
|
+
].join(" ");
|
|
124
|
+
log.detail(`kubectl create secret generic ${name} --namespace=${namespace} (SSH)`);
|
|
125
|
+
await execAsync(cmd);
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
81
131
|
//# sourceMappingURL=kubernetes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kubernetes.js","sourceRoot":"","sources":["../../src/core/kubernetes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAa,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"kubernetes.js","sourceRoot":"","sources":["../../src/core/kubernetes.ts"],"names":[],"mappings":"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"}
|
package/dist/schemas.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import type { ProviderType } from "./core/git-provider.js";
|
|
2
3
|
export declare const ClusterConfigSchema: z.ZodObject<{
|
|
3
4
|
clusterName: z.ZodString;
|
|
4
5
|
clusterDomain: z.ZodString;
|
|
@@ -6,8 +7,14 @@ export declare const ClusterConfigSchema: z.ZodObject<{
|
|
|
6
7
|
letsencryptEmail: z.ZodOptional<z.ZodString>;
|
|
7
8
|
ingressAllowedIps: z.ZodString;
|
|
8
9
|
}, z.core.$strip>;
|
|
9
|
-
export declare const
|
|
10
|
-
|
|
10
|
+
export declare const GitConfigSchema: z.ZodObject<{
|
|
11
|
+
gitProvider: z.ZodDefault<z.ZodEnum<{
|
|
12
|
+
gitlab: "gitlab";
|
|
13
|
+
github: "github";
|
|
14
|
+
}>>;
|
|
15
|
+
gitToken: z.ZodString;
|
|
16
|
+
gitFluxToken: z.ZodOptional<z.ZodString>;
|
|
17
|
+
gitHost: z.ZodOptional<z.ZodString>;
|
|
11
18
|
repoName: z.ZodString;
|
|
12
19
|
repoOwner: z.ZodString;
|
|
13
20
|
repoBranch: z.ZodString;
|
|
@@ -18,11 +25,12 @@ export declare const SecretsConfigSchema: z.ZodObject<{
|
|
|
18
25
|
openclawGatewayToken: z.ZodOptional<z.ZodString>;
|
|
19
26
|
}, z.core.$strip>;
|
|
20
27
|
export type ClusterConfig = z.infer<typeof ClusterConfigSchema>;
|
|
21
|
-
export type
|
|
28
|
+
export type GitConfig = z.infer<typeof GitConfigSchema>;
|
|
22
29
|
export type SecretsConfig = z.infer<typeof SecretsConfigSchema>;
|
|
23
|
-
export type BootstrapConfig = ClusterConfig &
|
|
30
|
+
export type BootstrapConfig = ClusterConfig & GitConfig & SecretsConfig & {
|
|
24
31
|
selectedComponents: string[];
|
|
25
32
|
};
|
|
33
|
+
export type { ProviderType };
|
|
26
34
|
export interface SopsConfig {
|
|
27
35
|
keyDir: string;
|
|
28
36
|
keyFile: string;
|
|
@@ -42,9 +50,12 @@ export interface ComponentDef {
|
|
|
42
50
|
export declare const COMPONENTS: ComponentDef[];
|
|
43
51
|
export declare const REQUIRED_COMPONENT_IDS: string[];
|
|
44
52
|
export declare const DNS_TLS_COMPONENT_IDS: string[];
|
|
53
|
+
export declare const MONITORING_COMPONENT_IDS: string[];
|
|
45
54
|
export declare const OPTIONAL_COMPONENTS: ComponentDef[];
|
|
46
55
|
export declare const KUBERNETES_VERSION = "1.35.1";
|
|
47
56
|
export declare const SOURCE_GITLAB_HOST = "gitlab.com";
|
|
48
57
|
export declare const SOURCE_PROJECT_PATH = "everythings-gonna-be-alright/fluxcd_ai_template";
|
|
49
58
|
export declare const INSTALL_PLAN_PATH = "/tmp/installplan.json";
|
|
59
|
+
export declare function isShortLivedGitHubToken(token: string): boolean;
|
|
60
|
+
export declare function shouldUseSshDeployKey(config: BootstrapConfig): boolean;
|
|
50
61
|
export declare function defaultSopsConfig(repoRoot: string): SopsConfig;
|
package/dist/schemas.js
CHANGED
|
@@ -12,8 +12,11 @@ export const ClusterConfigSchema = z.object({
|
|
|
12
12
|
letsencryptEmail: z.string().optional(),
|
|
13
13
|
ingressAllowedIps: z.string().min(1),
|
|
14
14
|
});
|
|
15
|
-
export const
|
|
16
|
-
|
|
15
|
+
export const GitConfigSchema = z.object({
|
|
16
|
+
gitProvider: z.enum(["gitlab", "github"]).default("gitlab"),
|
|
17
|
+
gitToken: z.string().min(1, "Git token is required"),
|
|
18
|
+
gitFluxToken: z.string().optional(),
|
|
19
|
+
gitHost: z.string().min(1).optional(),
|
|
17
20
|
repoName: z.string().min(1),
|
|
18
21
|
repoOwner: z.string().min(1),
|
|
19
22
|
repoBranch: z.string().min(1),
|
|
@@ -29,12 +32,15 @@ export const COMPONENTS = [
|
|
|
29
32
|
{ id: "cert-manager", label: "Cert Manager", hint: "Automatic TLS certificates via Let's Encrypt", required: false, secrets: ["secret-cloudflare.yaml"] },
|
|
30
33
|
{ id: "external-dns", label: "External DNS", hint: "Automatic DNS records in Cloudflare", required: false, secrets: ["secret-cloudflare.yaml"] },
|
|
31
34
|
{ id: "prometheus-operator-crds", label: "Prometheus CRDs", hint: "Monitoring custom resource definitions", required: true },
|
|
35
|
+
{ id: "grafana-operator", label: "Grafana Operator", hint: "Grafana dashboards and datasources via CRDs", required: false, subdomain: "grafana" },
|
|
36
|
+
{ id: "victoria-metrics-k8s-stack", label: "Victoria Metrics Stack", hint: "Metrics collection, alerting and long-term storage", required: false, subdomain: "victoria" },
|
|
32
37
|
{ id: "flux-web", label: "Flux Web UI", hint: "Web dashboard for Flux status", required: false, subdomain: "flux" },
|
|
33
38
|
{ id: "openclaw", label: "OpenClaw", hint: "AI assistant gateway (requires OpenAI key)", required: false, secrets: ["secret-openclaw-envs.yaml"], subdomain: "openclaw" },
|
|
34
39
|
];
|
|
35
40
|
export const REQUIRED_COMPONENT_IDS = COMPONENTS.filter((c) => c.required).map((c) => c.id);
|
|
36
41
|
export const DNS_TLS_COMPONENT_IDS = ["cert-manager", "external-dns"];
|
|
37
|
-
export const
|
|
42
|
+
export const MONITORING_COMPONENT_IDS = ["grafana-operator", "victoria-metrics-k8s-stack"];
|
|
43
|
+
export const OPTIONAL_COMPONENTS = COMPONENTS.filter((c) => !c.required && !DNS_TLS_COMPONENT_IDS.includes(c.id) && !MONITORING_COMPONENT_IDS.includes(c.id));
|
|
38
44
|
// ---------------------------------------------------------------------------
|
|
39
45
|
// Constants
|
|
40
46
|
// ---------------------------------------------------------------------------
|
|
@@ -42,6 +48,14 @@ export const KUBERNETES_VERSION = "1.35.1";
|
|
|
42
48
|
export const SOURCE_GITLAB_HOST = "gitlab.com";
|
|
43
49
|
export const SOURCE_PROJECT_PATH = "everythings-gonna-be-alright/fluxcd_ai_template";
|
|
44
50
|
export const INSTALL_PLAN_PATH = "/tmp/installplan.json";
|
|
51
|
+
export function isShortLivedGitHubToken(token) {
|
|
52
|
+
return token.startsWith("gho_") || token.startsWith("ghu_");
|
|
53
|
+
}
|
|
54
|
+
export function shouldUseSshDeployKey(config) {
|
|
55
|
+
return (config.gitProvider === "github" &&
|
|
56
|
+
isShortLivedGitHubToken(config.gitToken) &&
|
|
57
|
+
!config.gitFluxToken);
|
|
58
|
+
}
|
|
45
59
|
export function defaultSopsConfig(repoRoot) {
|
|
46
60
|
const keyDir = process.env.SOPS_AGE_KEY_DIR ?? `${process.env.HOME}/.sops`;
|
|
47
61
|
return {
|