claw-dashboard 2.1.1 → 2.2.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/CHANGELOG.md +29 -1
- package/docs/API.md +1 -2
- package/index.js +31 -41
- package/package.json +22 -12
- package/src/auto-save.js +11 -5
- package/src/cli/export-snapshot.js +3 -1
- package/src/cli/import-snapshot.js +3 -1
- package/src/config.js +9 -15
- package/src/errors.js +0 -9
- package/src/security.js +6 -2
- package/src/snapshot.js +73 -26
- package/src/web-server.js +7 -10
- package/.c8rc.json +0 -38
- package/.dockerignore +0 -68
- package/.github/dependabot.yml +0 -45
- package/.github/pull_request_template.md +0 -39
- package/.github/workflows/ci.yml +0 -147
- package/.github/workflows/release.yml +0 -40
- package/.github/workflows/security.yml +0 -84
- package/.husky/pre-commit +0 -1
- package/.planning/codebase/ARCHITECTURE.md +0 -206
- package/.planning/codebase/INTEGRATIONS.md +0 -150
- package/.planning/codebase/STACK.md +0 -122
- package/.planning/codebase/STRUCTURE.md +0 -201
- package/CONTRIBUTING.md +0 -378
- package/Dockerfile +0 -54
- package/FEATURES.md +0 -307
- package/TODO.md +0 -28
- package/ai.openclaw.dashboard.plist +0 -35
- package/build-cjs.js +0 -127
- package/cjs-shim.js +0 -13
- package/dist/clawdash +0 -1729
- package/dist/clawdash.meta.json +0 -2236
- package/dist/widgets.cjs +0 -6511
- package/docker-compose.yml +0 -67
- package/esbuild.config.js +0 -158
- package/eslint.config.js +0 -56
- package/examples/plugins/README.md +0 -122
- package/examples/plugins/api-status/index.js +0 -294
- package/examples/plugins/api-status/plugin.json +0 -19
- package/examples/plugins/hello-world/index.js +0 -104
- package/examples/plugins/hello-world/plugin.json +0 -15
- package/examples/plugins/system-metrics-chart/index.js +0 -339
- package/examples/plugins/system-metrics-chart/plugin.json +0 -18
- package/examples/plugins/weather-widget/index.js +0 -136
- package/examples/plugins/weather-widget/plugin.json +0 -19
- package/index.cjs +0 -23005
- package/jest.config.js +0 -11
- package/scripts/release.js +0 -595
- package/src/database.js +0 -734
- package/tests/alerts.test.js +0 -437
- package/tests/auto-save.test.js +0 -529
- package/tests/cache.test.js +0 -317
- package/tests/cli.test.js +0 -351
- package/tests/command-palette.test.js +0 -320
- package/tests/config-processor.test.js +0 -452
- package/tests/config-validator.test.js +0 -710
- package/tests/config-watcher.test.js +0 -594
- package/tests/config.test.js +0 -755
- package/tests/database.test.js +0 -438
- package/tests/errors.test.js +0 -189
- package/tests/example-plugins.test.js +0 -624
- package/tests/integration.test.js +0 -1321
- package/tests/loading-states.test.js +0 -300
- package/tests/manifest-validation-on-load.test.js +0 -671
- package/tests/performance-monitor.test.js +0 -190
- package/tests/plugin-api-rate-limit.test.js +0 -302
- package/tests/plugin-errors.test.js +0 -311
- package/tests/plugin-lifecycle-e2e.test.js +0 -1036
- package/tests/plugin-reload.test.js +0 -764
- package/tests/rate-limiter.test.js +0 -539
- package/tests/removed-dependencies.test.js +0 -74
- package/tests/retry.test.js +0 -308
- package/tests/security.test.js +0 -411
- package/tests/settings-modal.test.js +0 -226
- package/tests/theme-selector.test.js +0 -57
- package/tests/utils.js +0 -242
- package/tests/utils.test.js +0 -317
- package/tests/validate-plugin-cli.test.js +0 -359
- package/tests/validation.test.js +0 -837
- package/tests/web-server.test.js +0 -646
- package/tests/widget-arrange-mode.test.js +0 -183
- package/tests/widget-config-hot-reload.test.js +0 -465
- package/tests/widget-dependency.test.js +0 -591
- package/tests/widget-error-boundary.test.js +0 -749
- package/tests/widget-error-isolation.test.js +0 -469
- package/tests/widget-integration.test.js +0 -1147
- package/tests/widget-refresh-intervals.test.js +0 -284
- package/tests/worker-pool.test.js +0 -522
package/src/snapshot.js
CHANGED
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
import fs from 'fs';
|
|
8
8
|
import os from 'os';
|
|
9
|
-
import
|
|
9
|
+
import path from 'path';
|
|
10
10
|
import { PATHS, DEFAULT_SETTINGS, DASHBOARD_VERSION } from './config.js';
|
|
11
11
|
import logger from './logger.js';
|
|
12
|
+
import { validatePluginPath } from './security.js';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Snapshot schema version for compatibility checking
|
|
@@ -186,21 +187,34 @@ export function mergeSnapshotSettings(existingSettings, snapshotSettings) {
|
|
|
186
187
|
*/
|
|
187
188
|
export function exportSnapshotToFile(snapshot, filePath) {
|
|
188
189
|
try {
|
|
189
|
-
|
|
190
|
+
// Route through validator (allowAbsolute for documented arbitrary user paths e.g. ~/my-layout.json or /tmp/snap.json;
|
|
191
|
+
// traversal/characters/hidden still apply: hidden dirs only if whitelisted (see the allowedHidden list and hidden check in security.js: only .openclaw etc allowed; e.g. ~/.config/.secret/ or /tmp/.foo/ rejected even with abs).
|
|
192
|
+
// no allowedDirs to permit user-chosen locations (delete uses internal-dir restriction).
|
|
193
|
+
const validation = validatePluginPath(filePath, {
|
|
194
|
+
allowAbsolute: true,
|
|
195
|
+
mustExist: false,
|
|
196
|
+
expectedType: null,
|
|
197
|
+
});
|
|
198
|
+
if (!validation.valid) {
|
|
199
|
+
return { success: false, error: validation.error || 'Invalid snapshot path' };
|
|
200
|
+
}
|
|
201
|
+
const safePath = validation.path || filePath;
|
|
202
|
+
|
|
203
|
+
const dir = path.dirname(safePath);
|
|
190
204
|
if (dir && !fs.existsSync(dir)) {
|
|
191
205
|
fs.mkdirSync(dir, { recursive: true });
|
|
192
206
|
}
|
|
193
207
|
|
|
194
|
-
fs.writeFileSync(
|
|
208
|
+
fs.writeFileSync(safePath, JSON.stringify(snapshot, null, 2));
|
|
195
209
|
|
|
196
210
|
// Set secure permissions (owner read/write only)
|
|
197
211
|
try {
|
|
198
|
-
fs.chmodSync(
|
|
212
|
+
fs.chmodSync(safePath, 0o600);
|
|
199
213
|
} catch (permErr) {
|
|
200
214
|
logger.warn(`Could not set permissions on snapshot: ${permErr.message}`);
|
|
201
215
|
}
|
|
202
216
|
|
|
203
|
-
return { success: true, path:
|
|
217
|
+
return { success: true, path: safePath };
|
|
204
218
|
} catch (err) {
|
|
205
219
|
return { success: false, error: err.message };
|
|
206
220
|
}
|
|
@@ -213,16 +227,29 @@ export function exportSnapshotToFile(snapshot, filePath) {
|
|
|
213
227
|
*/
|
|
214
228
|
export function importSnapshotFromFile(filePath) {
|
|
215
229
|
try {
|
|
216
|
-
|
|
217
|
-
|
|
230
|
+
// Route through validator (allowAbsolute:true for arbitrary user-specified import paths per CLI/TUI/docs;
|
|
231
|
+
// traversal/character/hidden checks still enforced; omit allowedDirs to permit outside snap dir).
|
|
232
|
+
// Exact rule (shared w/ plugins): abs paths ok but dot-dir components limited to whitelisted ('.openclaw' etc per the allowedHidden list in security.js); other dots like .secret or .foo under ~ or /tmp are rejected (tests cover intended .openclaw + non-dot).
|
|
233
|
+
const validation = validatePluginPath(filePath, {
|
|
234
|
+
allowAbsolute: true,
|
|
235
|
+
mustExist: false,
|
|
236
|
+
expectedType: null,
|
|
237
|
+
});
|
|
238
|
+
if (!validation.valid) {
|
|
239
|
+
return { success: false, error: validation.error || 'Invalid snapshot path' };
|
|
218
240
|
}
|
|
241
|
+
const safePath = validation.path || filePath;
|
|
219
242
|
|
|
220
|
-
|
|
243
|
+
if (!fs.existsSync(safePath)) {
|
|
244
|
+
return { success: false, error: `File not found: ${safePath}` };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const data = fs.readFileSync(safePath, 'utf8');
|
|
221
248
|
const snapshot = JSON.parse(data);
|
|
222
249
|
|
|
223
|
-
const
|
|
224
|
-
if (!
|
|
225
|
-
return { success: false, error:
|
|
250
|
+
const schemaValidation = validateSnapshot(snapshot);
|
|
251
|
+
if (!schemaValidation.valid) {
|
|
252
|
+
return { success: false, error: schemaValidation.error };
|
|
226
253
|
}
|
|
227
254
|
|
|
228
255
|
return { success: true, snapshot };
|
|
@@ -250,7 +277,7 @@ export function generateSnapshotFilename(name) {
|
|
|
250
277
|
* @returns {string} Path to snapshots directory
|
|
251
278
|
*/
|
|
252
279
|
export function getSnapshotsDirectory() {
|
|
253
|
-
return join(PATHS.OPENCLAW_DIR, 'snapshots');
|
|
280
|
+
return path.join(PATHS.OPENCLAW_DIR, 'snapshots');
|
|
254
281
|
}
|
|
255
282
|
|
|
256
283
|
/**
|
|
@@ -267,14 +294,14 @@ export function listSnapshots() {
|
|
|
267
294
|
const files = fs.readdirSync(dir)
|
|
268
295
|
.filter(f => f.endsWith('.json'))
|
|
269
296
|
.map(f => {
|
|
270
|
-
const
|
|
297
|
+
const filePath = path.join(dir, f);
|
|
271
298
|
try {
|
|
272
|
-
const data = fs.readFileSync(
|
|
299
|
+
const data = fs.readFileSync(filePath, 'utf8');
|
|
273
300
|
const snapshot = JSON.parse(data);
|
|
274
|
-
const stats = fs.statSync(
|
|
301
|
+
const stats = fs.statSync(filePath);
|
|
275
302
|
return {
|
|
276
303
|
filename: f,
|
|
277
|
-
path,
|
|
304
|
+
path: filePath,
|
|
278
305
|
name: snapshot.name || 'Unnamed',
|
|
279
306
|
description: snapshot.description || '',
|
|
280
307
|
createdAt: snapshot.createdAt || stats.mtime.toISOString(),
|
|
@@ -303,22 +330,42 @@ export function listSnapshots() {
|
|
|
303
330
|
*/
|
|
304
331
|
export function deleteSnapshot(filename) {
|
|
305
332
|
const dir = getSnapshotsDirectory();
|
|
306
|
-
const filePath = join(dir, filename);
|
|
307
|
-
|
|
308
|
-
// Security:
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
333
|
+
const filePath = path.join(dir, filename);
|
|
334
|
+
|
|
335
|
+
// Security: route through validator + proper realpath + trailing sep (fixes pre-existing broken .safe + startsWith).
|
|
336
|
+
// Mirrors validatePluginPath + validateFilePath patterns used elsewhere.
|
|
337
|
+
// For internal snapshots only (always under ~/.openclaw/snapshots); abs user paths for export/import use allowAbsolute no allowedDirs (see rules in exportSnapshotToFile/importSnapshotFromFile comments + security hidden whitelist).
|
|
338
|
+
const validation = validatePluginPath(filePath, {
|
|
339
|
+
allowedDirs: [dir],
|
|
340
|
+
allowAbsolute: true,
|
|
341
|
+
mustExist: false,
|
|
342
|
+
expectedType: null,
|
|
343
|
+
});
|
|
344
|
+
if (!validation.valid) {
|
|
345
|
+
return { success: false, error: validation.error || 'Invalid snapshot path' };
|
|
346
|
+
}
|
|
347
|
+
const safePath = validation.path || filePath;
|
|
312
348
|
|
|
313
|
-
|
|
314
|
-
|
|
349
|
+
let unlinkPath = safePath;
|
|
350
|
+
try {
|
|
351
|
+
const resolvedPath = fs.realpathSync(safePath);
|
|
352
|
+
const resolvedDir = fs.realpathSync(dir);
|
|
353
|
+
if (!resolvedPath.startsWith(resolvedDir + path.sep) && resolvedPath !== resolvedDir) {
|
|
354
|
+
return { success: false, error: 'Invalid snapshot path' };
|
|
355
|
+
}
|
|
356
|
+
unlinkPath = resolvedPath;
|
|
357
|
+
} catch (realErr) {
|
|
358
|
+
// If file doesn't exist yet, proceed to not-found (or let later check handle)
|
|
359
|
+
if (!fs.existsSync(safePath)) {
|
|
360
|
+
return { success: false, error: 'Snapshot not found' };
|
|
361
|
+
}
|
|
315
362
|
}
|
|
316
363
|
|
|
317
364
|
try {
|
|
318
|
-
if (!fs.existsSync(
|
|
365
|
+
if (!fs.existsSync(unlinkPath)) {
|
|
319
366
|
return { success: false, error: 'Snapshot not found' };
|
|
320
367
|
}
|
|
321
|
-
fs.unlinkSync(
|
|
368
|
+
fs.unlinkSync(unlinkPath);
|
|
322
369
|
return { success: true };
|
|
323
370
|
} catch (err) {
|
|
324
371
|
return { success: false, error: err.message };
|
package/src/web-server.js
CHANGED
|
@@ -298,16 +298,6 @@ class CorsManager {
|
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
300
|
|
|
301
|
-
/**
|
|
302
|
-
* Create CORS headers for HTTP responses (legacy function for backward compatibility)
|
|
303
|
-
* @returns {Object} CORS headers
|
|
304
|
-
* @deprecated Use CorsManager instead
|
|
305
|
-
*/
|
|
306
|
-
function getCorsHeaders() {
|
|
307
|
-
const corsManager = new CorsManager();
|
|
308
|
-
return corsManager.getHeaders({ headers: {} });
|
|
309
|
-
}
|
|
310
|
-
|
|
311
301
|
/**
|
|
312
302
|
* Send JSON response
|
|
313
303
|
* @param {http.ServerResponse} res - HTTP response
|
|
@@ -334,6 +324,13 @@ function sendError(res, statusCode, message, headers = {}, extra = {}) {
|
|
|
334
324
|
|
|
335
325
|
/**
|
|
336
326
|
* Web Server class for exposing dashboard data via HTTP API
|
|
327
|
+
*
|
|
328
|
+
* SECURITY NOTE (pre-existing defaults, untouched by lean trim to preserve --web UX):
|
|
329
|
+
* - Binds to 0.0.0.0 + CORS * + auth disabled by default (see config WEB.HOST/AUTH/CORS).
|
|
330
|
+
* - Intended for trusted/remote/localhost use or with explicit --web-host + auth keys enabled.
|
|
331
|
+
* - Health is intentionally public; other endpoints (sessions with tokens, logs, metrics) are sensitive.
|
|
332
|
+
* - Recommend: bind localhost, enable auth, restrict CORS origins in production.
|
|
333
|
+
* No changes here as trim focused on deadcode/lean (db/CJS/legacy); no new surface added.
|
|
337
334
|
*/
|
|
338
335
|
export class WebServer {
|
|
339
336
|
constructor(options = {}) {
|
package/.c8rc.json
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"all": true,
|
|
3
|
-
"include": [
|
|
4
|
-
"index.js",
|
|
5
|
-
"src/**/*.js"
|
|
6
|
-
],
|
|
7
|
-
"exclude": [
|
|
8
|
-
"node_modules/**",
|
|
9
|
-
"coverage/**",
|
|
10
|
-
"tests/**",
|
|
11
|
-
"dist/**",
|
|
12
|
-
"scripts/**",
|
|
13
|
-
"examples/**",
|
|
14
|
-
"src/workers/**",
|
|
15
|
-
"**/*.test.js",
|
|
16
|
-
"**/*.config.js"
|
|
17
|
-
],
|
|
18
|
-
"reporter": [
|
|
19
|
-
"text",
|
|
20
|
-
"text-summary",
|
|
21
|
-
"lcov",
|
|
22
|
-
"html",
|
|
23
|
-
"json-summary"
|
|
24
|
-
],
|
|
25
|
-
"check-coverage": true,
|
|
26
|
-
"statements": 35,
|
|
27
|
-
"branches": 30,
|
|
28
|
-
"functions": 20,
|
|
29
|
-
"lines": 35,
|
|
30
|
-
"watermarks": {
|
|
31
|
-
"statements": [70, 90],
|
|
32
|
-
"branches": [65, 85],
|
|
33
|
-
"functions": [70, 90],
|
|
34
|
-
"lines": [70, 90]
|
|
35
|
-
},
|
|
36
|
-
"report-dir": "./coverage",
|
|
37
|
-
"temp-dir": "./coverage/.tmp"
|
|
38
|
-
}
|
package/.dockerignore
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
# Dependencies
|
|
2
|
-
node_modules
|
|
3
|
-
npm-debug.log*
|
|
4
|
-
yarn-debug.log*
|
|
5
|
-
yarn-error.log*
|
|
6
|
-
|
|
7
|
-
# Testing
|
|
8
|
-
tests/
|
|
9
|
-
coverage/
|
|
10
|
-
*.test.js
|
|
11
|
-
*.spec.js
|
|
12
|
-
jest.config.js
|
|
13
|
-
|
|
14
|
-
# Documentation
|
|
15
|
-
docs/
|
|
16
|
-
*.md
|
|
17
|
-
CONTRIBUTING.md
|
|
18
|
-
CHANGELOG.md
|
|
19
|
-
README.md
|
|
20
|
-
TODO.md
|
|
21
|
-
|
|
22
|
-
# Git
|
|
23
|
-
.git
|
|
24
|
-
.gitignore
|
|
25
|
-
.gitattributes
|
|
26
|
-
|
|
27
|
-
# CI/CD
|
|
28
|
-
.github/
|
|
29
|
-
.travis.yml
|
|
30
|
-
.gitlab-ci.yml
|
|
31
|
-
|
|
32
|
-
# IDE
|
|
33
|
-
.vscode/
|
|
34
|
-
.idea/
|
|
35
|
-
*.swp
|
|
36
|
-
*.swo
|
|
37
|
-
*~
|
|
38
|
-
|
|
39
|
-
# OS
|
|
40
|
-
.DS_Store
|
|
41
|
-
Thumbs.db
|
|
42
|
-
|
|
43
|
-
# Logs
|
|
44
|
-
logs/
|
|
45
|
-
*.log
|
|
46
|
-
|
|
47
|
-
# Runtime data
|
|
48
|
-
pids/
|
|
49
|
-
*.pid
|
|
50
|
-
*.seed
|
|
51
|
-
*.pid.lock
|
|
52
|
-
|
|
53
|
-
# Optional npm cache directory
|
|
54
|
-
.npm
|
|
55
|
-
|
|
56
|
-
# Optional eslint cache
|
|
57
|
-
.eslintcache
|
|
58
|
-
|
|
59
|
-
# Build outputs
|
|
60
|
-
dist/
|
|
61
|
-
build/
|
|
62
|
-
|
|
63
|
-
# Worktrees
|
|
64
|
-
.worktrees/
|
|
65
|
-
|
|
66
|
-
# Installation scripts (not needed in container)
|
|
67
|
-
install.sh
|
|
68
|
-
start.sh
|
package/.github/dependabot.yml
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
version: 2
|
|
2
|
-
updates:
|
|
3
|
-
- package-ecosystem: 'npm'
|
|
4
|
-
directory: '/'
|
|
5
|
-
schedule:
|
|
6
|
-
interval: 'weekly'
|
|
7
|
-
day: 'monday'
|
|
8
|
-
time: '09:00'
|
|
9
|
-
open-pull-requests-limit: 10
|
|
10
|
-
reviewers:
|
|
11
|
-
- 'spleck'
|
|
12
|
-
assignees:
|
|
13
|
-
- 'spleck'
|
|
14
|
-
commit-message:
|
|
15
|
-
prefix: 'chore(deps)'
|
|
16
|
-
include: 'scope'
|
|
17
|
-
labels:
|
|
18
|
-
- 'dependencies'
|
|
19
|
-
groups:
|
|
20
|
-
dev-dependencies:
|
|
21
|
-
patterns:
|
|
22
|
-
- '*'
|
|
23
|
-
exclude-patterns:
|
|
24
|
-
- 'blessed*'
|
|
25
|
-
- 'systeminformation'
|
|
26
|
-
production-dependencies:
|
|
27
|
-
patterns:
|
|
28
|
-
- 'blessed*'
|
|
29
|
-
- 'systeminformation'
|
|
30
|
-
|
|
31
|
-
- package-ecosystem: 'github-actions'
|
|
32
|
-
directory: '/'
|
|
33
|
-
schedule:
|
|
34
|
-
interval: 'weekly'
|
|
35
|
-
day: 'monday'
|
|
36
|
-
time: '09:00'
|
|
37
|
-
open-pull-requests-limit: 5
|
|
38
|
-
reviewers:
|
|
39
|
-
- 'spleck'
|
|
40
|
-
commit-message:
|
|
41
|
-
prefix: 'chore(actions)'
|
|
42
|
-
include: 'scope'
|
|
43
|
-
labels:
|
|
44
|
-
- 'dependencies'
|
|
45
|
-
- 'github-actions'
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
## Description
|
|
2
|
-
|
|
3
|
-
Brief description of the changes in this PR.
|
|
4
|
-
|
|
5
|
-
## Type of Change
|
|
6
|
-
|
|
7
|
-
- [ ] Bug fix (non-breaking change that fixes an issue)
|
|
8
|
-
- [ ] New feature (non-breaking change that adds functionality)
|
|
9
|
-
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
|
10
|
-
- [ ] Documentation update
|
|
11
|
-
- [ ] Refactoring (no functional changes)
|
|
12
|
-
- [ ] Performance improvement
|
|
13
|
-
- [ ] Test addition or improvement
|
|
14
|
-
|
|
15
|
-
## Checklist
|
|
16
|
-
|
|
17
|
-
- [ ] I have run `npm test` and all tests pass
|
|
18
|
-
- [ ] I have run `npm run build` and the build succeeds
|
|
19
|
-
- [ ] My code follows the project's style guidelines
|
|
20
|
-
- [ ] I have performed a self-review of my code
|
|
21
|
-
- [ ] I have commented my code, particularly in hard-to-understand areas
|
|
22
|
-
- [ ] I have made corresponding changes to the documentation
|
|
23
|
-
- [ ] My changes generate no new warnings
|
|
24
|
-
- [ ] I have added tests that prove my fix is effective or that my feature works
|
|
25
|
-
- [ ] New and existing unit tests pass locally with my changes
|
|
26
|
-
|
|
27
|
-
## Testing
|
|
28
|
-
|
|
29
|
-
Describe the tests you ran and how to reproduce them:
|
|
30
|
-
|
|
31
|
-
## Screenshots (if applicable)
|
|
32
|
-
|
|
33
|
-
## Related Issues
|
|
34
|
-
|
|
35
|
-
Fixes #(issue number)
|
|
36
|
-
|
|
37
|
-
## Additional Notes
|
|
38
|
-
|
|
39
|
-
Any other information that would be helpful for reviewers.
|
package/.github/workflows/ci.yml
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main, dev]
|
|
6
|
-
paths-ignore:
|
|
7
|
-
- '**.md'
|
|
8
|
-
- 'docs/**'
|
|
9
|
-
- '.github/*.md'
|
|
10
|
-
pull_request:
|
|
11
|
-
branches: [main]
|
|
12
|
-
paths-ignore:
|
|
13
|
-
- '**.md'
|
|
14
|
-
- 'docs/**'
|
|
15
|
-
- '.github/*.md'
|
|
16
|
-
|
|
17
|
-
jobs:
|
|
18
|
-
test:
|
|
19
|
-
name: Test (Node ${{ matrix.node-version }})
|
|
20
|
-
runs-on: ubuntu-latest
|
|
21
|
-
strategy:
|
|
22
|
-
matrix:
|
|
23
|
-
node-version: [18, 20, 22]
|
|
24
|
-
fail-fast: false
|
|
25
|
-
|
|
26
|
-
steps:
|
|
27
|
-
- name: Checkout code
|
|
28
|
-
uses: actions/checkout@v6
|
|
29
|
-
|
|
30
|
-
- name: Setup Node.js ${{ matrix.node-version }}
|
|
31
|
-
uses: actions/setup-node@v6
|
|
32
|
-
with:
|
|
33
|
-
node-version: ${{ matrix.node-version }}
|
|
34
|
-
cache: 'npm'
|
|
35
|
-
|
|
36
|
-
- name: Install dependencies
|
|
37
|
-
run: npm ci
|
|
38
|
-
|
|
39
|
-
- name: Run linter (ESLint checks)
|
|
40
|
-
run: npm run lint
|
|
41
|
-
|
|
42
|
-
- name: Run tests
|
|
43
|
-
run: npm test
|
|
44
|
-
|
|
45
|
-
- name: Run tests with coverage
|
|
46
|
-
if: matrix.node-version == 20
|
|
47
|
-
run: npm run test:coverage
|
|
48
|
-
|
|
49
|
-
- name: Upload coverage to Codecov
|
|
50
|
-
if: matrix.node-version == 20 && github.event_name != 'pull_request'
|
|
51
|
-
uses: codecov/codecov-action@v5
|
|
52
|
-
with:
|
|
53
|
-
files: ./coverage/lcov.info
|
|
54
|
-
fail_ci_if_error: false
|
|
55
|
-
verbose: true
|
|
56
|
-
env:
|
|
57
|
-
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
|
58
|
-
|
|
59
|
-
build:
|
|
60
|
-
name: Build
|
|
61
|
-
runs-on: ubuntu-latest
|
|
62
|
-
needs: test
|
|
63
|
-
|
|
64
|
-
steps:
|
|
65
|
-
- name: Checkout code
|
|
66
|
-
uses: actions/checkout@v6
|
|
67
|
-
|
|
68
|
-
- name: Setup Node.js
|
|
69
|
-
uses: actions/setup-node@v6
|
|
70
|
-
with:
|
|
71
|
-
node-version: 20
|
|
72
|
-
cache: 'npm'
|
|
73
|
-
|
|
74
|
-
- name: Install dependencies
|
|
75
|
-
run: npm ci
|
|
76
|
-
|
|
77
|
-
- name: Build distribution
|
|
78
|
-
run: npm run build
|
|
79
|
-
|
|
80
|
-
- name: Upload build artifacts
|
|
81
|
-
uses: actions/upload-artifact@v7
|
|
82
|
-
with:
|
|
83
|
-
name: dist
|
|
84
|
-
path: dist/
|
|
85
|
-
retention-days: 7
|
|
86
|
-
|
|
87
|
-
docker:
|
|
88
|
-
name: Docker Build
|
|
89
|
-
runs-on: ubuntu-latest
|
|
90
|
-
needs: test
|
|
91
|
-
if: github.event_name == 'pull_request'
|
|
92
|
-
|
|
93
|
-
steps:
|
|
94
|
-
- name: Checkout code
|
|
95
|
-
uses: actions/checkout@v6
|
|
96
|
-
|
|
97
|
-
- name: Set up Docker Buildx
|
|
98
|
-
uses: docker/setup-buildx-action@v3
|
|
99
|
-
|
|
100
|
-
- name: Build Docker image
|
|
101
|
-
uses: docker/build-push-action@v5
|
|
102
|
-
with:
|
|
103
|
-
context: .
|
|
104
|
-
push: false
|
|
105
|
-
tags: claw-dashboard:test
|
|
106
|
-
cache-from: type=gha
|
|
107
|
-
cache-to: type=gha,mode=max
|
|
108
|
-
|
|
109
|
-
security-audit:
|
|
110
|
-
name: Security Audit
|
|
111
|
-
runs-on: ubuntu-latest
|
|
112
|
-
needs: test
|
|
113
|
-
permissions:
|
|
114
|
-
actions: read
|
|
115
|
-
contents: read
|
|
116
|
-
security-events: write
|
|
117
|
-
|
|
118
|
-
steps:
|
|
119
|
-
- name: Checkout code
|
|
120
|
-
uses: actions/checkout@v6
|
|
121
|
-
|
|
122
|
-
- name: Setup Node.js
|
|
123
|
-
uses: actions/setup-node@v6
|
|
124
|
-
with:
|
|
125
|
-
node-version: 20
|
|
126
|
-
cache: 'npm'
|
|
127
|
-
|
|
128
|
-
- name: Install dependencies
|
|
129
|
-
run: npm ci
|
|
130
|
-
|
|
131
|
-
- name: Run npm audit
|
|
132
|
-
run: npm audit --audit-level=moderate
|
|
133
|
-
continue-on-error: true
|
|
134
|
-
|
|
135
|
-
- name: Run Trivy vulnerability scanner
|
|
136
|
-
uses: aquasecurity/trivy-action@master
|
|
137
|
-
with:
|
|
138
|
-
scan-type: 'fs'
|
|
139
|
-
scan-ref: '.'
|
|
140
|
-
format: 'sarif'
|
|
141
|
-
output: 'trivy-results.sarif'
|
|
142
|
-
|
|
143
|
-
- name: Upload Trivy scan results
|
|
144
|
-
uses: github/codeql-action/upload-sarif@v4
|
|
145
|
-
if: always()
|
|
146
|
-
with:
|
|
147
|
-
sarif_file: 'trivy-results.sarif'
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
name: Release
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
release:
|
|
5
|
-
types: [created, published]
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
build-and-publish:
|
|
9
|
-
name: Build and Publish
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
permissions:
|
|
12
|
-
contents: read
|
|
13
|
-
id-token: write
|
|
14
|
-
|
|
15
|
-
steps:
|
|
16
|
-
- name: Checkout code
|
|
17
|
-
uses: actions/checkout@v6
|
|
18
|
-
|
|
19
|
-
- name: Setup Node.js
|
|
20
|
-
uses: actions/setup-node@v6
|
|
21
|
-
with:
|
|
22
|
-
node-version: 20
|
|
23
|
-
cache: 'npm'
|
|
24
|
-
registry-url: 'https://registry.npmjs.org'
|
|
25
|
-
|
|
26
|
-
- name: Install dependencies
|
|
27
|
-
run: npm ci
|
|
28
|
-
|
|
29
|
-
- name: Run tests
|
|
30
|
-
run: npm test
|
|
31
|
-
|
|
32
|
-
- name: Build all bundles
|
|
33
|
-
run: |
|
|
34
|
-
npm run build
|
|
35
|
-
npm run build:cjs
|
|
36
|
-
|
|
37
|
-
- name: Publish to npm
|
|
38
|
-
run: npm publish --provenance --access public
|
|
39
|
-
env:
|
|
40
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
name: Security Audit
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main, dev]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [main]
|
|
8
|
-
schedule:
|
|
9
|
-
# Run daily at 2:00 AM UTC
|
|
10
|
-
- cron: '0 2 * * *'
|
|
11
|
-
workflow_dispatch:
|
|
12
|
-
|
|
13
|
-
jobs:
|
|
14
|
-
npm-audit:
|
|
15
|
-
name: NPM Audit
|
|
16
|
-
runs-on: ubuntu-latest
|
|
17
|
-
|
|
18
|
-
steps:
|
|
19
|
-
- name: Checkout code
|
|
20
|
-
uses: actions/checkout@v6
|
|
21
|
-
|
|
22
|
-
- name: Setup Node.js
|
|
23
|
-
uses: actions/setup-node@v6
|
|
24
|
-
with:
|
|
25
|
-
node-version: 20
|
|
26
|
-
cache: 'npm'
|
|
27
|
-
|
|
28
|
-
- name: Install dependencies
|
|
29
|
-
run: npm ci
|
|
30
|
-
|
|
31
|
-
- name: Run npm audit
|
|
32
|
-
run: |
|
|
33
|
-
npm audit --audit-level=moderate || exit_code=$?
|
|
34
|
-
if [ "${exit_code:-0}" -eq 0 ]; then
|
|
35
|
-
echo "No vulnerabilities found"
|
|
36
|
-
elif [ "${exit_code:-0}" -eq 1 ]; then
|
|
37
|
-
echo "Vulnerabilities found! See above for details."
|
|
38
|
-
exit 1
|
|
39
|
-
fi
|
|
40
|
-
|
|
41
|
-
dependency-review:
|
|
42
|
-
name: Dependency Review
|
|
43
|
-
runs-on: ubuntu-latest
|
|
44
|
-
if: github.event_name == 'pull_request'
|
|
45
|
-
|
|
46
|
-
steps:
|
|
47
|
-
- name: Checkout code
|
|
48
|
-
uses: actions/checkout@v6
|
|
49
|
-
|
|
50
|
-
- name: Dependency Review
|
|
51
|
-
uses: actions/dependency-review-action@v4
|
|
52
|
-
with:
|
|
53
|
-
fail-on-severity: moderate
|
|
54
|
-
comment-summary-in-pr: true
|
|
55
|
-
|
|
56
|
-
codeql-analysis:
|
|
57
|
-
name: CodeQL Analysis
|
|
58
|
-
runs-on: ubuntu-latest
|
|
59
|
-
permissions:
|
|
60
|
-
actions: read
|
|
61
|
-
contents: read
|
|
62
|
-
security-events: write
|
|
63
|
-
|
|
64
|
-
strategy:
|
|
65
|
-
fail-fast: false
|
|
66
|
-
matrix:
|
|
67
|
-
language: ['javascript']
|
|
68
|
-
|
|
69
|
-
steps:
|
|
70
|
-
- name: Checkout code
|
|
71
|
-
uses: actions/checkout@v6
|
|
72
|
-
|
|
73
|
-
- name: Initialize CodeQL
|
|
74
|
-
uses: github/codeql-action/init@v4
|
|
75
|
-
with:
|
|
76
|
-
languages: ${{ matrix.language }}
|
|
77
|
-
|
|
78
|
-
- name: Autobuild
|
|
79
|
-
uses: github/codeql-action/autobuild@v4
|
|
80
|
-
|
|
81
|
-
- name: Perform CodeQL Analysis
|
|
82
|
-
uses: github/codeql-action/analyze@v4
|
|
83
|
-
with:
|
|
84
|
-
category: "/language:${{matrix.language}}"
|
package/.husky/pre-commit
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
npx lint-staged
|