@synap-core/cli 0.9.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.
Files changed (45) hide show
  1. package/README.md +250 -0
  2. package/dist/commands/connect.d.ts +11 -0
  3. package/dist/commands/connect.js +96 -0
  4. package/dist/commands/connect.js.map +1 -0
  5. package/dist/commands/finish.d.ts +16 -0
  6. package/dist/commands/finish.js +82 -0
  7. package/dist/commands/finish.js.map +1 -0
  8. package/dist/commands/init.d.ts +21 -0
  9. package/dist/commands/init.js +865 -0
  10. package/dist/commands/init.js.map +1 -0
  11. package/dist/commands/security-audit.d.ts +12 -0
  12. package/dist/commands/security-audit.js +100 -0
  13. package/dist/commands/security-audit.js.map +1 -0
  14. package/dist/commands/status.d.ts +6 -0
  15. package/dist/commands/status.js +216 -0
  16. package/dist/commands/status.js.map +1 -0
  17. package/dist/commands/update.d.ts +6 -0
  18. package/dist/commands/update.js +34 -0
  19. package/dist/commands/update.js.map +1 -0
  20. package/dist/index.d.ts +16 -0
  21. package/dist/index.js +138 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/lib/auth.d.ts +57 -0
  24. package/dist/lib/auth.js +322 -0
  25. package/dist/lib/auth.js.map +1 -0
  26. package/dist/lib/hardening.d.ts +18 -0
  27. package/dist/lib/hardening.js +203 -0
  28. package/dist/lib/hardening.js.map +1 -0
  29. package/dist/lib/openclaw.d.ts +28 -0
  30. package/dist/lib/openclaw.js +106 -0
  31. package/dist/lib/openclaw.js.map +1 -0
  32. package/dist/lib/pod.d.ts +91 -0
  33. package/dist/lib/pod.js +305 -0
  34. package/dist/lib/pod.js.map +1 -0
  35. package/dist/lib/seed.d.ts +13 -0
  36. package/dist/lib/seed.js +135 -0
  37. package/dist/lib/seed.js.map +1 -0
  38. package/dist/lib/templates.d.ts +11 -0
  39. package/dist/lib/templates.js +13 -0
  40. package/dist/lib/templates.js.map +1 -0
  41. package/dist/templates/agent-os.json +3090 -0
  42. package/dist/utils/logger.d.ts +11 -0
  43. package/dist/utils/logger.js +31 -0
  44. package/dist/utils/logger.js.map +1 -0
  45. package/package.json +45 -0
