fg-devkit 1.20.2 → 1.21.1
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 +32 -9
- package/configs/dependency-policy.vue-workspace.json +1 -1
- package/package.json +3 -3
- package/scaffold/vue/package.json +2 -2
- package/scripts/audit-fix-plan.mjs +436 -0
- package/scripts/audit-fix-plan.test.mjs +287 -0
- package/scripts/audit-override-commit.mjs +380 -81
- package/scripts/bump-node-toolchain.mjs +2 -5
- package/scripts/fg-devkit.mjs +6 -6
- package/scripts/fleet-project-repos.mjs +25 -5
- package/scripts/node-toolchain-sync.mjs +2 -2
- package/scripts/piwik-dimensions.test.mjs +0 -17
- package/scripts/sync-dependency-check-suppressions-commit.mjs +78 -14
|
@@ -1,22 +1,47 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Write dependency-check-suppressions.xml into the consumer repo and auto-commit.
|
|
4
|
+
*
|
|
5
|
+
* Only the active <suppress> entries from fg-devkit's shared file that match a finding
|
|
6
|
+
* `pnpm audit` still reports in this repo are written, so OWASP Dependency-Check accepts
|
|
7
|
+
* exactly the risks this repo has. Pass --all to copy the whole shared file instead.
|
|
4
8
|
*
|
|
5
9
|
* Usage:
|
|
6
|
-
* node node_modules/fg-devkit/scripts/sync-dependency-check-suppressions-commit.mjs
|
|
7
|
-
* pnpm exec fg-devkit sync-dependency-check-suppressions-commit
|
|
10
|
+
* node node_modules/fg-devkit/scripts/sync-dependency-check-suppressions-commit.mjs [--all]
|
|
11
|
+
* pnpm exec fg-devkit sync-dependency-check-suppressions-commit [--all]
|
|
8
12
|
*/
|
|
9
13
|
|
|
10
14
|
import fs from 'node:fs'
|
|
11
15
|
import path from 'node:path'
|
|
12
16
|
import { fileURLToPath } from 'node:url'
|
|
13
17
|
import { spawnSync } from 'node:child_process'
|
|
18
|
+
import { parseArgs } from 'node:util'
|
|
19
|
+
import { filterSuppressions, normalizeAdvisories, parseAuditJson, parseSuppressions } from './audit-fix-plan.mjs'
|
|
14
20
|
|
|
21
|
+
const TAG = '[sync-dependency-check-suppressions]'
|
|
15
22
|
const FILE_NAME = 'dependency-check-suppressions.xml'
|
|
16
23
|
const COMMIT_MESSAGE = 'chore(repo): sync dependency-check suppressions'
|
|
17
24
|
const projectRoot = process.cwd()
|
|
18
25
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
19
26
|
|
|
27
|
+
const { values: args } = parseArgs({
|
|
28
|
+
options: {
|
|
29
|
+
all: { type: 'boolean', default: false },
|
|
30
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
31
|
+
},
|
|
32
|
+
strict: true,
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
if (args.help) {
|
|
36
|
+
console.log(`Usage: pnpm exec fg-devkit sync-dependency-check-suppressions-commit [--all]
|
|
37
|
+
|
|
38
|
+
Writes ${FILE_NAME} with the entries from fg-devkit that match findings
|
|
39
|
+
pnpm audit reports in this repo, and auto-commits it.
|
|
40
|
+
|
|
41
|
+
--all Copy every entry from fg-devkit's shared file (no pnpm audit)`)
|
|
42
|
+
process.exit(0)
|
|
43
|
+
}
|
|
44
|
+
|
|
20
45
|
function findFgDevkitPackageRoot() {
|
|
21
46
|
const candidates = [
|
|
22
47
|
path.resolve(scriptDir, '..'),
|
|
@@ -31,15 +56,15 @@ function findFgDevkitPackageRoot() {
|
|
|
31
56
|
return null
|
|
32
57
|
}
|
|
33
58
|
|
|
34
|
-
function runGit(
|
|
35
|
-
const result = spawnSync('git',
|
|
59
|
+
function runGit(gitArgs, options = {}) {
|
|
60
|
+
const result = spawnSync('git', gitArgs, {
|
|
36
61
|
stdio: options.capture ? 'pipe' : 'inherit',
|
|
37
62
|
encoding: options.capture ? 'utf8' : undefined,
|
|
38
63
|
cwd: projectRoot,
|
|
39
64
|
env: process.env,
|
|
40
65
|
})
|
|
41
66
|
if (result.error) {
|
|
42
|
-
console.error(
|
|
67
|
+
console.error(TAG, result.error.message)
|
|
43
68
|
return { status: 1, stdout: '' }
|
|
44
69
|
}
|
|
45
70
|
return { status: result.status ?? 1, stdout: result.stdout ?? '' }
|
|
@@ -56,30 +81,69 @@ function fileDiffersFromHead(filePath) {
|
|
|
56
81
|
return diff.status !== 0
|
|
57
82
|
}
|
|
58
83
|
|
|
84
|
+
/** GHSA ids `pnpm audit` reports in this repo. Exits on audit failure so nothing is written blindly. */
|
|
85
|
+
function reportedGhsas() {
|
|
86
|
+
const result = spawnSync('pnpm', ['audit', '--json'], {
|
|
87
|
+
cwd: projectRoot,
|
|
88
|
+
env: process.env,
|
|
89
|
+
encoding: 'utf8',
|
|
90
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
91
|
+
})
|
|
92
|
+
if (result.error || (result.status !== 0 && result.status !== 1)) {
|
|
93
|
+
console.error(`${TAG} pnpm audit failed, ${FILE_NAME} was not changed.`)
|
|
94
|
+
console.error((result.error?.message ?? result.stderr ?? result.stdout ?? '').trim())
|
|
95
|
+
process.exit(1)
|
|
96
|
+
}
|
|
97
|
+
return new Set(normalizeAdvisories(parseAuditJson(result.stdout)).map((advisory) => advisory.ghsa))
|
|
98
|
+
}
|
|
99
|
+
|
|
59
100
|
const fgRoot = findFgDevkitPackageRoot()
|
|
60
101
|
if (!fgRoot) {
|
|
61
|
-
console.error(
|
|
62
|
-
'[sync-dependency-check-suppressions] Could not find fg-devkit (install fg-devkit or a package that bundles it, e.g. fds-vue-core).',
|
|
63
|
-
)
|
|
102
|
+
console.error(`${TAG} Could not find fg-devkit (install fg-devkit or a package that bundles it, e.g. fds-vue-core).`)
|
|
64
103
|
process.exit(1)
|
|
65
104
|
}
|
|
66
105
|
|
|
67
106
|
const sourcePath = path.join(fgRoot, 'configs', FILE_NAME)
|
|
68
107
|
if (!fs.existsSync(sourcePath)) {
|
|
69
|
-
console.error(
|
|
108
|
+
console.error(`${TAG} Missing template: ${sourcePath}`)
|
|
70
109
|
process.exit(1)
|
|
71
110
|
}
|
|
72
111
|
|
|
73
|
-
fs.
|
|
74
|
-
|
|
112
|
+
const shared = fs.readFileSync(sourcePath, 'utf8')
|
|
113
|
+
const targetPath = path.join(projectRoot, FILE_NAME)
|
|
114
|
+
let content = shared
|
|
115
|
+
|
|
116
|
+
if (!args.all) {
|
|
117
|
+
console.log(`${TAG} Running pnpm audit to find the entries that apply to this repo…`)
|
|
118
|
+
const reported = reportedGhsas()
|
|
119
|
+
const now = Date.now()
|
|
120
|
+
const kept = parseSuppressions(shared, now).filter(
|
|
121
|
+
(entry) => entry.active && entry.ghsas.some((ghsa) => reported.has(ghsa)),
|
|
122
|
+
)
|
|
123
|
+
content = filterSuppressions(shared, reported, now)
|
|
124
|
+
|
|
125
|
+
if (kept.length === 0 && !fs.existsSync(targetPath)) {
|
|
126
|
+
console.log(`${TAG} No shared suppression applies to this repo. ${FILE_NAME} not created.`)
|
|
127
|
+
process.exit(0)
|
|
128
|
+
}
|
|
129
|
+
const keptIds = kept.flatMap((entry) => entry.ghsas).filter((ghsa) => reported.has(ghsa))
|
|
130
|
+
console.log(
|
|
131
|
+
kept.length > 0
|
|
132
|
+
? `${TAG} Keeping ${kept.length} entr${kept.length === 1 ? 'y' : 'ies'}: ${keptIds.join(', ')}`
|
|
133
|
+
: `${TAG} No shared suppression applies to this repo. Writing ${FILE_NAME} without entries.`,
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
fs.writeFileSync(targetPath, content)
|
|
138
|
+
console.log(`${TAG} Updated ${FILE_NAME}.`)
|
|
75
139
|
|
|
76
140
|
if (!fileDiffersFromHead(FILE_NAME)) {
|
|
77
|
-
console.log(
|
|
141
|
+
console.log(`${TAG} No changes to commit.`)
|
|
78
142
|
process.exit(0)
|
|
79
143
|
}
|
|
80
144
|
|
|
81
145
|
const stage = runGit(['add', '--', FILE_NAME])
|
|
82
146
|
if (stage.status !== 0) process.exit(stage.status)
|
|
83
147
|
|
|
84
|
-
console.log(
|
|
148
|
+
console.log(`${TAG} Auto-committing: ${COMMIT_MESSAGE}`)
|
|
85
149
|
process.exit(runGit(['commit', '-m', COMMIT_MESSAGE]).status)
|