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.
Files changed (89) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/docs/API.md +1 -2
  3. package/index.js +31 -41
  4. package/package.json +22 -12
  5. package/src/auto-save.js +11 -5
  6. package/src/cli/export-snapshot.js +3 -1
  7. package/src/cli/import-snapshot.js +3 -1
  8. package/src/config.js +9 -15
  9. package/src/errors.js +0 -9
  10. package/src/security.js +6 -2
  11. package/src/snapshot.js +73 -26
  12. package/src/web-server.js +7 -10
  13. package/.c8rc.json +0 -38
  14. package/.dockerignore +0 -68
  15. package/.github/dependabot.yml +0 -45
  16. package/.github/pull_request_template.md +0 -39
  17. package/.github/workflows/ci.yml +0 -147
  18. package/.github/workflows/release.yml +0 -40
  19. package/.github/workflows/security.yml +0 -84
  20. package/.husky/pre-commit +0 -1
  21. package/.planning/codebase/ARCHITECTURE.md +0 -206
  22. package/.planning/codebase/INTEGRATIONS.md +0 -150
  23. package/.planning/codebase/STACK.md +0 -122
  24. package/.planning/codebase/STRUCTURE.md +0 -201
  25. package/CONTRIBUTING.md +0 -378
  26. package/Dockerfile +0 -54
  27. package/FEATURES.md +0 -307
  28. package/TODO.md +0 -28
  29. package/ai.openclaw.dashboard.plist +0 -35
  30. package/build-cjs.js +0 -127
  31. package/cjs-shim.js +0 -13
  32. package/dist/clawdash +0 -1729
  33. package/dist/clawdash.meta.json +0 -2236
  34. package/dist/widgets.cjs +0 -6511
  35. package/docker-compose.yml +0 -67
  36. package/esbuild.config.js +0 -158
  37. package/eslint.config.js +0 -56
  38. package/examples/plugins/README.md +0 -122
  39. package/examples/plugins/api-status/index.js +0 -294
  40. package/examples/plugins/api-status/plugin.json +0 -19
  41. package/examples/plugins/hello-world/index.js +0 -104
  42. package/examples/plugins/hello-world/plugin.json +0 -15
  43. package/examples/plugins/system-metrics-chart/index.js +0 -339
  44. package/examples/plugins/system-metrics-chart/plugin.json +0 -18
  45. package/examples/plugins/weather-widget/index.js +0 -136
  46. package/examples/plugins/weather-widget/plugin.json +0 -19
  47. package/index.cjs +0 -23005
  48. package/jest.config.js +0 -11
  49. package/scripts/release.js +0 -595
  50. package/src/database.js +0 -734
  51. package/tests/alerts.test.js +0 -437
  52. package/tests/auto-save.test.js +0 -529
  53. package/tests/cache.test.js +0 -317
  54. package/tests/cli.test.js +0 -351
  55. package/tests/command-palette.test.js +0 -320
  56. package/tests/config-processor.test.js +0 -452
  57. package/tests/config-validator.test.js +0 -710
  58. package/tests/config-watcher.test.js +0 -594
  59. package/tests/config.test.js +0 -755
  60. package/tests/database.test.js +0 -438
  61. package/tests/errors.test.js +0 -189
  62. package/tests/example-plugins.test.js +0 -624
  63. package/tests/integration.test.js +0 -1321
  64. package/tests/loading-states.test.js +0 -300
  65. package/tests/manifest-validation-on-load.test.js +0 -671
  66. package/tests/performance-monitor.test.js +0 -190
  67. package/tests/plugin-api-rate-limit.test.js +0 -302
  68. package/tests/plugin-errors.test.js +0 -311
  69. package/tests/plugin-lifecycle-e2e.test.js +0 -1036
  70. package/tests/plugin-reload.test.js +0 -764
  71. package/tests/rate-limiter.test.js +0 -539
  72. package/tests/removed-dependencies.test.js +0 -74
  73. package/tests/retry.test.js +0 -308
  74. package/tests/security.test.js +0 -411
  75. package/tests/settings-modal.test.js +0 -226
  76. package/tests/theme-selector.test.js +0 -57
  77. package/tests/utils.js +0 -242
  78. package/tests/utils.test.js +0 -317
  79. package/tests/validate-plugin-cli.test.js +0 -359
  80. package/tests/validation.test.js +0 -837
  81. package/tests/web-server.test.js +0 -646
  82. package/tests/widget-arrange-mode.test.js +0 -183
  83. package/tests/widget-config-hot-reload.test.js +0 -465
  84. package/tests/widget-dependency.test.js +0 -591
  85. package/tests/widget-error-boundary.test.js +0 -749
  86. package/tests/widget-error-isolation.test.js +0 -469
  87. package/tests/widget-integration.test.js +0 -1147
  88. package/tests/widget-refresh-intervals.test.js +0 -284
  89. 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 { join } from 'path';
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
- const dir = filePath.substring(0, filePath.lastIndexOf('/'));
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(filePath, JSON.stringify(snapshot, null, 2));
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(filePath, 0o600);
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: filePath };
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
- if (!fs.existsSync(filePath)) {
217
- return { success: false, error: `File not found: ${filePath}` };
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
- const data = fs.readFileSync(filePath, 'utf8');
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 validation = validateSnapshot(snapshot);
224
- if (!validation.valid) {
225
- return { success: false, error: validation.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 path = join(dir, f);
297
+ const filePath = path.join(dir, f);
271
298
  try {
272
- const data = fs.readFileSync(path, 'utf8');
299
+ const data = fs.readFileSync(filePath, 'utf8');
273
300
  const snapshot = JSON.parse(data);
274
- const stats = fs.statSync(path);
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: ensure the resolved path is within snapshots directory
309
- const resolvedPath = fs.realpathSync.safe
310
- ? fs.realpathSync(filePath)
311
- : filePath;
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
- if (!resolvedPath.startsWith(dir)) {
314
- return { success: false, error: 'Invalid snapshot path' };
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(filePath)) {
365
+ if (!fs.existsSync(unlinkPath)) {
319
366
  return { success: false, error: 'Snapshot not found' };
320
367
  }
321
- fs.unlinkSync(filePath);
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
@@ -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.
@@ -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