@rsaglobaltech/specgate 0.26.0 → 0.27.2
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 +47 -0
- package/README.md +6 -0
- package/dist/packages/core/src/domain/ChangeMeasures.js +198 -0
- package/dist/packages/core/src/domain/ChangeMeasures.js.map +1 -0
- package/dist/packages/core/src/domain/ConventionalCommit.js +73 -0
- package/dist/packages/core/src/domain/ConventionalCommit.js.map +1 -0
- package/dist/packages/core/src/domain/HarnessConfig.js.map +1 -1
- package/dist/packages/core/src/domain/HarnessReport.js +2 -0
- package/dist/packages/core/src/domain/HarnessReport.js.map +1 -1
- package/dist/packages/core/src/domain/QualityChecks.js +241 -0
- package/dist/packages/core/src/domain/QualityChecks.js.map +1 -0
- package/dist/packages/core/src/domain/QualitySummary.js +58 -0
- package/dist/packages/core/src/domain/QualitySummary.js.map +1 -0
- package/dist/packages/core/src/domain/Sarif.js +121 -0
- package/dist/packages/core/src/domain/Sarif.js.map +1 -0
- package/dist/packages/core/src/infrastructure/GitContributionStager.js +1 -1
- package/dist/packages/core/src/infrastructure/GitContributionStager.js.map +1 -1
- package/dist/packages/core/src/infrastructure/HarnessConfigFile.js +21 -0
- package/dist/packages/core/src/infrastructure/HarnessConfigFile.js.map +1 -1
- package/dist/packages/core/src/infrastructure/QualityBaselineFile.js +67 -0
- package/dist/packages/core/src/infrastructure/QualityBaselineFile.js.map +1 -0
- package/dist/scripts/cli/commands/change/TicketCommand.js +1 -1
- package/dist/scripts/cli/commands/change/TicketCommand.js.map +1 -1
- package/dist/scripts/cli/commands/harness/RunCommand.js +212 -15
- package/dist/scripts/cli/commands/harness/RunCommand.js.map +1 -1
- package/dist/scripts/cli/commands/project/Forja.js +61 -5
- package/dist/scripts/cli/commands/project/Forja.js.map +1 -1
- package/dist/scripts/cli/commands/project/InitProjectCommand.js +7 -0
- package/dist/scripts/cli/commands/project/InitProjectCommand.js.map +1 -1
- package/dist/scripts/cli/commands/quality/CheckCommand.js +54 -3
- package/dist/scripts/cli/commands/quality/CheckCommand.js.map +1 -1
- package/dist/scripts/cli/commands/quality/QualityCommand.js +336 -0
- package/dist/scripts/cli/commands/quality/QualityCommand.js.map +1 -0
- package/dist/scripts/cli/commands/spec/DoneCommand.js +4 -1
- package/dist/scripts/cli/commands/spec/DoneCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/StudioCommand.js +14 -0
- package/dist/scripts/cli/commands/spec/StudioCommand.js.map +1 -1
- package/dist/scripts/docs/nav.js +13 -2
- package/dist/scripts/docs/nav.js.map +1 -1
- package/dist/scripts/harness/prompt.js +4 -0
- package/dist/scripts/harness/prompt.js.map +1 -1
- package/dist/scripts/harness/report.js +13 -0
- package/dist/scripts/harness/report.js.map +1 -1
- package/dist/scripts/lib/quality-presets.js +458 -0
- package/dist/scripts/lib/quality-presets.js.map +1 -0
- package/dist/scripts/lib/quality-run.js +595 -0
- package/dist/scripts/lib/quality-run.js.map +1 -0
- package/dist/scripts/lib/sonar-local.js +308 -0
- package/dist/scripts/lib/sonar-local.js.map +1 -0
- package/dist/scripts/lib/studio-app-page.js +74 -11
- package/dist/scripts/lib/studio-app-page.js.map +1 -1
- package/dist/scripts/lib/studio-app.js +80 -0
- package/dist/scripts/lib/studio-app.js.map +1 -1
- package/dist/scripts/lib/studio-route.js +64 -1
- package/dist/scripts/lib/studio-route.js.map +1 -1
- package/dist/scripts/lib/surface.js +11 -0
- package/dist/scripts/lib/surface.js.map +1 -1
- package/dist/scripts/lib/ticket-keys.js +1 -1
- package/dist/scripts/lib/ticket-keys.js.map +1 -1
- package/dist/scripts/quality.js +10 -0
- package/dist/scripts/quality.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.IMAGES = void 0;
|
|
37
|
+
exports.detectApps = detectApps;
|
|
38
|
+
exports.detectStacks = detectStacks;
|
|
39
|
+
exports.javaVersion = javaVersion;
|
|
40
|
+
exports.presetYaml = presetYaml;
|
|
41
|
+
exports.withPreset = withPreset;
|
|
42
|
+
const fs = __importStar(require("node:fs"));
|
|
43
|
+
const path = __importStar(require("node:path"));
|
|
44
|
+
/** Images, pinned. Refreshed with the presets, in a release. */
|
|
45
|
+
exports.IMAGES = {
|
|
46
|
+
gitleaks: "ghcr.io/gitleaks/gitleaks:v8.24.3",
|
|
47
|
+
semgrep: "semgrep/semgrep:1.99.0",
|
|
48
|
+
osv: "ghcr.io/google/osv-scanner:v2.2.4",
|
|
49
|
+
node: "node:22",
|
|
50
|
+
};
|
|
51
|
+
const read = (dir, rel) => {
|
|
52
|
+
try {
|
|
53
|
+
return fs.readFileSync(path.join(dir, rel), "utf8");
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return "";
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const STACKS = ["maven", "gradle", "node"];
|
|
60
|
+
const BUILD_FILES = {
|
|
61
|
+
maven: ["pom.xml"],
|
|
62
|
+
gradle: ["build.gradle", "build.gradle.kts", "settings.gradle", "settings.gradle.kts"],
|
|
63
|
+
node: ["package.json"],
|
|
64
|
+
};
|
|
65
|
+
const NOT_APPS = new Set(["node_modules", "target", "build", "dist", "docs", "features", "infra"]);
|
|
66
|
+
/** Folders one level down, and in apps/, packages/ and services/: where a monorepo keeps its apps. */
|
|
67
|
+
function appFolders(projectDir) {
|
|
68
|
+
const children = (rel) => {
|
|
69
|
+
try {
|
|
70
|
+
return fs
|
|
71
|
+
.readdirSync(path.join(projectDir, rel), { withFileTypes: true })
|
|
72
|
+
.filter((e) => e.isDirectory() && !e.name.startsWith(".") && !NOT_APPS.has(e.name))
|
|
73
|
+
.map((e) => (rel ? `${rel}/${e.name}` : e.name))
|
|
74
|
+
.sort();
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const top = children("");
|
|
81
|
+
const nested = ["apps", "packages", "services"].flatMap((d) => top.includes(d) ? children(d) : []);
|
|
82
|
+
return [...top, ...nested];
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Each stack with the folder it is built in (REQ-235). The root wins: a stack
|
|
86
|
+
* whose build file is at the root covers the whole repository (a Maven
|
|
87
|
+
* reactor, npm workspaces); otherwise each folder with that build file is an
|
|
88
|
+
* app of its own, such as forja's `apps/api`.
|
|
89
|
+
*/
|
|
90
|
+
function detectApps(projectDir) {
|
|
91
|
+
const has = (rel) => fs.existsSync(path.join(projectDir, rel));
|
|
92
|
+
const out = [];
|
|
93
|
+
const folders = appFolders(projectDir);
|
|
94
|
+
for (const stack of STACKS) {
|
|
95
|
+
const at = (dir) => BUILD_FILES[stack].some((f) => has(dir ? `${dir}/${f}` : f));
|
|
96
|
+
if (at(""))
|
|
97
|
+
out.push({ stack, dir: "" });
|
|
98
|
+
else
|
|
99
|
+
for (const dir of folders)
|
|
100
|
+
if (at(dir))
|
|
101
|
+
out.push({ stack, dir });
|
|
102
|
+
}
|
|
103
|
+
return out;
|
|
104
|
+
}
|
|
105
|
+
/** The stacks a project's build files give away, in the order presets are written. */
|
|
106
|
+
function detectStacks(projectDir) {
|
|
107
|
+
return [...new Set(detectApps(projectDir).map((a) => a.stack))];
|
|
108
|
+
}
|
|
109
|
+
/** The JDK a Java build declares (release, source or java.version), 21 when it says none. */
|
|
110
|
+
function javaVersion(projectDir) {
|
|
111
|
+
const text = `${read(projectDir, "pom.xml")}\n${read(projectDir, "build.gradle")}\n${read(projectDir, "build.gradle.kts")}`;
|
|
112
|
+
const m = /<maven\.compiler\.(?:release|source)>(\d+)</.exec(text) ||
|
|
113
|
+
/<java\.version>(\d+)</.exec(text) ||
|
|
114
|
+
/languageVersion\s*(?:=|\.set\()\s*JavaLanguageVersion\.of\((\d+)\)/.exec(text) ||
|
|
115
|
+
/sourceCompatibility\s*=\s*(?:JavaVersion\.VERSION_)?['"]?(\d+)/.exec(text);
|
|
116
|
+
const v = m ? Number(m[1]) : 21;
|
|
117
|
+
return [17, 21, 25].includes(v) ? v : v < 17 ? 17 : 21;
|
|
118
|
+
}
|
|
119
|
+
/** The lockfile and how to install in a node container. */
|
|
120
|
+
function nodeInstall(projectDir) {
|
|
121
|
+
const has = (rel) => fs.existsSync(path.join(projectDir, rel));
|
|
122
|
+
if (has("pnpm-lock.yaml"))
|
|
123
|
+
return {
|
|
124
|
+
lock: "pnpm-lock.yaml",
|
|
125
|
+
install: "corepack enable && pnpm install --frozen-lockfile --reporter=silent",
|
|
126
|
+
};
|
|
127
|
+
if (has("yarn.lock"))
|
|
128
|
+
return {
|
|
129
|
+
lock: "yarn.lock",
|
|
130
|
+
install: "corepack enable && yarn install --frozen-lockfile --silent",
|
|
131
|
+
};
|
|
132
|
+
return { lock: "package-lock.json", install: "npm ci --no-audit --no-fund --silent" };
|
|
133
|
+
}
|
|
134
|
+
const q = (s) => JSON.stringify(s);
|
|
135
|
+
function render(c) {
|
|
136
|
+
const lines = [
|
|
137
|
+
` - name: ${c.name}`,
|
|
138
|
+
` run: ${q(c.run)}`,
|
|
139
|
+
` when: ${c.when}`,
|
|
140
|
+
...(c.gate === false ? [" gate: false"] : []),
|
|
141
|
+
" runner: docker",
|
|
142
|
+
` image: ${c.image}`,
|
|
143
|
+
...(c.network === false ? [" network: false"] : []),
|
|
144
|
+
...(c.volumes && c.volumes.length ? [` volumes: [${c.volumes.join(", ")}]`] : []),
|
|
145
|
+
...(c.sarif ? [` sarif: ${c.sarif}`] : []),
|
|
146
|
+
...(c.report ? [` report: ${c.report}`] : []),
|
|
147
|
+
...(c.scope ? [` scope: ${c.scope}`] : []),
|
|
148
|
+
...(c.timeout ? [` timeout: ${c.timeout}`] : []),
|
|
149
|
+
...(c.docker ? [" docker: true"] : []),
|
|
150
|
+
...(c.needs ? [` needs: ${c.needs}`] : []),
|
|
151
|
+
];
|
|
152
|
+
return c.missing ? [` # ${c.missing}`, ...lines.map((l) => ` #${l.slice(1)}`)] : lines;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* The secrets and dependency checks every stack shares; `depsLock` is from the
|
|
156
|
+
* root, and `generated` when a check before it writes it (Maven's bill of materials).
|
|
157
|
+
*/
|
|
158
|
+
function shared(projectDir, level, depsLock, generated = false) {
|
|
159
|
+
// osv-scanner reads a lockfile (or pom.xml); without one it finds nothing to
|
|
160
|
+
// scan and writes no SARIF, so the check would fail on every run.
|
|
161
|
+
const lockMissing = !generated && !fs.existsSync(path.join(projectDir, depsLock))
|
|
162
|
+
? `Dependencies need ${depsLock}, which this project does not have yet; once it does, uncomment:`
|
|
163
|
+
: undefined;
|
|
164
|
+
return [
|
|
165
|
+
{
|
|
166
|
+
name: "secrets",
|
|
167
|
+
run: "gitleaks dir . --no-banner --report-format sarif --report-path .specgate/quality/gitleaks.sarif",
|
|
168
|
+
when: "attempt",
|
|
169
|
+
image: exports.IMAGES.gitleaks,
|
|
170
|
+
network: false,
|
|
171
|
+
sarif: ".specgate/quality/gitleaks.sarif",
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
name: "dependencies",
|
|
175
|
+
run: `/osv-scanner scan source -L ${depsLock} --format sarif --output .specgate/quality/osv.sarif`,
|
|
176
|
+
when: level === "strict" ? "attempt" : "end",
|
|
177
|
+
image: exports.IMAGES.osv,
|
|
178
|
+
sarif: ".specgate/quality/osv.sarif",
|
|
179
|
+
scope: "all",
|
|
180
|
+
missing: lockMissing,
|
|
181
|
+
},
|
|
182
|
+
];
|
|
183
|
+
}
|
|
184
|
+
/** A path of an app, from the root. */
|
|
185
|
+
const inApp = (dir, rel) => (dir ? `${dir}/${rel}` : rel);
|
|
186
|
+
/** A command of an app, run in its folder. */
|
|
187
|
+
const cdApp = (dir, cmd) => (dir ? `cd ${dir} && ${cmd}` : cmd);
|
|
188
|
+
/** Semgrep's rules for a stack: one scan carries every stack's (REQ-235). */
|
|
189
|
+
const SEMGREP_RULES = {
|
|
190
|
+
maven: ["p/java"],
|
|
191
|
+
gradle: ["p/java"],
|
|
192
|
+
node: ["p/typescript", "p/react"],
|
|
193
|
+
};
|
|
194
|
+
function semgrep(rules) {
|
|
195
|
+
return {
|
|
196
|
+
name: "semgrep",
|
|
197
|
+
run: `semgrep scan ${rules.map((r) => `--config ${r}`).join(" ")} --sarif --output .specgate/quality/semgrep.sarif --metrics off --quiet`,
|
|
198
|
+
when: "end",
|
|
199
|
+
image: exports.IMAGES.semgrep,
|
|
200
|
+
sarif: ".specgate/quality/semgrep.sarif",
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function maven(projectDir, level, dir = "") {
|
|
204
|
+
const appDir = path.join(projectDir, dir);
|
|
205
|
+
const pom = read(appDir, "pom.xml");
|
|
206
|
+
const image = `maven:3.9-eclipse-temurin-${javaVersion(appDir)}`;
|
|
207
|
+
const m2 = ["specgate-m2:/root/.m2"];
|
|
208
|
+
const mvn = "mvn -B -q";
|
|
209
|
+
// REQ-238: the tests start containers; they need the host's Docker.
|
|
210
|
+
const testcontainers = /org\.testcontainers/.test(pom);
|
|
211
|
+
// REQ-237: Maven resolves what a parent POM or a BOM manages, with its own
|
|
212
|
+
// repositories and cache; osv-scanner then reads that bill of materials.
|
|
213
|
+
const [secrets, dependencies] = shared(projectDir, level, inApp(dir, "target/bom.json"), true);
|
|
214
|
+
const checks = [
|
|
215
|
+
secrets,
|
|
216
|
+
{
|
|
217
|
+
name: "sbom",
|
|
218
|
+
run: cdApp(dir, `${mvn} org.cyclonedx:cyclonedx-maven-plugin:2.9.1:makeBom -DoutputFormat=json -DoutputName=bom`),
|
|
219
|
+
when: dependencies.when,
|
|
220
|
+
image,
|
|
221
|
+
volumes: m2,
|
|
222
|
+
},
|
|
223
|
+
{ ...dependencies, needs: "sbom" },
|
|
224
|
+
{
|
|
225
|
+
name: "coverage",
|
|
226
|
+
run: cdApp(dir, `${mvn} org.jacoco:jacoco-maven-plugin:0.8.12:prepare-agent test org.jacoco:jacoco-maven-plugin:0.8.12:report`),
|
|
227
|
+
when: "attempt",
|
|
228
|
+
image,
|
|
229
|
+
volumes: m2,
|
|
230
|
+
report: `jacoco:${inApp(dir, "target/site/jacoco/jacoco.xml")}`,
|
|
231
|
+
timeout: 1800,
|
|
232
|
+
docker: testcontainers,
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
name: "spotbugs",
|
|
236
|
+
run: cdApp(dir, `${mvn} compile com.github.spotbugs:spotbugs-maven-plugin:4.8.6.6:spotbugs -Dspotbugs.sarifOutput=true`),
|
|
237
|
+
when: level === "strict" ? "attempt" : "end",
|
|
238
|
+
image,
|
|
239
|
+
volumes: m2,
|
|
240
|
+
sarif: inApp(dir, "target/spotbugsSarif.json"),
|
|
241
|
+
},
|
|
242
|
+
];
|
|
243
|
+
if (level === "strict") {
|
|
244
|
+
checks.push({
|
|
245
|
+
name: "pmd",
|
|
246
|
+
run: cdApp(dir, `${mvn} org.apache.maven.plugins:maven-pmd-plugin:3.26.0:pmd -Dformat=net.sourceforge.pmd.renderers.SarifRenderer -DlinkXRef=false`),
|
|
247
|
+
when: "attempt",
|
|
248
|
+
image,
|
|
249
|
+
volumes: m2,
|
|
250
|
+
sarif: inApp(dir, "target/pmd.sarif.json"),
|
|
251
|
+
}, semgrep(SEMGREP_RULES.maven), {
|
|
252
|
+
name: "mutation",
|
|
253
|
+
run: cdApp(dir, `${mvn} test-compile org.pitest:pitest-maven:mutationCoverage -DtargetClasses=${dir ? `{changed_classes@${dir}}` : "{changed_classes}"} -DoutputFormats=XML -DtimestampedReports=false`),
|
|
254
|
+
when: "end",
|
|
255
|
+
image,
|
|
256
|
+
volumes: m2,
|
|
257
|
+
report: `pit:${inApp(dir, "target/pit-reports/mutations.xml")}`,
|
|
258
|
+
timeout: 3600,
|
|
259
|
+
docker: testcontainers,
|
|
260
|
+
missing: /pitest-maven/.test(pom)
|
|
261
|
+
? undefined
|
|
262
|
+
: "Mutation needs pitest-maven with pitest-junit5-plugin declared in pom.xml (JUnit 5 cannot be added from the command line); add them and uncomment:",
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
return checks;
|
|
266
|
+
}
|
|
267
|
+
function gradle(projectDir, level, dir = "") {
|
|
268
|
+
const appDir = path.join(projectDir, dir);
|
|
269
|
+
const build = `${read(appDir, "build.gradle")}\n${read(appDir, "build.gradle.kts")}`;
|
|
270
|
+
// osv-scanner reads Gradle's lockfile, not the build script: dependency locking must be on.
|
|
271
|
+
const lock = inApp(dir, "gradle.lockfile");
|
|
272
|
+
const image = `gradle:8-jdk${javaVersion(appDir)}`;
|
|
273
|
+
const cache = ["specgate-gradle:/home/gradle/.gradle"];
|
|
274
|
+
const checks = [
|
|
275
|
+
...shared(projectDir, level, lock),
|
|
276
|
+
{
|
|
277
|
+
name: "coverage",
|
|
278
|
+
run: cdApp(dir, "gradle --no-daemon -q test jacocoTestReport"),
|
|
279
|
+
when: "attempt",
|
|
280
|
+
image,
|
|
281
|
+
volumes: cache,
|
|
282
|
+
report: `jacoco:${inApp(dir, "build/reports/jacoco/test/jacocoTestReport.xml")}`,
|
|
283
|
+
docker: /org\.testcontainers/.test(build),
|
|
284
|
+
timeout: 1800,
|
|
285
|
+
missing: /\bjacoco\b/.test(build)
|
|
286
|
+
? undefined
|
|
287
|
+
: "Coverage needs the jacoco plugin applied, with reports { xml.required = true }; add it and uncomment:",
|
|
288
|
+
},
|
|
289
|
+
];
|
|
290
|
+
if (level === "strict")
|
|
291
|
+
checks.push(semgrep(SEMGREP_RULES.gradle));
|
|
292
|
+
return checks;
|
|
293
|
+
}
|
|
294
|
+
function node(projectDir, level, dir = "") {
|
|
295
|
+
const appDir = path.join(projectDir, dir);
|
|
296
|
+
let pkg = {};
|
|
297
|
+
try {
|
|
298
|
+
pkg = JSON.parse(read(appDir, "package.json") || "{}");
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
pkg = {};
|
|
302
|
+
}
|
|
303
|
+
const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
|
|
304
|
+
const { lock, install } = nodeInstall(appDir);
|
|
305
|
+
const slug = path
|
|
306
|
+
.basename(appDir)
|
|
307
|
+
.toLowerCase()
|
|
308
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
309
|
+
.replace(/^-|-$/g, "") || "project";
|
|
310
|
+
// node_modules lives in a volume: the host's may hold another platform's binaries.
|
|
311
|
+
const volumes = [
|
|
312
|
+
`specgate-nm-${slug}:/src/${inApp(dir, "node_modules")}`,
|
|
313
|
+
"specgate-npm:/root/.npm",
|
|
314
|
+
];
|
|
315
|
+
const inNode = (cmd) => cdApp(dir, `${install} && ${cmd}`);
|
|
316
|
+
const tsconfig = fs.existsSync(path.join(appDir, "tsconfig.json"));
|
|
317
|
+
const runner = deps.vitest ? "vitest" : deps.jest ? "jest" : "";
|
|
318
|
+
const checks = [...shared(projectDir, level, inApp(dir, lock))];
|
|
319
|
+
if (tsconfig) {
|
|
320
|
+
checks.push({
|
|
321
|
+
name: "types",
|
|
322
|
+
run: inNode("npx --no-install tsc --noEmit"),
|
|
323
|
+
when: "attempt",
|
|
324
|
+
image: exports.IMAGES.node,
|
|
325
|
+
volumes,
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
if (deps.eslint) {
|
|
329
|
+
checks.push({
|
|
330
|
+
name: "lint",
|
|
331
|
+
run: inNode("npx --no-install eslint ."),
|
|
332
|
+
when: "attempt",
|
|
333
|
+
image: exports.IMAGES.node,
|
|
334
|
+
volumes,
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
checks.push({
|
|
338
|
+
name: "coverage",
|
|
339
|
+
run: inNode(runner === "jest"
|
|
340
|
+
? "npx --no-install jest --coverage --coverageReporters=lcov"
|
|
341
|
+
: "npx --no-install vitest run --coverage --coverage.reporter=lcov"),
|
|
342
|
+
when: "attempt",
|
|
343
|
+
image: exports.IMAGES.node,
|
|
344
|
+
volumes,
|
|
345
|
+
report: `lcov:${inApp(dir, "coverage/lcov.info")}`,
|
|
346
|
+
timeout: 1800,
|
|
347
|
+
missing: runner
|
|
348
|
+
? runner === "vitest" && !deps["@vitest/coverage-v8"] && !deps["@vitest/coverage-istanbul"]
|
|
349
|
+
? "Coverage needs @vitest/coverage-v8 in devDependencies; add it and uncomment:"
|
|
350
|
+
: undefined
|
|
351
|
+
: "Coverage needs Vitest or Jest; with one installed, uncomment:",
|
|
352
|
+
});
|
|
353
|
+
if (level === "strict") {
|
|
354
|
+
checks.push(semgrep(SEMGREP_RULES.node), {
|
|
355
|
+
name: "mutation",
|
|
356
|
+
run: inNode(`npx --no-install stryker run --mutate ${dir ? `{changed_src@${dir}}` : "{changed_src}"} --reporters json`),
|
|
357
|
+
when: "end",
|
|
358
|
+
image: exports.IMAGES.node,
|
|
359
|
+
volumes,
|
|
360
|
+
report: `stryker:${inApp(dir, "reports/mutation/mutation.json")}`,
|
|
361
|
+
timeout: 3600,
|
|
362
|
+
missing: deps["@stryker-mutator/core"]
|
|
363
|
+
? undefined
|
|
364
|
+
: "Mutation needs @stryker-mutator/core and its runner in devDependencies; add them and uncomment:",
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
return checks;
|
|
368
|
+
}
|
|
369
|
+
/** The `quality:` block a level writes for a project, as YAML lines. */
|
|
370
|
+
function presetYaml(projectDir, level) {
|
|
371
|
+
const found = detectApps(projectDir);
|
|
372
|
+
const apps = found.length ? found : [{ stack: "node", dir: "" }];
|
|
373
|
+
// One Semgrep scan of the repository, with the rules of every stack in it.
|
|
374
|
+
const rules = [...new Set(apps.flatMap((a) => SEMGREP_RULES[a.stack]))];
|
|
375
|
+
const lines = [
|
|
376
|
+
"# Quality and security checks (ADR-0040), written by `specgate quality init`.",
|
|
377
|
+
"# Every check runs in Docker, with tools that need no account. Take the",
|
|
378
|
+
"# baseline once (`specgate quality baseline`) so only new findings fail.",
|
|
379
|
+
`quality: ${level}`,
|
|
380
|
+
"checks:",
|
|
381
|
+
// REQ-234: Specgate checks this itself — no tool, so no container either.
|
|
382
|
+
" - name: commits",
|
|
383
|
+
' run: "builtin:commits"',
|
|
384
|
+
" when: attempt",
|
|
385
|
+
" runner: local",
|
|
386
|
+
];
|
|
387
|
+
const sonar = [
|
|
388
|
+
" # SonarQube Community in Docker (REQ-226): starts a local server on first use",
|
|
389
|
+
" # (about 2 GB of memory) at http://127.0.0.1:9123, login admin/admin. Uncomment:",
|
|
390
|
+
" # - name: sonar",
|
|
391
|
+
' # run: "builtin:sonar"',
|
|
392
|
+
" # when: end",
|
|
393
|
+
" # runner: docker",
|
|
394
|
+
" # sarif: .specgate/quality/sonar.sarif",
|
|
395
|
+
" # timeout: 1800",
|
|
396
|
+
// REQ-227: a second agent reads the change against the requirement; it advises.
|
|
397
|
+
" - name: review",
|
|
398
|
+
' run: "builtin:review"',
|
|
399
|
+
" when: end",
|
|
400
|
+
" gate: false",
|
|
401
|
+
" runner: local",
|
|
402
|
+
];
|
|
403
|
+
const seen = new Set(["commits"]);
|
|
404
|
+
for (const { stack, dir } of apps) {
|
|
405
|
+
const checks = stack === "maven"
|
|
406
|
+
? maven(projectDir, level, dir)
|
|
407
|
+
: stack === "gradle"
|
|
408
|
+
? gradle(projectDir, level, dir)
|
|
409
|
+
: node(projectDir, level, dir);
|
|
410
|
+
for (const c of checks) {
|
|
411
|
+
// One secrets and one Semgrep scan for the whole repository; per-app
|
|
412
|
+
// checks get the stack's name, then the folder's when a stack repeats.
|
|
413
|
+
if (seen.has(c.name) && (c.name === "secrets" || c.name === "semgrep"))
|
|
414
|
+
continue;
|
|
415
|
+
let name = c.name;
|
|
416
|
+
if (seen.has(name))
|
|
417
|
+
name = `${c.name}-${stack}`;
|
|
418
|
+
if (seen.has(name) && dir)
|
|
419
|
+
name = `${c.name}-${path.basename(dir)}`;
|
|
420
|
+
seen.add(name);
|
|
421
|
+
let check = c.name === "semgrep" ? { ...semgrep(rules), name } : { ...c, name };
|
|
422
|
+
// A renamed check writes its own report: `osv.sarif` → `dependencies-node.sarif`.
|
|
423
|
+
if (name !== c.name && check.sarif && check.sarif.startsWith(".specgate/quality/")) {
|
|
424
|
+
const own = `.specgate/quality/${name}.sarif`;
|
|
425
|
+
check = { ...check, run: check.run.split(check.sarif).join(own), sarif: own };
|
|
426
|
+
}
|
|
427
|
+
lines.push(...render(check));
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
if (level === "strict")
|
|
431
|
+
lines.push(...sonar);
|
|
432
|
+
return lines.join("\n") + "\n";
|
|
433
|
+
}
|
|
434
|
+
/** Keys the quality block owns in harness.config.yaml. */
|
|
435
|
+
const OWNED = ["quality", "diff_coverage", "mutation_score", "checks"];
|
|
436
|
+
/**
|
|
437
|
+
* harness.config.yaml with its quality block replaced by this one: every
|
|
438
|
+
* other line kept, the block's own comment lines dropped with it.
|
|
439
|
+
*/
|
|
440
|
+
function withPreset(config, preset) {
|
|
441
|
+
const lines = config.replace(/\r\n/g, "\n").split("\n");
|
|
442
|
+
const out = [];
|
|
443
|
+
let skipping = false;
|
|
444
|
+
for (const line of lines) {
|
|
445
|
+
const top = /^([a-z_]+):/.exec(line);
|
|
446
|
+
if (top)
|
|
447
|
+
skipping = OWNED.includes(top[1]);
|
|
448
|
+
else if (skipping && !/^(\s|#|$)/.test(line))
|
|
449
|
+
skipping = false;
|
|
450
|
+
if (skipping)
|
|
451
|
+
continue;
|
|
452
|
+
if (/^# (Quality and security checks|Every check runs in Docker|baseline once)/.test(line))
|
|
453
|
+
continue;
|
|
454
|
+
out.push(line);
|
|
455
|
+
}
|
|
456
|
+
return `${out.join("\n").trimEnd()}\n\n${preset}`;
|
|
457
|
+
}
|
|
458
|
+
//# sourceMappingURL=quality-presets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality-presets.js","sourceRoot":"","sources":["../../../scripts/lib/quality-presets.ts"],"names":[],"mappings":"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"}
|