@bardioc/create-bardioc-app 0.6.1 → 0.7.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/README.md CHANGED
@@ -49,7 +49,11 @@ Every scaffolded app ships a lightweight versioning toolkit:
49
49
 
50
50
  - **Changesets** (`.changeset/` + `changeset`/`release:*` scripts) for semver-versioning the app
51
51
  - **`scripts/stamp-manifest.mjs`** — folds `package.json`'s version into the built `app-manifest.json`
52
- so the WebOS app store shows the real release version (wired into `npm run build` / `npm run bundle`)
52
+ and `manifest.yaml` (wired into `npm run build` / `npm run bundle`)
53
+ - **Compliance gate** (`scripts/compliance.mjs`, `audit.mjs`, `compliance-summary.mjs` + `sbom` /
54
+ `compliance` / `audit:security` / `compliance:all` scripts) — `npm run bundle` first writes a
55
+ CycloneDX SBOM, checks production licenses against an allow list and fails on high/critical audit
56
+ findings; the four reports land in `public/` and ship inside the zip
53
57
  - Two Claude skills under `.claude/commands/`: **`/changeset-app`** (bump locally) and
54
58
  **`/refresh-bundle`** (rebuild the zip and swap it into a WebOS host checkout)
55
59
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bardioc/create-bardioc-app",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "Scaffold a Bardioc app with framework templates (vite, react, vue, angular, svelte, solid, preact, nextjs)",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -12,7 +12,7 @@ Re-bundle **this** standalone hosted app and swap the fresh zip into the WebOS h
12
12
  The flow, end to end:
13
13
 
14
14
  1. **Remove** the stale zip in this app repo (forces a clean rebundle, never copies a stale artifact).
15
- 2. **Bundle** via this repo's `npm run bundle` script (`<build> && node scripts/stamp-manifest.mjs && zip → <app>.zip`).
15
+ 2. **Bundle** via this repo's `npm run bundle` script (`npm run compliance:all && <build> && node scripts/stamp-manifest.mjs && zip → <app>.zip`).
16
16
  3. **Replace** `<host>/apps/webos-host/public/_apps/<app>.zip` with the freshly built one.
17
17
 
18
18
  ## Arguments
@@ -69,7 +69,7 @@ Then verify the artifact was actually produced:
69
69
  test -f "$REPO/$ZIP" && ls -l "$REPO/$ZIP" || { echo "Bundle did not produce $ZIP"; exit 1; }
70
70
  ```
71
71
 
72
- If `npm run bundle` fails (build errors), **stop and report the real failure** — do not copy anything.
72
+ If `npm run bundle` fails (compliance gate or build errors), **stop and report the real failure** — do not copy anything.
73
73
  You may fix an obvious issue and retry once; on a second failure, report it truthfully and ask the
74
74
  user how to proceed.
75
75
 
@@ -69,11 +69,14 @@ resolves from Nexus. No overlay or CI-only workspace file needed.
69
69
 
70
70
  ```bash
71
71
  npm run build # type-check + build (+ stamp the manifest version) → output dir
