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.
@@ -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, "&amp;")
170
+ .replace(/</g, "&lt;")
171
+ .replace(/>/g, "&gt;")
172
+ .replace(/"/g, "&quot;");
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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"}
@@ -1,10 +1,5 @@
1
- export declare function authenticate(pat: string, host: string): Promise<string>;
2
- export declare function resolveNamespaceId(namespace: string, host: string): Promise<string>;
3
- export interface ProjectInfo {
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 getProject(namespace: string, name: string, host: string): Promise<ProjectInfo | null>;
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;
@@ -1,65 +1,136 @@
1
- import { exec, execAsync, execSafe } from "../utils/shell.js";
1
+ import { exec, execSafe } from "../utils/shell.js";
2
2
  import { log } from "../utils/log.js";
3
- export async function authenticate(pat, host) {
4
- await execAsync(`echo "${pat}" | glab auth login --hostname "${host}" --stdin`);
5
- const username = await execAsync(`glab api "user" --hostname "${host}" | jq -r '.username'`);
6
- log.success(`Authenticated as: ${username}`);
7
- return username;
8
- }
9
- export async function resolveNamespaceId(namespace, host) {
10
- const result = execSafe(`glab api --hostname "${host}" "namespaces/${namespace}" 2>/dev/null | jq -r '.id'`);
11
- if (result.exitCode !== 0 || !result.stdout || result.stdout === "null") {
12
- throw new Error(`Namespace '${namespace}' not found. Check the group or username.`);
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
- log.success(`Namespace ID: ${result.stdout}`);
15
- return result.stdout;
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
- catch {
33
- return null;
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 async function createProject(name, namespaceId, host) {
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
- id: String(data.id),
50
- httpUrl: data.http_url_to_repo,
51
- pathWithNamespace: data.path_with_namespace,
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
@@ -1 +1 @@
1
- {"version":3,"file":"gitlab.js","sourceRoot":"","sources":["../../src/core/gitlab.ts"],"names":[],"mappings":"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"}
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>;
@@ -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":"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"}
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 GitLabConfigSchema: z.ZodObject<{
10
- gitlabPat: z.ZodString;
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 GitLabConfig = z.infer<typeof GitLabConfigSchema>;
28
+ export type GitConfig = z.infer<typeof GitConfigSchema>;
22
29
  export type SecretsConfig = z.infer<typeof SecretsConfigSchema>;
23
- export type BootstrapConfig = ClusterConfig & GitLabConfig & SecretsConfig & {
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 GitLabConfigSchema = z.object({
16
- gitlabPat: z.string().min(1, "GitLab PAT is required"),
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 OPTIONAL_COMPONENTS = COMPONENTS.filter((c) => !c.required && !DNS_TLS_COMPONENT_IDS.includes(c.id));
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 {