@@ -0,0 +1,57 @@
1
+ /**
2
+ * CLI Authentication Module
3
+ *
4
+ * Browser-based OAuth flow:
5
+ * 1. Start temporary HTTP server on localhost (random port)
6
+ * 2. Open browser to synap.live/auth/cli?callback=http://localhost:PORT/callback
7
+ * 3. User logs in via Better Auth (email/password, Google, GitHub)
8
+ * 4. synap.live redirects to localhost callback with session token
9
+ * 5. CLI stores token in ~/.synap/credentials.json
10
+ */
11
+ export interface StoredCredentials {
12
+ token: string;
13
+ expiresAt: string;
14
+ userId: string;
15
+ email: string;
16
+ }
17
+ export declare function getStoredToken(): StoredCredentials | null;
18
+ /** True if local expiry timestamp has passed (does NOT call the server). */
19
+ export declare function isTokenLocallyExpired(creds: StoredCredentials): boolean;
20
+ export declare function logout(): void;
21
+ export declare function isLoggedIn(): Promise<{
22
+ valid: boolean;
23
+ email?: string;
24
+ userId?: string;
25
+ }>;
26
+ /**
27
+ * Store a manually provided API token (Better Auth session token).
28
+ * Validates against the CP before saving.
29
+ *
30
+ * Usage: synap login --token <token>
31
+ * Get a token from: https://synap.live/account/tokens
32
+ */
33
+ export declare function loginWithToken(token: string): Promise<StoredCredentials | null>;
34
+ export declare function login(): Promise<StoredCredentials | null>;
35
+ export interface PodCallbackResult {
36
+ podUrl: string;
37
+ workspaceId?: string;
38
+ }
39
+ export declare function waitForPodCallback(timeoutMs?: number): Promise<PodCallbackResult | null>;
40
+ export declare function getCpUrl(): string;
41
+ export interface Pod {
42
+ id: string;
43
+ subdomain: string;
44
+ customDomain: string | null;
45
+ status: string;
46
+ region: string;
47
+ url: string;
48
+ }
49
+ export declare function listPods(token: string): Promise<Pod[]>;
50
+ /**
51
+ * Get the remote OpenClaw provisioning status from the CP.
52
+ * Returns null if not provisioned or on network error.
53
+ */
54
+ export declare function getOpenClawRemoteStatus(cpToken: string, podId: string): Promise<{
55
+ status: "not_provisioned" | "provisioning" | "running" | "error";
56
+ url: string | null;
57
+ } | null>;
@@ -0,0 +1,322 @@
1
+ /**
2
+ * CLI Authentication Module
3
+ *
4
+ * Browser-based OAuth flow:
5
+ * 1. Start temporary HTTP server on localhost (random port)
6
+ * 2. Open browser to synap.live/auth/cli?callback=http://localhost:PORT/callback
7
+ * 3. User logs in via Better Auth (email/password, Google, GitHub)
8
+ * 4. synap.live redirects to localhost callback with session token
9
+ * 5. CLI stores token in ~/.synap/credentials.json
10
+ */
11
+ import http from "node:http";
12
+ import { execSync } from "node:child_process";
13
+ import fs from "node:fs";
14
+ import path from "node:path";
15
+ import os from "node:os";
16
+ const CP_URL = process.env.SYNAP_CP_URL || "https://api.synap.live";
17
+ const LANDING_URL = process.env.SYNAP_LANDING_URL || "https://synap.live";
18
+ const CREDENTIALS_DIR = path.join(os.homedir(), ".synap");
19
+ const CREDENTIALS_FILE = path.join(CREDENTIALS_DIR, "credentials.json");
20
+ // ─── Credential Storage ────────────────────────────────────────────────────
21
+ function ensureCredentialsDir() {
22
+ if (!fs.existsSync(CREDENTIALS_DIR)) {
23
+ fs.mkdirSync(CREDENTIALS_DIR, { recursive: true, mode: 0o700 });
24
+ }
25
+ }
26
+ function writeCredentials(creds) {
27
+ ensureCredentialsDir();
28
+ fs.writeFileSync(CREDENTIALS_FILE, JSON.stringify(creds, null, 2), {
29
+ mode: 0o600,
30
+ });
31
+ }
32
+ export function getStoredToken() {
33
+ try {
34
+ if (!fs.existsSync(CREDENTIALS_FILE))
35
+ return null;
36
+ const raw = fs.readFileSync(CREDENTIALS_FILE, "utf-8");
37
+ return JSON.parse(raw);
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ }
43
+ /** True if local expiry timestamp has passed (does NOT call the server). */
44
+ export function isTokenLocallyExpired(creds) {
45
+ return new Date(creds.expiresAt) < new Date();
46
+ }
47
+ export function logout() {
48
+ try {
49
+ if (fs.existsSync(CREDENTIALS_FILE)) {
50
+ fs.unlinkSync(CREDENTIALS_FILE);
51
+ }
52
+ }
53
+ catch {
54
+ // ignore
55
+ }
56
+ }
57
+ // ─── Session Validation ────────────────────────────────────────────────────
58
+ export async function isLoggedIn() {
59
+ const creds = getStoredToken();
60
+ if (!creds)
61
+ return { valid: false };
62
+ try {
63
+ const res = await fetch(`${CP_URL}/auth/me`, {
64
+ headers: { Authorization: `Bearer ${creds.token}` },
65
+ signal: AbortSignal.timeout(5000),
66
+ });
67
+ if (!res.ok) {
68
+ // Server explicitly rejects token — clean up
69
+ logout();
70
+ return { valid: false };
71
+ }
72
+ const data = (await res.json());
73
+ // Extend local expiry by 7 days from now — keeps the token alive as long
74
+ // as the server is still accepting it (avoids false "expired" deletions)
75
+ writeCredentials({
76
+ ...creds,
77
+ email: data.user.email,
78
+ userId: data.user.id,
79
+ expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
80
+ });
81
+ return { valid: true, email: data.user.email, userId: data.user.id };
82
+ }
83
+ catch {
84
+ // Network error — keep token, report as invalid for this call only
85
+ return { valid: false };
86
+ }
87
+ }
88
+ // ─── Token-based Login (headless / server) ─────────────────────────────────
89
+ /**
90
+ * Store a manually provided API token (Better Auth session token).
91
+ * Validates against the CP before saving.
92
+ *
93
+ * Usage: synap login --token <token>
94
+ * Get a token from: https://synap.live/account/tokens
95
+ */
96
+ export async function loginWithToken(token) {
97
+ const res = await fetch(`${CP_URL}/auth/me`, {
98
+ headers: { Authorization: `Bearer ${token}` },
99
+ signal: AbortSignal.timeout(8000),
100
+ });
101
+ if (!res.ok)
102
+ return null;
103
+ const data = (await res.json());
104
+ const creds = {
105
+ token,
106
+ email: data.user.email,
107
+ userId: data.user.id,
108
+ expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
109
+ };
110
+ writeCredentials(creds);
111
+ return creds;
112
+ }
113
+ // ─── Browser Login Flow ────────────────────────────────────────────────────
114
+ function openBrowser(url) {
115
+ try {
116
+ switch (process.platform) {
117
+ case "darwin":
118
+ execSync(`open "${url}"`);
119
+ break;
120
+ case "linux":
121
+ execSync(`xdg-open "${url}"`);
122
+ break;
123
+ case "win32":
124
+ execSync(`start "" "${url}"`);
125
+ break;
126
+ default:
127
+ // Can't open browser — caller handles fallback
128
+ throw new Error("Unsupported platform");
129
+ }
130
+ }
131
+ catch {
132
+ throw new Error("Could not open browser");
133
+ }
134
+ }
135
+ export async function login() {
136
+ return new Promise((resolve) => {
137
+ const server = http.createServer((req, res) => {
138
+ const url = new URL(req.url ?? "/", `http://localhost`);
139
+ if (url.pathname === "/callback") {
140
+ const token = url.searchParams.get("token");
141
+ const email = url.searchParams.get("email");
142
+ const userId = url.searchParams.get("userId");
143
+ const expiresAt = url.searchParams.get("expiresAt");
144
+ if (token && email && userId) {
145
+ const creds = {
146
+ token,
147
+ email,
148
+ userId,
149
+ expiresAt: expiresAt ||
150
+ new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
151
+ };
152
+ writeCredentials(creds);
153
+ // Send success page
154
+ res.writeHead(200, { "Content-Type": "text/html" });
155
+ res.end(`<!DOCTYPE html>
156
+ <html>
157
+ <head><title>Synap CLI</title></head>
158
+ <body style="font-family: system-ui, sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; background: #0a0a0a; color: #e5e5e5;">
159
+ <div style="text-align: center;">
160
+ <h1 style="font-size: 24px; margin-bottom: 8px;">Authenticated</h1>
161
+ <p style="color: #888;">You can close this window and return to the terminal.</p>
162
+ </div>
163
+ </body>
164
+ </html>`);
165
+ cleanup();
166
+ resolve(creds);
167
+ }
168
+ else {
169
+ res.writeHead(400, { "Content-Type": "text/html" });
170
+ res.end(`<!DOCTYPE html>
171
+ <html>
172
+ <head><title>Synap CLI</title></head>
173
+ <body style="font-family: system-ui, sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; background: #0a0a0a; color: #e5e5e5;">
174
+ <div style="text-align: center;">
175
+ <h1 style="font-size: 24px; color: #ef4444; margin-bottom: 8px;">Authentication Failed</h1>
176
+ <p style="color: #888;">Missing token. Please try again.</p>
177
+ </div>
178
+ </body>
179
+ </html>`);
180
+ }
181
+ }
182
+ else {
183
+ res.writeHead(404);
184
+ res.end();
185
+ }
186
+ });
187
+ // Listen on random port
188
+ server.listen(0, "127.0.0.1", () => {
189
+ const addr = server.address();
190
+ if (!addr || typeof addr === "string") {
191
+ cleanup();
192
+ resolve(null);
193
+ return;
194
+ }
195
+ const port = addr.port;
196
+ const callbackUrl = `http://localhost:${port}/callback`;
197
+ const loginUrl = `${LANDING_URL}/cli?callback=${encodeURIComponent(callbackUrl)}`;
198
+ try {
199
+ openBrowser(loginUrl);
200
+ }
201
+ catch {
202
+ // Browser didn't open — show manual URL
203
+ console.log(`\n Open this URL in your browser:\n`);
204
+ console.log(` ${loginUrl}\n`);
205
+ }
206
+ });
207
+ // Timeout after 120 seconds
208
+ const timeout = setTimeout(() => {
209
+ cleanup();
210
+ resolve(null);
211
+ }, 120_000);
212
+ function cleanup() {
213
+ clearTimeout(timeout);
214
+ try {
215
+ server.close();
216
+ }
217
+ catch {
218
+ // ignore
219
+ }
220
+ }
221
+ });
222
+ }
223
+ export async function waitForPodCallback(timeoutMs = 300_000 // 5-minute window
224
+ ) {
225
+ return new Promise((resolve) => {
226
+ const server = http.createServer((req, res) => {
227
+ const url = new URL(req.url ?? "/", `http://localhost`);
228
+ if (url.pathname === "/callback") {
229
+ const podUrl = url.searchParams.get("podUrl");
230
+ const workspaceId = url.searchParams.get("workspaceId") ?? undefined;
231
+ res.writeHead(200, { "Content-Type": "text/html" });
232
+ res.end(`<!DOCTYPE html>
233
+ <html>
234
+ <head><title>Synap CLI</title></head>
235
+ <body style="font-family: system-ui, sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; background: #0a0a0a; color: #e5e5e5;">
236
+ <div style="text-align: center;">
237
+ <h1 style="font-size: 24px; margin-bottom: 8px;">Pod connected</h1>
238
+ <p style="color: #888;">You can close this window and return to the terminal.</p>
239
+ </div>
240
+ </body>
241
+ </html>`);
242
+ cleanup();
243
+ if (podUrl) {
244
+ resolve({ podUrl, workspaceId });
245
+ }
246
+ else {
247
+ resolve(null);
248
+ }
249
+ }
250
+ else {
251
+ res.writeHead(404);
252
+ res.end();
253
+ }
254
+ });
255
+ server.listen(0, "127.0.0.1", () => {
256
+ const addr = server.address();
257
+ if (!addr || typeof addr === "string") {
258
+ cleanup();
259
+ resolve(null);
260
+ return;
261
+ }
262
+ const port = addr.port;
263
+ const callbackUrl = `http://localhost:${port}/callback`;
264
+ const provisionUrl = `${LANDING_URL}/account/pod/provision?cli_callback=${encodeURIComponent(callbackUrl)}`;
265
+ try {
266
+ openBrowser(provisionUrl);
267
+ }
268
+ catch {
269
+ console.log(`\n Open this URL in your browser to provision your pod:\n`);
270
+ console.log(` ${provisionUrl}\n`);
271
+ }
272
+ });
273
+ const timeout = setTimeout(() => {
274
+ cleanup();
275
+ resolve(null);
276
+ }, timeoutMs);
277
+ function cleanup() {
278
+ clearTimeout(timeout);
279
+ try {
280
+ server.close();
281
+ }
282
+ catch {
283
+ // ignore
284
+ }
285
+ }
286
+ });
287
+ }
288
+ // ─── CP API Helpers ────────────────────────────────────────────────────────
289
+ export function getCpUrl() {
290
+ return CP_URL;
291
+ }
292
+ export async function listPods(token) {
293
+ const res = await fetch(`${CP_URL}/pods`, {
294
+ headers: { Authorization: `Bearer ${token}` },
295
+ signal: AbortSignal.timeout(10000),
296
+ });
297
+ if (!res.ok) {
298
+ throw new Error(`Failed to list pods (HTTP ${res.status})`);
299
+ }
300
+ const data = (await res.json());
301
+ // Only show active/provisioning pods — not deleted/archived
302
+ return (data.pods ?? []).filter((p) => p.status === "active" || p.status === "provisioning" || p.status === "syncing_intelligence");
303
+ }
304
+ /**
305
+ * Get the remote OpenClaw provisioning status from the CP.
306
+ * Returns null if not provisioned or on network error.
307
+ */
308
+ export async function getOpenClawRemoteStatus(cpToken, podId) {
309
+ try {
310
+ const res = await fetch(`${getCpUrl()}/openclaw/status?podId=${encodeURIComponent(podId)}`, {
311
+ headers: { Authorization: `Bearer ${cpToken}` },
312
+ signal: AbortSignal.timeout(8000),
313
+ });
314
+ if (!res.ok)
315
+ return null;
316
+ return (await res.json());
317
+ }
318
+ catch {
319
+ return null;
320
+ }
321
+ }
322
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Security hardening checks and fixes for OpenClaw.
3
+ * Based on CVE research and official OpenClaw security docs.
4
+ */
5
+ export interface SecurityCheck {
6
+ id: string;
7
+ name: string;
8
+ severity: "critical" | "high" | "medium" | "low";
9
+ passed: boolean;
10
+ message: string;
11
+ fixable: boolean;
12
+ fix?: () => void;
13
+ }
14
+ /**
15
+ * Run all 9 security checks against the OpenClaw configuration.
16
+ */
17
+ export declare function runSecurityChecks(version?: string): SecurityCheck[];
18
+ export declare function computeScore(checks: SecurityCheck[]): string;
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Security hardening checks and fixes for OpenClaw.
3
+ * Based on CVE research and official OpenClaw security docs.
4
+ */
5
+ import { chmodSync } from "fs";
6
+ import { homedir } from "os";
7
+ import { join } from "path";
8
+ import { readOpenClawConfig, writeOpenClawConfig, getConfigValue, setConfigValue, getConfigPermissions, } from "./openclaw.js";
9
+ /**
10
+ * Run all 9 security checks against the OpenClaw configuration.
11
+ */
12
+ export function runSecurityChecks(version) {
13
+ const config = readOpenClawConfig();
14
+ const checks = [];
15
+ // 1. Gateway bound to loopback
16
+ const bind = config ? getConfigValue(config, "gateway.bind") : undefined;
17
+ checks.push({
18
+ id: "gateway-bind",
19
+ name: "Gateway bound to loopback",
20
+ severity: "critical",
21
+ passed: !bind || bind === "loopback" || bind === "127.0.0.1",
22
+ message: !bind || bind === "loopback" || bind === "127.0.0.1"
23
+ ? "Gateway only accepts local connections"
24
+ : `Gateway bound to "${bind}" — exposed to network`,
25
+ fixable: true,
26
+ fix: config
27
+ ? () => {
28
+ setConfigValue(config, "gateway.bind", "loopback");
29
+ writeOpenClawConfig(config);
30
+ }
31
+ : undefined,
32
+ });
33
+ // 2. Token auth enabled
34
+ const token = config ? getConfigValue(config, "gateway.token") : undefined;
35
+ checks.push({
36
+ id: "gateway-token",
37
+ name: "Token authentication enabled",
38
+ severity: "critical",
39
+ passed: !!token,
40
+ message: token
41
+ ? "Gateway requires token for access"
42
+ : "No gateway token set — anyone can connect",
43
+ fixable: false, // user must set their own token
44
+ });
45
+ // 3. OpenClaw version >= 2026.3.12
46
+ const minVersion = "2026.3.12";
47
+ const versionOk = version ? compareVersions(version, minVersion) >= 0 : true;
48
+ checks.push({
49
+ id: "version",
50
+ name: `OpenClaw version >= ${minVersion}`,
51
+ severity: "critical",
52
+ passed: versionOk,
53
+ message: version
54
+ ? versionOk
55
+ ? `Running v${version}`
56
+ : `Running v${version} — has 9.9 CVSS vulnerability (CVE-2026-24763)`
57
+ : "Could not detect version",
58
+ fixable: false,
59
+ });
60
+ // 4. No plaintext credentials in config
61
+ const hasPlaintext = config
62
+ ? containsPlaintextCredentials(JSON.stringify(config))
63
+ : false;
64
+ checks.push({
65
+ id: "plaintext-creds",
66
+ name: "No plaintext credentials in config",
67
+ severity: "high",
68
+ passed: !hasPlaintext,
69
+ message: hasPlaintext
70
+ ? "Config contains potential plaintext credentials"
71
+ : "No obvious plaintext credentials found",
72
+ fixable: false,
73
+ });
74
+ // 5. File permissions on ~/.openclaw
75
+ const perms = getConfigPermissions();
76
+ checks.push({
77
+ id: "file-permissions",
78
+ name: "Config directory permissions",
79
+ severity: "high",
80
+ passed: perms.safe,
81
+ message: perms.safe
82
+ ? `~/.openclaw mode ${perms.mode} (owner-only)`
83
+ : `~/.openclaw mode ${perms.mode} — readable by others`,
84
+ fixable: true,
85
+ fix: () => {
86
+ chmodSync(join(homedir(), ".openclaw"), 0o700);
87
+ },
88
+ });
89
+ // 6. WebSocket origin validation
90
+ const wsOrigin = config
91
+ ? getConfigValue(config, "gateway.websocket.validateOrigin")
92
+ : undefined;
93
+ checks.push({
94
+ id: "ws-origin",
95
+ name: "WebSocket origin validation",
96
+ severity: "medium",
97
+ passed: wsOrigin !== false,
98
+ message: wsOrigin === false
99
+ ? "WebSocket origin validation disabled"
100
+ : "WebSocket origin validation active",
101
+ fixable: true,
102
+ fix: config
103
+ ? () => {
104
+ setConfigValue(config, "gateway.websocket.validateOrigin", true);
105
+ writeOpenClawConfig(config);
106
+ }
107
+ : undefined,
108
+ });
109
+ // 7. Dangerous skill scanner
110
+ const scanner = config
111
+ ? getConfigValue(config, "skills.dangerousCodeScanner")
112
+ : undefined;
113
+ checks.push({
114
+ id: "skill-scanner",
115
+ name: "Dangerous skill scanner enabled",
116
+ severity: "medium",
117
+ passed: scanner !== false,
118
+ message: scanner === false
119
+ ? "Skill scanner disabled — malicious skills can run unchecked"
120
+ : "Skill scanner active",
121
+ fixable: true,
122
+ fix: config
123
+ ? () => {
124
+ setConfigValue(config, "skills.dangerousCodeScanner", true);
125
+ writeOpenClawConfig(config);
126
+ }
127
+ : undefined,
128
+ });
129
+ // 8. Workspace-only filesystem
130
+ const fsAccess = config
131
+ ? getConfigValue(config, "tools.filesystem.scope")
132
+ : undefined;
133
+ checks.push({
134
+ id: "fs-scope",
135
+ name: "Workspace-only filesystem access",
136
+ severity: "medium",
137
+ passed: fsAccess === "workspace" || fsAccess === undefined,
138
+ message: fsAccess && fsAccess !== "workspace"
139
+ ? `Filesystem scope: "${fsAccess}" — broader than needed`
140
+ : "Filesystem access scoped to workspace",
141
+ fixable: true,
142
+ fix: config
143
+ ? () => {
144
+ setConfigValue(config, "tools.filesystem.scope", "workspace");
145
+ writeOpenClawConfig(config);
146
+ }
147
+ : undefined,
148
+ });
149
+ // 9. Exec approval gates
150
+ const execApproval = config
151
+ ? getConfigValue(config, "tools.exec.requireApproval")
152
+ : undefined;
153
+ checks.push({
154
+ id: "exec-approval",
155
+ name: "Exec approval gates enabled",
156
+ severity: "low",
157
+ passed: execApproval !== false,
158
+ message: execApproval === false
159
+ ? "Shell commands execute without approval"
160
+ : "Exec commands require approval",
161
+ fixable: true,
162
+ fix: config
163
+ ? () => {
164
+ setConfigValue(config, "tools.exec.requireApproval", true);
165
+ writeOpenClawConfig(config);
166
+ }
167
+ : undefined,
168
+ });
169
+ return checks;
170
+ }
171
+ export function computeScore(checks) {
172
+ const criticalFail = checks.some((c) => !c.passed && c.severity === "critical");
173
+ const highFail = checks.some((c) => !c.passed && c.severity === "high");
174
+ const medFail = checks.some((c) => !c.passed && c.severity === "medium");
175
+ const failCount = checks.filter((c) => !c.passed).length;
176
+ if (criticalFail)
177
+ return "D";
178
+ if (highFail)
179
+ return "C";
180
+ if (medFail || failCount > 1)
181
+ return "B";
182
+ return "A";
183
+ }
184
+ function compareVersions(a, b) {
185
+ const pa = a.split(".").map(Number);
186
+ const pb = b.split(".").map(Number);
187
+ for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
188
+ const na = pa[i] ?? 0;
189
+ const nb = pb[i] ?? 0;
190
+ if (na !== nb)
191
+ return na - nb;
192
+ }
193
+ return 0;
194
+ }
195
+ function containsPlaintextCredentials(text) {
196
+ const patterns = [
197
+ /sk-[a-zA-Z0-9]{20,}/,
198
+ /sk_live_[a-zA-Z0-9]{20,}/,
199
+ /password["']\s*:\s*["'][^"']+["']/i,
200
+ ];
201
+ return patterns.some((p) => p.test(text));
202
+ }
203
+ //# sourceMappingURL=hardening.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hardening.js","sourceRoot":"","sources":["../../src/lib/hardening.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * OpenClaw detection and configuration utilities.
3
+ * Reads/writes OpenClaw config without modifying unrelated settings.
4
+ */
5
+ export interface OpenClawInfo {
6
+ found: boolean;
7
+ version?: string;
8
+ configPath?: string;
9
+ config?: Record<string, unknown>;
10
+ gatewayRunning?: boolean;
11
+ gatewayPort?: number;
12
+ skillsDir?: string;
13
+ }
14
+ export declare function detectOpenClaw(): OpenClawInfo;
15
+ export declare function readOpenClawConfig(): Record<string, unknown> | null;
16
+ export declare function writeOpenClawConfig(config: Record<string, unknown>): void;
17
+ export declare function getConfigPermissions(): {
18
+ mode: string;
19
+ safe: boolean;
20
+ };
21
+ /**
22
+ * Get a nested config value safely.
23
+ */
24
+ export declare function getConfigValue(config: Record<string, unknown>, path: string): unknown;
25
+ /**
26
+ * Set a nested config value.
27
+ */
28
+ export declare function setConfigValue(config: Record<string, unknown>, path: string, value: unknown): void;