72
- npm run bundle # build + zip → {{APP_NAME}}.zip
72
+ npm run bundle # compliance gate + build + zip → {{APP_NAME}}.zip
73
+ npm run compliance:all # SBOM + license check + vulnerability audit → public/*.json
73
74
  ```
74
75
 
75
- `scripts/stamp-manifest.mjs` folds `package.json`'s `version` into the built `app-manifest.json` so
76
- the WebOS app store shows the real release version. `{{APP_NAME}}.zip` is the deliverable uploaded
76
+ `scripts/stamp-manifest.mjs` folds `package.json`'s `version` into the built `app-manifest.json` and
77
+ `manifest.yaml`. `npm run bundle` starts with the compliance gate: it stops on a production dependency
78
+ whose license is not on the allow list in `scripts/compliance.mjs`, or on a high or critical audit
79
+ finding, and ships the SBOM and the reports inside the zip. `{{APP_NAME}}.zip` is the deliverable uploaded
77
80
  to the Bardioc host as a hosted app. To swap a fresh build into a local WebOS host checkout, run the
78
81
  **`/refresh-bundle`** skill.
79
82
 
@@ -0,0 +1,50 @@
1
+ // Vulnerability gate: scans production dependencies via npm audit, fails on high/critical findings.
2
+ import { spawnSync } from 'node:child_process';
3
+ import { mkdirSync, writeFileSync } from 'node:fs';
4
+ import { resolve } from 'node:path';
5
+
6
+ const FAIL_SEVERITIES = ['high', 'critical'];
7
+
8
+ const outDir = resolve(process.argv[2] ?? 'public');
9
+ mkdirSync(outDir, { recursive: true });
10
+
11
+ // npm audit exits non-zero when vulnerabilities exist, so exit code is not an error signal here.
12
+ const res = spawnSync('npm', ['audit', '--omit=dev', '--json'], {
13
+ encoding: 'utf8',
14
+ maxBuffer: 64 * 1024 * 1024,
15
+ });
16
+ if (!res.stdout) {
17
+ console.error('npm audit produced no output:', res.stderr);
18
+ process.exit(1);
19
+ }
20
+ const audit = JSON.parse(res.stdout);
21
+ const counts = audit.metadata?.vulnerabilities ?? {};
22
+
23
+ const findings = Object.values(audit.vulnerabilities ?? {}).map(v => ({
24
+ name: v.name,
25
+ severity: v.severity,
26
+ range: v.range,
27
+ fixAvailable: v.fixAvailable,
28
+ advisories: (v.via ?? [])
29
+ .filter(x => typeof x === 'object')
30
+ .map(x => ({ title: x.title, url: x.url, severity: x.severity, cwe: x.cwe, cvss: x.cvss })),
31
+ }));
32
+
33
+ const blocking = findings.filter(f => FAIL_SEVERITIES.includes(f.severity));
34
+ const report = {
35
+ generatedAt: new Date().toISOString(),
36
+ tool: 'npm audit (production dependencies)',
37
+ failOn: FAIL_SEVERITIES,
38
+ counts,
39
+ passed: blocking.length === 0,
40
+ findings,
41
+ };
42
+ writeFileSync(resolve(outDir, 'security-audit.json'), JSON.stringify(report, null, 2));
43
+
44
+ console.log('Vulnerability scan:', JSON.stringify(counts));
45
+ if (blocking.length > 0) {
46
+ console.error('Blocking vulnerabilities:');
47
+ for (const f of blocking) console.error(` ${f.name} (${f.severity}) ${f.range}`);
48
+ process.exit(1);
49
+ }
50
+ console.log('No high/critical vulnerabilities.');
@@ -0,0 +1,42 @@
1
+ // Aggregates SBOM, license, and vulnerability reports into one verdict a reviewer or CI can read.
2
+ import { readFileSync, writeFileSync } from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+
5
+ const dir = resolve(process.argv[2] ?? 'public');
6
+ const readJson = f => JSON.parse(readFileSync(resolve(dir, f), 'utf8'));
7
+
8
+ const pkg = JSON.parse(readFileSync('package.json', 'utf8'));
9
+ const sbom = readJson('sbom.cdx.json');
10
+ const licenses = readJson('license-compliance.json');
11
+ const audit = readJson('security-audit.json');
12
+
13
+ const summary = {
14
+ app: { name: pkg.name, version: pkg.version },
15
+ generatedAt: new Date().toISOString(),
16
+ checks: {
17
+ sbom: {
18
+ passed: true,
19
+ format: `CycloneDX ${sbom.specVersion}`,
20
+ components: sbom.components?.length ?? 0,
21
+ report: 'sbom.cdx.json',
22
+ },
23
+ licenses: {
24
+ passed: licenses.violations.length === 0,
25
+ packagesScanned: licenses.totalPackages,
26
+ violations: licenses.violations.length,
27
+ allowedLicenses: licenses.allowedLicenses,
28
+ report: 'license-compliance.json',
29
+ },
30
+ vulnerabilities: {
31
+ passed: audit.passed,
32
+ counts: audit.counts,
33
+ failOn: audit.failOn,
34
+ report: 'security-audit.json',
35
+ },
36
+ },
37
+ };
38
+ summary.passed = Object.values(summary.checks).every(c => c.passed);
39
+
40
+ writeFileSync(resolve(dir, 'compliance-summary.json'), JSON.stringify(summary, null, 2));
41
+ console.log(`Compliance summary: ${summary.passed ? 'PASSED' : 'FAILED'}`);
42
+ if (!summary.passed) process.exit(1);
@@ -0,0 +1,64 @@
1
+ // License compliance gate: fails the build when a production dependency uses a non-allowed license.
2
+ import { execFileSync } from 'node:child_process';
3
+ import { mkdirSync, writeFileSync } from 'node:fs';
4
+ import { resolve } from 'node:path';
5
+
6
+ const ALLOWED_LICENSES = [
7
+ 'MIT',
8
+ 'ISC',
9
+ 'Apache-2.0',
10
+ 'BSD-2-Clause',
11
+ 'BSD-3-Clause',
12
+ '0BSD',
13
+ 'CC0-1.0',
14
+ 'Unlicense',
15
+ // Permissive OSI license (PSF); argparse, a js-yaml dependency, ships under it.
16
+ 'Python-2.0',
17
+ ];
18
+
19
+ const outDir = resolve(process.argv[2] ?? 'dist/reports');
20
+ mkdirSync(outDir, { recursive: true });
21
+
22
+ const raw = execFileSync(
23
+ 'npx',
24
+ ['license-checker-rseidelsohn', '--production', '--json', '--excludePrivatePackages'],
25
+ { encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 }
26
+ );
27
+ const packages = JSON.parse(raw);
28
+
29
+ // SPDX expressions: "A AND B" needs every part allowed, "A OR B" lets us pick an
30
+ // allowed alternative (e.g. dompurify's "MPL-2.0 OR Apache-2.0").
31
+ const isAllowed = licenses => {
32
+ const expr = String(licenses).replaceAll(/[()]/g, '');
33
+ const conjuncts = expr.split(/\s+AND\s+/);
34
+ return conjuncts.every(part =>
35
+ part.split(/\s+OR\s+/).some(l => ALLOWED_LICENSES.includes(l.trim()))
36
+ );
37
+ };
38
+
39
+ const violations = [];
40
+ const summary = {};
41
+ for (const [name, info] of Object.entries(packages)) {
42
+ const license = String(info.licenses);
43
+ summary[license] = (summary[license] ?? 0) + 1;
44
+ if (!isAllowed(license)) violations.push({ package: name, license, repository: info.repository });
45
+ }
46
+
47
+ const report = {
48
+ generatedAt: new Date().toISOString(),
49
+ allowedLicenses: ALLOWED_LICENSES,
50
+ totalPackages: Object.keys(packages).length,
51
+ licenseSummary: summary,
52
+ violations,
53
+ packages,
54
+ };
55
+ writeFileSync(resolve(outDir, 'license-compliance.json'), JSON.stringify(report, null, 2));
56
+
57
+ console.log(`License compliance: ${report.totalPackages} packages scanned`);
58
+ console.table(summary);
59
+ if (violations.length > 0) {
60
+ console.error('License violations found:');
61
+ for (const v of violations) console.error(` ${v.package}: ${v.license}`);
62
+ process.exit(1);
63
+ }
64
+ console.log('No license violations.');
@@ -1,5 +1,5 @@
1
- // Folds package.json's version into the built app-manifest.json so the WebOS app store (name +
2
- // description only) shows the release version. Output dir comes from argv (defaults to dist). Idempotent.
1
+ // Folds package.json's version into the built app-manifest.json and manifest.yaml. Output dir comes
2
+ // from argv (defaults to dist). Idempotent.
3
3
  import { readFileSync, writeFileSync } from 'node:fs';
4
4
 
5
5
  const root = new URL('..', import.meta.url);
@@ -8,10 +8,16 @@ const { version } = JSON.parse(readFileSync(new URL('package.json', root), 'utf8
8
8
 
9
9
  const url = new URL(`${outDir}/app-manifest.json`, root);
10
10
  const manifest = JSON.parse(readFileSync(url, 'utf8'));
11
- const base = (manifest.description ?? '').replace(/\s*\(v[^)]*\)\s*$/, '').trim();
12
11
 
13
12
  manifest.version = version;
14
- manifest.description = base ? `${base} (v${version})` : `v${version}`;
13
+ // The version lives in its own field; a "(vX.Y.Z)" suffix left by an older stamp is dropped.
14
+ if (manifest.description) {
15
+ manifest.description = manifest.description.replace(/\s*\(v[^)]*\)\s*$/, '').trim();
16
+ }
15
17
 
16
18
  writeFileSync(url, `${JSON.stringify(manifest, null, 2)}\n`);
19
+
20
+ // The legacy manifest.yaml carries the same version for the store's uploader.
21
+ const yamlUrl = new URL(`${outDir}/manifest.yaml`, root);
22
+ writeFileSync(yamlUrl, `name: ${manifest.id}\nversion: ${version}\n`);
17
23
  process.stdout.write(`[stamp-manifest] ${version} → ${outDir}/app-manifest.json\n`);
@@ -6,3 +6,9 @@ node_modules
6
6
  *.zip
7
7
  .linked/
8
8
  .DS_Store
9
+
10
+ # Generated by `npm run compliance:all`, shipped inside the bundle.
11
+ public/sbom.cdx.json
12
+ public/license-compliance.json
13
+ public/security-audit.json
14
+ public/compliance-summary.json
@@ -9,7 +9,11 @@
9
9
  "dev": "node ./scripts/dev.mjs",
10
10
  "prebuild": "npm run sync:runtime-env",
11
11
  "build": "ng build && node scripts/stamp-manifest.mjs dist/{{APP_NAME}}/browser",
12
- "bundle": "ng build && node scripts/stamp-manifest.mjs dist/{{APP_NAME}}/browser && cd dist/{{APP_NAME}}/browser && zip -r ../../../{{APP_NAME}}.zip .",
12
+ "bundle": "npm run compliance:all && ng build && node scripts/stamp-manifest.mjs dist/{{APP_NAME}}/browser && cd dist/{{APP_NAME}}/browser && zip -r ../../../{{APP_NAME}}.zip .",
13
+ "sbom": "cyclonedx-npm --omit dev --output-format json --output-reproducible --output-file public/sbom.cdx.json",
14
+ "compliance": "node scripts/compliance.mjs public",
15
+ "audit:security": "node scripts/audit.mjs public",
16
+ "compliance:all": "npm run sbom && npm run compliance && npm run audit:security && node scripts/compliance-summary.mjs public",
13
17
  "prewatch": "npm run sync:runtime-env",
14
18
  "watch": "ng build --watch --configuration development",
15
19
  "precheck-types": "npm run sync:runtime-env",
@@ -38,8 +42,10 @@
38
42
  "@angular/cli": "^19.2.13",
39
43
  "@angular/compiler-cli": "^19.2.12",
40
44
  "@changesets/cli": "^2.31.0",
45
+ "@cyclonedx/cyclonedx-npm": "^6.0.1",
41
46
  "@tailwindcss/postcss": "^4.2.4",
42
47
  "autoprefixer": "^10.4.21",
48
+ "license-checker-rseidelsohn": "^5.0.1",
43
49
  "postcss": "^8.5.4",
44
50
  "tailwindcss": "^4.2.4",
45
51
  "typescript": "~5.8.3"
@@ -6,3 +6,9 @@ node_modules
6
6
  *.zip
7
7
  .linked/
8
8
  .DS_Store
9
+
10
+ # Generated by `npm run compliance:all`, shipped inside the bundle.
11
+ public/sbom.cdx.json
12
+ public/license-compliance.json
13
+ public/security-audit.json
14
+ public/compliance-summary.json
@@ -5,7 +5,11 @@
5
5
  "scripts": {
6
6
  "dev": "node ./scripts/dev.mjs",
7
7
  "build": "next build && node scripts/stamp-manifest.mjs out",
8
- "bundle": "next build && node scripts/stamp-manifest.mjs out && cd out && zip -r ../{{APP_NAME}}.zip .",
8
+ "bundle": "npm run compliance:all && next build && node scripts/stamp-manifest.mjs out && cd out && zip -r ../{{APP_NAME}}.zip .",
9
+ "sbom": "cyclonedx-npm --omit dev --output-format json --output-reproducible --output-file public/sbom.cdx.json",
10
+ "compliance": "node scripts/compliance.mjs public",
11
+ "audit:security": "node scripts/audit.mjs public",
12
+ "compliance:all": "npm run sbom && npm run compliance && npm run audit:security && node scripts/compliance-summary.mjs public",
9
13
  "start": "next start",
10
14
  "check-types": "tsc --noEmit",
11
15
  "lint": "eslint .",
@@ -25,11 +29,13 @@
25
29
  "devDependencies": {
26
30
  "@bardioc/configs": "0.2.1",
27
31
  "@changesets/cli": "^2.31.0",
32
+ "@cyclonedx/cyclonedx-npm": "^6.0.1",
28
33
  "@tailwindcss/postcss": "^4.2.4",
29
34
  "@types/node": "^22.10.0",
30
35
  "@types/react": "^19.2.14",
31
36
  "@types/react-dom": "^19.2.3",
32
37
  "eslint": "^10.0.0",
38
+ "license-checker-rseidelsohn": "^5.0.1",
33
39
  "prettier": "^3.6.2",
34
40
  "tailwindcss": "^4.2.4",
35
41
  "typescript": "^6.0.3"
@@ -7,3 +7,9 @@ coverage/
7
7
  .env.*.local
8
8
  *.tsbuildinfo
9
9
  .linked/
10
+
11
+ # Generated by `npm run compliance:all`, shipped inside the bundle.
12
+ public/sbom.cdx.json
13
+ public/license-compliance.json
14
+ public/security-audit.json
15
+ public/compliance-summary.json
@@ -6,7 +6,11 @@
6
6
  "scripts": {
7
7
  "dev": "vite",
8
8
  "build": "tsc && vite build && node scripts/stamp-manifest.mjs dist",
9
- "bundle": "tsc && vite build && node scripts/stamp-manifest.mjs dist && cd dist && zip -r ../{{APP_NAME}}.zip .",
9
+ "bundle": "npm run compliance:all && tsc && vite build && node scripts/stamp-manifest.mjs dist && cd dist && zip -r ../{{APP_NAME}}.zip .",
10
+ "sbom": "cyclonedx-npm --omit dev --output-format json --output-reproducible --output-file public/sbom.cdx.json",
11
+ "compliance": "node scripts/compliance.mjs public",
12
+ "audit:security": "node scripts/audit.mjs public",
13
+ "compliance:all": "npm run sbom && npm run compliance && npm run audit:security && node scripts/compliance-summary.mjs public",
10
14
  "preview": "vite preview",
11
15
  "check-types": "tsc --noEmit",
12
16
  "lint": "eslint .",
@@ -24,10 +28,12 @@
24
28
  "devDependencies": {
25
29
  "@bardioc/configs": "0.2.1",
26
30
  "@changesets/cli": "^2.31.0",
31
+ "@cyclonedx/cyclonedx-npm": "^6.0.1",
27
32
  "@preact/preset-vite": "^2.10.6",
28
33
  "@tailwindcss/vite": "^4.3.0",
29
34
  "@types/node": "^22.19.19",
30
35
  "eslint": "^10.0.0",
36
+ "license-checker-rseidelsohn": "^5.0.1",
31
37
  "preact-render-to-string": "^6.6.1",
32
38
  "prettier": "^3.6.2",
33
39
  "tailwindcss": "4.3.0",
@@ -7,3 +7,9 @@ coverage/
7
7
  .env.*.local
8
8
  *.tsbuildinfo
9
9
  .linked/
10
+
11
+ # Generated by `npm run compliance:all`, shipped inside the bundle.
12
+ public/sbom.cdx.json
13
+ public/license-compliance.json
14
+ public/security-audit.json
15
+ public/compliance-summary.json
@@ -6,7 +6,11 @@
6
6
  "scripts": {
7
7
  "dev": "vite",
8
8
  "build": "tsc && vite build && node scripts/stamp-manifest.mjs dist",
9
- "bundle": "tsc && vite build && node scripts/stamp-manifest.mjs dist && cd dist && zip -r ../{{APP_NAME}}.zip .",
9
+ "bundle": "npm run compliance:all && tsc && vite build && node scripts/stamp-manifest.mjs dist && cd dist && zip -r ../{{APP_NAME}}.zip .",
10
+ "sbom": "cyclonedx-npm --omit dev --output-format json --output-reproducible --output-file public/sbom.cdx.json",
11
+ "compliance": "node scripts/compliance.mjs public",
12
+ "audit:security": "node scripts/audit.mjs public",
13
+ "compliance:all": "npm run sbom && npm run compliance && npm run audit:security && node scripts/compliance-summary.mjs public",
10
14
  "preview": "vite preview",
11
15
  "check-types": "tsc --noEmit",
12
16
  "lint": "eslint .",
@@ -24,9 +28,11 @@
24
28
  "devDependencies": {
25
29
  "@bardioc/configs": "0.2.1",
26
30
  "@changesets/cli": "^2.31.0",
31
+ "@cyclonedx/cyclonedx-npm": "^6.0.1",
27
32
  "@tailwindcss/vite": "^4.3.0",
28
33
  "@types/node": "^22.19.19",
29
34
  "eslint": "^10.0.0",
35
+ "license-checker-rseidelsohn": "^5.0.1",
30
36
  "prettier": "^3.6.2",
31
37
  "tailwindcss": "4.3.0",
32
38
  "typescript": "6.0.3",
@@ -5,3 +5,9 @@ node_modules
5
5
  *.zip
6
6
  .linked/
7
7
  .DS_Store
8
+
9
+ # Generated by `npm run compliance:all`, shipped inside the bundle.
10
+ public/sbom.cdx.json
11
+ public/license-compliance.json
12
+ public/security-audit.json
13
+ public/compliance-summary.json
@@ -6,7 +6,11 @@
6
6
  "scripts": {
7
7
  "dev": "vite",
8
8
  "build": "svelte-check && vite build && node scripts/stamp-manifest.mjs dist",
9
- "bundle": "svelte-check && vite build && node scripts/stamp-manifest.mjs dist && cd dist && zip -r ../{{APP_NAME}}.zip .",
9
+ "bundle": "npm run compliance:all && svelte-check && vite build && node scripts/stamp-manifest.mjs dist && cd dist && zip -r ../{{APP_NAME}}.zip .",
10
+ "sbom": "cyclonedx-npm --omit dev --output-format json --output-reproducible --output-file public/sbom.cdx.json",
11
+ "compliance": "node scripts/compliance.mjs public",
12
+ "audit:security": "node scripts/audit.mjs public",
13
+ "compliance:all": "npm run sbom && npm run compliance && npm run audit:security && node scripts/compliance-summary.mjs public",
10
14
  "preview": "vite preview",
11
15
  "check-types": "svelte-check",
12
16
  "lint": "eslint .",
@@ -24,10 +28,12 @@
24
28
  "devDependencies": {
25
29
  "@bardioc/configs": "0.2.1",
26
30
  "@changesets/cli": "^2.31.0",
31
+ "@cyclonedx/cyclonedx-npm": "^6.0.1",
27
32
  "@sveltejs/vite-plugin-svelte": "^7.2.0",
28
33
  "@tailwindcss/vite": "^4.3.0",
29
34
  "@types/node": "^22.19.19",
30
35
  "eslint": "^10.0.0",
36
+ "license-checker-rseidelsohn": "^5.0.1",
31
37
  "prettier": "^3.6.2",
32
38
  "svelte-check": "^4.2.1",
33
39
  "tailwindcss": "4.3.0",
@@ -7,3 +7,9 @@ coverage/
7
7
  .env.*.local
8
8
  *.tsbuildinfo
9
9
  .linked/
10
+
11
+ # Generated by `npm run compliance:all`, shipped inside the bundle.
12
+ public/sbom.cdx.json
13
+ public/license-compliance.json
14
+ public/security-audit.json
15
+ public/compliance-summary.json
@@ -6,7 +6,11 @@
6
6
  "scripts": {
7
7
  "dev": "vite",
8
8
  "build": "tsc && vite build && node scripts/stamp-manifest.mjs dist",
9
- "bundle": "rm -f {{APP_NAME}}.zip && tsc && vite build && node scripts/stamp-manifest.mjs dist && cd dist && zip -r ../{{APP_NAME}}.zip .",
9
+ "bundle": "rm -f {{APP_NAME}}.zip && npm run compliance:all && tsc && vite build && node scripts/stamp-manifest.mjs dist && cd dist && zip -r ../{{APP_NAME}}.zip .",
10
+ "sbom": "cyclonedx-npm --omit dev --output-format json --output-reproducible --output-file public/sbom.cdx.json",
11
+ "compliance": "node scripts/compliance.mjs public",
12
+ "audit:security": "node scripts/audit.mjs public",
13
+ "compliance:all": "npm run sbom && npm run compliance && npm run audit:security && node scripts/compliance-summary.mjs public",
10
14
  "preview": "vite preview",
11
15
  "check-types": "tsc --noEmit",
12
16
  "lint": "eslint .",
@@ -28,12 +32,14 @@
28
32
  "devDependencies": {
29
33
  "@bardioc/configs": "0.2.1",
30
34
  "@changesets/cli": "^2.31.0",
35
+ "@cyclonedx/cyclonedx-npm": "^6.0.1",
31
36
  "@tailwindcss/vite": "^4.3.0",
32
37
  "@types/node": "^22.19.19",
33
38
  "@types/react": "^19.2.14",
34
39
  "@types/react-dom": "^19.2.3",
35
40
  "@vitejs/plugin-react": "5.2.0",
36
41
  "eslint": "^10.0.0",
42
+ "license-checker-rseidelsohn": "^5.0.1",
37
43
  "prettier": "^3.6.2",
38
44
  "tailwindcss": "4.3.0",
39
45
  "typescript": "6.0.3",
@@ -5,3 +5,9 @@ node_modules
5
5
  *.zip
6
6
  .linked/
7
7
  .DS_Store
8
+
9
+ # Generated by `npm run compliance:all`, shipped inside the bundle.
10
+ public/sbom.cdx.json
11
+ public/license-compliance.json
12
+ public/security-audit.json
13
+ public/compliance-summary.json
@@ -6,7 +6,11 @@
6
6
  "scripts": {
7
7
  "dev": "vite",
8
8
  "build": "vue-tsc -b && vite build && node scripts/stamp-manifest.mjs dist",
9
- "bundle": "vue-tsc -b && vite build && node scripts/stamp-manifest.mjs dist && cd dist && zip -r ../{{APP_NAME}}.zip .",
9
+ "bundle": "npm run compliance:all && vue-tsc -b && vite build && node scripts/stamp-manifest.mjs dist && cd dist && zip -r ../{{APP_NAME}}.zip .",
10
+ "sbom": "cyclonedx-npm --omit dev --output-format json --output-reproducible --output-file public/sbom.cdx.json",
11
+ "compliance": "node scripts/compliance.mjs public",
12
+ "audit:security": "node scripts/audit.mjs public",
13
+ "compliance:all": "npm run sbom && npm run compliance && npm run audit:security && node scripts/compliance-summary.mjs public",
10
14
  "preview": "vite preview",
11
15
  "check-types": "vue-tsc --noEmit",
12
16
  "lint": "eslint .",
@@ -24,10 +28,12 @@
24
28
  "devDependencies": {
25
29
  "@bardioc/configs": "0.2.1",
26
30
  "@changesets/cli": "^2.31.0",
31
+ "@cyclonedx/cyclonedx-npm": "^6.0.1",
27
32
  "@tailwindcss/vite": "^4.3.0",
28
33
  "@types/node": "^22.19.19",
29
34
  "@vitejs/plugin-vue": "^6.0.8",
30
35
  "eslint": "^10.0.0",
36
+ "license-checker-rseidelsohn": "^5.0.1",
31
37
  "prettier": "^3.6.2",
32
38
  "tailwindcss": "4.3.0",
33
39
  "typescript": "6.0.3",