@rsaglobaltech/specgate 0.25.0 → 0.27.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/CHANGELOG.md +87 -42
- package/README.md +6 -0
- package/dist/packages/core/src/domain/AgentPrompt.js +12 -0
- package/dist/packages/core/src/domain/AgentPrompt.js.map +1 -1
- 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/Clarification.js +5 -0
- package/dist/packages/core/src/domain/Clarification.js.map +1 -1
- 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 +218 -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/RequirementPlan.js +11 -0
- package/dist/packages/core/src/domain/RequirementPlan.js.map +1 -1
- 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/ChangeWorkspace.js +15 -3
- package/dist/packages/core/src/infrastructure/ChangeWorkspace.js.map +1 -1
- 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 +26 -0
- package/dist/packages/core/src/infrastructure/HarnessConfigFile.js.map +1 -1
- package/dist/packages/core/src/infrastructure/IdsAcrossBranches.js +4 -1
- package/dist/packages/core/src/infrastructure/IdsAcrossBranches.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/packages/core/test/unit/rework.test.js +62 -0
- package/dist/packages/core/test/unit/rework.test.js.map +1 -0
- package/dist/scripts/cli/commands/change/ChangeCommand.js +38 -1
- package/dist/scripts/cli/commands/change/ChangeCommand.js.map +1 -1
- 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 +269 -17
- package/dist/scripts/cli/commands/harness/RunCommand.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 +314 -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/DraftCommand.js +44 -4
- package/dist/scripts/cli/commands/spec/DraftCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/StatusCommand.js +5 -1
- package/dist/scripts/cli/commands/spec/StatusCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/StudioCommand.js +208 -1
- 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/docs/record-journey.js +1 -0
- package/dist/scripts/docs/record-journey.js.map +1 -1
- package/dist/scripts/docs/record-terminal.js +18 -0
- package/dist/scripts/docs/record-terminal.js.map +1 -1
- package/dist/scripts/draft/drafting-guide.js +11 -1
- package/dist/scripts/draft/drafting-guide.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/change-review.js +145 -0
- package/dist/scripts/lib/change-review.js.map +1 -0
- package/dist/scripts/lib/clarification.js +24 -5
- package/dist/scripts/lib/clarification.js.map +1 -1
- package/dist/scripts/lib/harness-guard.js +18 -0
- package/dist/scripts/lib/harness-guard.js.map +1 -1
- package/dist/scripts/lib/in-flight.js +17 -11
- package/dist/scripts/lib/in-flight.js.map +1 -1
- package/dist/scripts/lib/live-model.js +7 -1
- package/dist/scripts/lib/live-model.js.map +1 -1
- package/dist/scripts/lib/live-page.js +72 -11
- package/dist/scripts/lib/live-page.js.map +1 -1
- package/dist/scripts/lib/quality-presets.js +378 -0
- package/dist/scripts/lib/quality-presets.js.map +1 -0
- package/dist/scripts/lib/quality-run.js +579 -0
- package/dist/scripts/lib/quality-run.js.map +1 -0
- package/dist/scripts/lib/screen-requirements.js +149 -0
- package/dist/scripts/lib/screen-requirements.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 +1023 -0
- package/dist/scripts/lib/studio-app-page.js.map +1 -0
- package/dist/scripts/lib/studio-app.js +442 -0
- package/dist/scripts/lib/studio-app.js.map +1 -0
- package/dist/scripts/lib/studio-route.js +996 -0
- package/dist/scripts/lib/studio-route.js.map +1 -0
- 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
- package/templates/harness/harness.config.yaml.tpl +10 -1
|
@@ -25,12 +25,13 @@ exports.livePage = livePage;
|
|
|
25
25
|
* The script lives inside this template literal: it uses no backticks, no
|
|
26
26
|
* dollar-brace, and no backslash escapes.
|
|
27
27
|
*/
|
|
28
|
-
function livePage(projectName) {
|
|
28
|
+
function livePage(projectName, token = "") {
|
|
29
29
|
const title = String(projectName).replace(/[&<>"']/g, "");
|
|
30
30
|
return `<!doctype html>
|
|
31
31
|
<html lang="en"><head><meta charset="utf-8"/>
|
|
32
32
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
33
33
|
<title>Harness live — ${title}</title>
|
|
34
|
+
<meta name="specgate-token" content="${String(token).replace(/[^0-9a-f]/g, "")}"/>
|
|
34
35
|
<style>
|
|
35
36
|
:root{--bg:#f6f8fa;--panel:#ffffff;--line:#d1d9e0;--soft:#eff2f5;--ink:#1f2328;--muted:#59636e;--faint:#8c959f;
|
|
36
37
|
--pass:#1a7f37;--fail:#cf222e;--run:#9a6700;--run-bg:#fff8c5;--accent:#0969da;--sel:#ddf4ff;
|
|
@@ -65,8 +66,12 @@ function livePage(projectName) {
|
|
|
65
66
|
.summary-btn{padding-left:10px;margin-bottom:6px;font-weight:600}
|
|
66
67
|
.qsec{margin:10px 0 14px} .qsec h2{display:flex;align-items:center;gap:8px;margin:0 0 4px;padding:0 10px;font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.04em}
|
|
67
68
|
.qsec h2 .count{margin-left:auto;font-weight:400;font-variant-numeric:tabular-nums} .qsec .job{padding-left:10px;align-items:flex-start}
|
|
68
|
-
.qsec .job .ic{margin-top:3px} .job small{display:block;font-size:11.5px;color:var(--muted);font-weight:400}
|
|
69
|
+
.qsec .job .ic{margin-top:3px} .job small{display:block;font-size:11.5px;color:var(--muted);font-weight:400;white-space:normal;overflow-wrap:anywhere}
|
|
69
70
|
.qsec p{margin:2px 10px 6px;font-size:12.5px} .muted{color:var(--muted)}
|
|
71
|
+
form.answer{display:flex;flex-wrap:wrap;gap:6px;margin:2px 10px 10px 30px} form.answer textarea{flex:1 1 100%;font:inherit;font-size:12.5px;padding:6px 8px;border:1px solid var(--line);border-radius:6px;background:var(--panel);color:var(--ink);resize:vertical}
|
|
72
|
+
.oq{margin:4px 10px 12px} .oqh{font-size:12.5px} .oqh b{font-weight:600} .oqt{font-size:13px;margin:2px 0 4px;overflow-wrap:anywhere}
|
|
73
|
+
.oq form.answer{margin:0}
|
|
74
|
+
form.answer button{border:1px solid var(--line);background:var(--soft);border-radius:6px;padding:3px 10px;cursor:pointer;font-size:12.5px} form.answer small{flex:1 1 100%}
|
|
70
75
|
.now{border:1px solid var(--run);border-radius:6px;padding:4px 0 8px;background:var(--panel)}
|
|
71
76
|
.kv{display:grid;grid-template-columns:62px minmax(0,1fr);gap:4px 10px;margin:4px 10px 0;font-size:12.5px} .kv dt{color:var(--muted)} .kv dd{margin:0;min-width:0;overflow-wrap:anywhere}
|
|
72
77
|
.ctx{display:flex;flex-direction:column;gap:3px} .ctx .d{font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums}
|
|
@@ -256,6 +261,41 @@ function livePage(projectName) {
|
|
|
256
261
|
b.addEventListener("click", function(){ pick(r.req); });
|
|
257
262
|
return b;
|
|
258
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* Answer the agent's question from here (REQ-201): the same write as
|
|
266
|
+
* specgate answer, through studio's one POST, with this page's token.
|
|
267
|
+
*/
|
|
268
|
+
function answerForm(q){
|
|
269
|
+
var f = el("form", "answer"), ta = el("textarea"), go = el("button", "", "Answer"), msg = el("small", "muted");
|
|
270
|
+
ta.placeholder = "Your answer to " + q.id; ta.rows = 2; go.type = "submit";
|
|
271
|
+
f.append(ta, go, msg);
|
|
272
|
+
var post = function(body){
|
|
273
|
+
var tok = (document.querySelector('meta[name="specgate-token"]') || {}).content || "";
|
|
274
|
+
return fetch("live/answer", {method:"POST", headers:{"content-type":"application/json", "x-specgate-token":tok}, body:JSON.stringify(body)})
|
|
275
|
+
.then(function(x){ return x.json(); });
|
|
276
|
+
};
|
|
277
|
+
f.addEventListener("submit", function(ev){
|
|
278
|
+
ev.preventDefault();
|
|
279
|
+
if (!ta.value.trim()) return;
|
|
280
|
+
go.disabled = true;
|
|
281
|
+
post({question:q.id, change:q.change === "project" ? undefined : q.change, answer:ta.value}).then(function(r){
|
|
282
|
+
go.disabled = false;
|
|
283
|
+
if (!r.ok) { msg.textContent = r.message || "Not answered."; return; }
|
|
284
|
+
msg.textContent = q.id + " answered; " + r.assumption + " to review" + (r.revise && r.revise.length ? " — revise " + r.revise.join(", ") : "") + ".";
|
|
285
|
+
ta.remove(); go.remove();
|
|
286
|
+
var rv = el("button", "", "Mark reviewed"); rv.type = "button";
|
|
287
|
+
rv.addEventListener("click", function(){
|
|
288
|
+
post({question:q.id, change:q.change === "project" ? undefined : q.change, reviewed:true}).then(function(x){
|
|
289
|
+
msg.textContent = x.ok ? q.id + " reviewed: the specification reflects it." : (x.message || "Not reviewed.");
|
|
290
|
+
if (x.ok) rv.remove();
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
f.appendChild(rv);
|
|
294
|
+
}).catch(function(){ go.disabled = false; msg.textContent = "Studio did not answer."; });
|
|
295
|
+
});
|
|
296
|
+
return f;
|
|
297
|
+
}
|
|
298
|
+
|
|
259
299
|
function block(title, count){
|
|
260
300
|
var d = el("section", "qsec"), h = el("h2"); h.append(el("span", "", title));
|
|
261
301
|
if (count !== undefined) h.appendChild(el("span", "count", String(count)));
|
|
@@ -299,7 +339,7 @@ function livePage(projectName) {
|
|
|
299
339
|
matrix.forEach(function(m){ if (m.status === "Needs Clarification" && !byReq[m.requirement] && !seenB[m.requirement]) { seenB[m.requirement] = 1;
|
|
300
340
|
need.push({r:{req:m.requirement, title:m.title, state:"idle"}, note:"blocked · needs clarification", st:"idle"}); } });
|
|
301
341
|
var n1 = block("Needs attention", need.length);
|
|
302
|
-
need.forEach(function(x){ n1.appendChild(jobBtn(x.r, sel, x.note, x.st)); });
|
|
342
|
+
need.forEach(function(x){ n1.appendChild(jobBtn(x.r, sel, x.note, x.st)); if (x.st === "question" && x.r.question && x.r.question.id) n1.appendChild(answerForm(x.r.question)); });
|
|
303
343
|
if (!need.length) n1.appendChild(el("p", "muted", "Nothing failed or blocked."));
|
|
304
344
|
box.appendChild(n1);
|
|
305
345
|
|
|
@@ -314,6 +354,26 @@ function livePage(projectName) {
|
|
|
314
354
|
if (!next.length) n2.appendChild(el("p", "muted", (model.queue || []).length ? "The queue is done." : "No queue recorded for this run."));
|
|
315
355
|
box.appendChild(n2);
|
|
316
356
|
|
|
357
|
+
// REQ-203: every open question, not only the agent's, answered from here.
|
|
358
|
+
var shown = {};
|
|
359
|
+
need.forEach(function(x){ if (x.r.question && x.r.question.id) shown[x.r.question.change + ":" + x.r.question.id] = 1; });
|
|
360
|
+
var oq = (model.questions && model.questions.open || []).filter(function(q){ return !shown[q.change + ":" + q.id]; });
|
|
361
|
+
var wq = model.questions && model.questions.waitingWithoutQuestion || [];
|
|
362
|
+
var n4 = block("Open questions", oq.length + wq.length);
|
|
363
|
+
oq.forEach(function(q){
|
|
364
|
+
var row = el("div", "oq"), h = el("div", "oqh");
|
|
365
|
+
h.append(el("b", "", q.id), el("span", "muted", " " + (q.change === "project" ? "project" : q.change) + (q.blocks.length ? " · blocks " + q.blocks.join(", ") : "")));
|
|
366
|
+
row.append(h, el("div", "oqt", q.text), answerForm(q));
|
|
367
|
+
n4.appendChild(row);
|
|
368
|
+
});
|
|
369
|
+
wq.forEach(function(r){
|
|
370
|
+
var row = el("div", "oq");
|
|
371
|
+
row.append(el("div", "oqh", r.requirement + " " + (r.title || "")), el("small", "muted", "Needs Clarification with no question: specgate ask " + r.requirement + ' "…"'));
|
|
372
|
+
n4.appendChild(row);
|
|
373
|
+
});
|
|
374
|
+
if (!oq.length && !wq.length) n4.appendChild(el("p", "muted", "Nothing waits for an answer."));
|
|
375
|
+
box.appendChild(n4);
|
|
376
|
+
|
|
317
377
|
var recent = list.filter(function(r){ return r.state === "pass"; }).sort(function(a, b){ return b.updated - a.updated; }).slice(0, 5);
|
|
318
378
|
var n3 = block("Finished recently");
|
|
319
379
|
recent.forEach(function(r){ n3.appendChild(jobBtn(r, sel, dur(r.elapsed) + (r.usage && r.usage.cost !== null ? " · " + usd(r.usage.cost) : ""), "pass")); });
|
|
@@ -323,17 +383,18 @@ function livePage(projectName) {
|
|
|
323
383
|
}
|
|
324
384
|
|
|
325
385
|
function summary(list){
|
|
326
|
-
var p = 0, f = 0, run = 0, first = 0, last = 0;
|
|
327
|
-
|
|
386
|
+
var p = 0, f = 0, run = 0, asks = 0, first = 0, last = 0;
|
|
387
|
+
// A question waits for a person: neither a failure nor work in progress (REQ-201).
|
|
388
|
+
list.forEach(function(r){ if (r.state === "pass") p++; else if (r.state === "fail") f++; else if (r.state === "question") asks++; else run++;
|
|
328
389
|
if (!first || r.started < first) first = r.started; last = Math.max(last, r.state === "running" ? now() : r.updated); });
|
|
329
|
-
var state = run ? "running" : f ? "fail" : list.length ? "pass" : "running";
|
|
390
|
+
var state = run ? "running" : f ? "fail" : asks ? "running" : list.length ? "pass" : "running";
|
|
330
391
|
$("runBadge").className = "badge " + state;
|
|
331
|
-
$("runState").textContent = run ? "In progress" : f ? "Failed" : list.length ? "Completed" : "Waiting";
|
|
392
|
+
$("runState").textContent = run ? "In progress" : f ? "Failed" : asks ? "Waiting for an answer" : list.length ? "Completed" : "Waiting";
|
|
332
393
|
var cur = list.filter(function(r){ return r.state === "running"; })[0];
|
|
333
394
|
$("runTitle").textContent = cur ? cap(cur.group) + " · " + cur.req + " " + (cur.title || "") : groups(list).map(function(g){ return cap(g.name); }).join(", ") || "Harness run";
|
|
334
395
|
var box = $("progress"); box.replaceChildren();
|
|
335
396
|
[["Started", first ? stamp(first) : "—"], ["Duration", first ? dur(last - first) : "—"],
|
|
336
|
-
["Requirements", p + " passed · " + run + " running · " + f + " failed"],
|
|
397
|
+
["Requirements", p + " passed · " + run + " running · " + f + " failed" + (asks ? " · " + asks + " waiting for an answer" : "")],
|
|
337
398
|
["Agent time", dur(list.reduce(function(a, r){ return a + elapsed(r); }, 0))]].concat(model.totals && (model.totals.input || model.totals.output) ? [
|
|
338
399
|
["Tokens", kt(model.totals.input + model.totals.cacheRead + model.totals.cacheWrite) + " in · " + kt(model.totals.output) + " out"],
|
|
339
400
|
["Cost", usd(model.totals.cost)]] : []).forEach(function(x){
|
|
@@ -368,12 +429,12 @@ function livePage(projectName) {
|
|
|
368
429
|
["", "Module", "Requirements", "Passed", "Time"].forEach(function(h, i){ var c = el("span", i >= 3 ? "num" : "", h); head.appendChild(c); });
|
|
369
430
|
box.appendChild(head);
|
|
370
431
|
order.forEach(function(g){
|
|
371
|
-
var rs = rowsBy[g], pass = 0, fail = 0, run = 0, time = 0;
|
|
432
|
+
var rs = rowsBy[g], pass = 0, fail = 0, run = 0, asked = 0, time = 0;
|
|
372
433
|
var row = el("div", "mm-row"), bar = el("span", "mm-bar");
|
|
373
434
|
rs.forEach(function(q){
|
|
374
435
|
var ev = byReq[q.req], st = ev ? ev.state : (q.status === "Implemented" || q.status === "Verified" || q.status === "Released") ? "pass"
|
|
375
436
|
: q.status === "Needs Clarification" ? "blocked" : "queued";
|
|
376
|
-
if (st === "pass") pass++; else if (st === "fail"
|
|
437
|
+
if (st === "pass") pass++; else if (st === "fail") fail++; else if (st === "running") run++; else if (st === "question") asked++;
|
|
377
438
|
if (ev) time += elapsed(ev);
|
|
378
439
|
var seg = el("button", "seg " + st + (sel && sel.req === q.req ? " on" : "")); seg.type = "button";
|
|
379
440
|
seg.title = q.req + " — " + (q.title || "") + " · " + (ev ? st + " · " + dur(elapsed(ev)) : st);
|
|
@@ -381,7 +442,7 @@ function livePage(projectName) {
|
|
|
381
442
|
seg.addEventListener("click", function(){ pick(q.req); });
|
|
382
443
|
bar.appendChild(seg);
|
|
383
444
|
});
|
|
384
|
-
var state = fail ? "fail" : run ? "running" : pass === rs.length ? "pass" : "idle";
|
|
445
|
+
var state = fail ? "fail" : asked ? "question" : run ? "running" : pass === rs.length ? "pass" : "idle";
|
|
385
446
|
if (fail) row.classList.add("has-fail"); else if (run) row.classList.add("has-run"); else if (state === "idle" && !pass) row.classList.add("queued");
|
|
386
447
|
row.append(icon(state), el("b", "", cap(g === "spec" ? "" : g)), bar, el("span", "num", pass + "/" + rs.length), el("span", "num muted", time ? dur(time) : pass === rs.length ? "earlier" : "queued"));
|
|
387
448
|
box.appendChild(row);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-page.js","sourceRoot":"","sources":["../../../scripts/lib/live-page.ts"],"names":[],"mappings":";;AAwBA,
|
|
1
|
+
{"version":3,"file":"live-page.js","sourceRoot":"","sources":["../../../scripts/lib/live-page.ts"],"names":[],"mappings":";;AAwBA,4BAipBC;AAzqBD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,SAAgB,QAAQ,CAAC,WAAmB,EAAE,KAAK,GAAG,EAAE;IACtD,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC1D,OAAO;;;wBAGe,KAAK;uCACU,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBAmH9D,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAuhBN,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,378 @@
|
|
|
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.detectStacks = detectStacks;
|
|
38
|
+
exports.javaVersion = javaVersion;
|
|
39
|
+
exports.presetYaml = presetYaml;
|
|
40
|
+
exports.withPreset = withPreset;
|
|
41
|
+
const fs = __importStar(require("node:fs"));
|
|
42
|
+
const path = __importStar(require("node:path"));
|
|
43
|
+
/** Images, pinned. Refreshed with the presets, in a release. */
|
|
44
|
+
exports.IMAGES = {
|
|
45
|
+
gitleaks: "ghcr.io/gitleaks/gitleaks:v8.24.3",
|
|
46
|
+
semgrep: "semgrep/semgrep:1.99.0",
|
|
47
|
+
osv: "ghcr.io/google/osv-scanner:v2.0.2",
|
|
48
|
+
node: "node:22",
|
|
49
|
+
};
|
|
50
|
+
const read = (dir, rel) => {
|
|
51
|
+
try {
|
|
52
|
+
return fs.readFileSync(path.join(dir, rel), "utf8");
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return "";
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
/** The stacks a project's build files give away, in the order presets are written. */
|
|
59
|
+
function detectStacks(projectDir) {
|
|
60
|
+
const has = (rel) => fs.existsSync(path.join(projectDir, rel));
|
|
61
|
+
const out = [];
|
|
62
|
+
if (has("pom.xml"))
|
|
63
|
+
out.push("maven");
|
|
64
|
+
if (has("build.gradle") || has("build.gradle.kts"))
|
|
65
|
+
out.push("gradle");
|
|
66
|
+
if (has("package.json"))
|
|
67
|
+
out.push("node");
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
/** The JDK a Java build declares (release, source or java.version), 21 when it says none. */
|
|
71
|
+
function javaVersion(projectDir) {
|
|
72
|
+
const text = `${read(projectDir, "pom.xml")}\n${read(projectDir, "build.gradle")}\n${read(projectDir, "build.gradle.kts")}`;
|
|
73
|
+
const m = /<maven\.compiler\.(?:release|source)>(\d+)</.exec(text) ||
|
|
74
|
+
/<java\.version>(\d+)</.exec(text) ||
|
|
75
|
+
/languageVersion\s*(?:=|\.set\()\s*JavaLanguageVersion\.of\((\d+)\)/.exec(text) ||
|
|
76
|
+
/sourceCompatibility\s*=\s*(?:JavaVersion\.VERSION_)?['"]?(\d+)/.exec(text);
|
|
77
|
+
const v = m ? Number(m[1]) : 21;
|
|
78
|
+
return [17, 21, 25].includes(v) ? v : v < 17 ? 17 : 21;
|
|
79
|
+
}
|
|
80
|
+
/** The lockfile and how to install in a node container. */
|
|
81
|
+
function nodeInstall(projectDir) {
|
|
82
|
+
const has = (rel) => fs.existsSync(path.join(projectDir, rel));
|
|
83
|
+
if (has("pnpm-lock.yaml"))
|
|
84
|
+
return {
|
|
85
|
+
lock: "pnpm-lock.yaml",
|
|
86
|
+
install: "corepack enable && pnpm install --frozen-lockfile --reporter=silent",
|
|
87
|
+
};
|
|
88
|
+
if (has("yarn.lock"))
|
|
89
|
+
return {
|
|
90
|
+
lock: "yarn.lock",
|
|
91
|
+
install: "corepack enable && yarn install --frozen-lockfile --silent",
|
|
92
|
+
};
|
|
93
|
+
return { lock: "package-lock.json", install: "npm ci --no-audit --no-fund --silent" };
|
|
94
|
+
}
|
|
95
|
+
const q = (s) => JSON.stringify(s);
|
|
96
|
+
function render(c) {
|
|
97
|
+
const lines = [
|
|
98
|
+
` - name: ${c.name}`,
|
|
99
|
+
` run: ${q(c.run)}`,
|
|
100
|
+
` when: ${c.when}`,
|
|
101
|
+
...(c.gate === false ? [" gate: false"] : []),
|
|
102
|
+
" runner: docker",
|
|
103
|
+
` image: ${c.image}`,
|
|
104
|
+
...(c.network === false ? [" network: false"] : []),
|
|
105
|
+
...(c.volumes && c.volumes.length ? [` volumes: [${c.volumes.join(", ")}]`] : []),
|
|
106
|
+
...(c.sarif ? [` sarif: ${c.sarif}`] : []),
|
|
107
|
+
...(c.report ? [` report: ${c.report}`] : []),
|
|
108
|
+
...(c.scope ? [` scope: ${c.scope}`] : []),
|
|
109
|
+
...(c.timeout ? [` timeout: ${c.timeout}`] : []),
|
|
110
|
+
];
|
|
111
|
+
return c.missing ? [` # ${c.missing}`, ...lines.map((l) => ` #${l.slice(1)}`)] : lines;
|
|
112
|
+
}
|
|
113
|
+
/** The secrets and dependency checks every stack shares. */
|
|
114
|
+
function shared(projectDir, level, depsLock) {
|
|
115
|
+
// osv-scanner reads a lockfile (or pom.xml); without one it finds nothing to
|
|
116
|
+
// scan and writes no SARIF, so the check would fail on every run.
|
|
117
|
+
const lockMissing = !fs.existsSync(path.join(projectDir, depsLock))
|
|
118
|
+
? `Dependencies need ${depsLock}, which this project does not have yet; once it does, uncomment:`
|
|
119
|
+
: undefined;
|
|
120
|
+
return [
|
|
121
|
+
{
|
|
122
|
+
name: "secrets",
|
|
123
|
+
run: "gitleaks dir . --no-banner --report-format sarif --report-path .specgate/quality/gitleaks.sarif",
|
|
124
|
+
when: "attempt",
|
|
125
|
+
image: exports.IMAGES.gitleaks,
|
|
126
|
+
network: false,
|
|
127
|
+
sarif: ".specgate/quality/gitleaks.sarif",
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: "dependencies",
|
|
131
|
+
run: `/osv-scanner scan source -L ${depsLock} --format sarif --output .specgate/quality/osv.sarif`,
|
|
132
|
+
when: level === "strict" ? "attempt" : "end",
|
|
133
|
+
image: exports.IMAGES.osv,
|
|
134
|
+
sarif: ".specgate/quality/osv.sarif",
|
|
135
|
+
scope: "all",
|
|
136
|
+
missing: lockMissing,
|
|
137
|
+
},
|
|
138
|
+
];
|
|
139
|
+
}
|
|
140
|
+
function maven(projectDir, level) {
|
|
141
|
+
const pom = read(projectDir, "pom.xml");
|
|
142
|
+
const image = `maven:3.9-eclipse-temurin-${javaVersion(projectDir)}`;
|
|
143
|
+
const m2 = ["specgate-m2:/root/.m2"];
|
|
144
|
+
const mvn = "mvn -B -q";
|
|
145
|
+
const checks = [
|
|
146
|
+
...shared(projectDir, level, "pom.xml"),
|
|
147
|
+
{
|
|
148
|
+
name: "coverage",
|
|
149
|
+
run: `${mvn} org.jacoco:jacoco-maven-plugin:0.8.12:prepare-agent test org.jacoco:jacoco-maven-plugin:0.8.12:report`,
|
|
150
|
+
when: "attempt",
|
|
151
|
+
image,
|
|
152
|
+
volumes: m2,
|
|
153
|
+
report: "jacoco:target/site/jacoco/jacoco.xml",
|
|
154
|
+
timeout: 1800,
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: "spotbugs",
|
|
158
|
+
run: `${mvn} compile com.github.spotbugs:spotbugs-maven-plugin:4.8.6.6:spotbugs -Dspotbugs.sarifOutput=true`,
|
|
159
|
+
when: level === "strict" ? "attempt" : "end",
|
|
160
|
+
image,
|
|
161
|
+
volumes: m2,
|
|
162
|
+
sarif: "target/spotbugsSarif.json",
|
|
163
|
+
},
|
|
164
|
+
];
|
|
165
|
+
if (level === "strict") {
|
|
166
|
+
checks.push({
|
|
167
|
+
name: "pmd",
|
|
168
|
+
run: `${mvn} org.apache.maven.plugins:maven-pmd-plugin:3.26.0:pmd -Dformat=net.sourceforge.pmd.renderers.SarifRenderer -DlinkXRef=false`,
|
|
169
|
+
when: "attempt",
|
|
170
|
+
image,
|
|
171
|
+
volumes: m2,
|
|
172
|
+
sarif: "target/pmd.sarif.json",
|
|
173
|
+
}, {
|
|
174
|
+
name: "semgrep",
|
|
175
|
+
run: "semgrep scan --config p/java --sarif --output .specgate/quality/semgrep.sarif --metrics off --quiet",
|
|
176
|
+
when: "end",
|
|
177
|
+
image: exports.IMAGES.semgrep,
|
|
178
|
+
sarif: ".specgate/quality/semgrep.sarif",
|
|
179
|
+
}, {
|
|
180
|
+
name: "mutation",
|
|
181
|
+
run: `${mvn} test-compile org.pitest:pitest-maven:mutationCoverage -DtargetClasses={changed_classes} -DoutputFormats=XML -DtimestampedReports=false`,
|
|
182
|
+
when: "end",
|
|
183
|
+
image,
|
|
184
|
+
volumes: m2,
|
|
185
|
+
report: "pit:target/pit-reports/mutations.xml",
|
|
186
|
+
timeout: 3600,
|
|
187
|
+
missing: /pitest-maven/.test(pom)
|
|
188
|
+
? undefined
|
|
189
|
+
: "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:",
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
return checks;
|
|
193
|
+
}
|
|
194
|
+
function gradle(projectDir, level) {
|
|
195
|
+
const build = `${read(projectDir, "build.gradle")}\n${read(projectDir, "build.gradle.kts")}`;
|
|
196
|
+
// osv-scanner reads Gradle's lockfile, not the build script: dependency locking must be on.
|
|
197
|
+
const lock = "gradle.lockfile";
|
|
198
|
+
const image = `gradle:8-jdk${javaVersion(projectDir)}`;
|
|
199
|
+
const cache = ["specgate-gradle:/home/gradle/.gradle"];
|
|
200
|
+
const checks = [
|
|
201
|
+
...shared(projectDir, level, lock),
|
|
202
|
+
{
|
|
203
|
+
name: "coverage",
|
|
204
|
+
run: "gradle --no-daemon -q test jacocoTestReport",
|
|
205
|
+
when: "attempt",
|
|
206
|
+
image,
|
|
207
|
+
volumes: cache,
|
|
208
|
+
report: "jacoco:build/reports/jacoco/test/jacocoTestReport.xml",
|
|
209
|
+
timeout: 1800,
|
|
210
|
+
missing: /\bjacoco\b/.test(build)
|
|
211
|
+
? undefined
|
|
212
|
+
: "Coverage needs the jacoco plugin applied, with reports { xml.required = true }; add it and uncomment:",
|
|
213
|
+
},
|
|
214
|
+
];
|
|
215
|
+
if (level === "strict") {
|
|
216
|
+
checks.push({
|
|
217
|
+
name: "semgrep",
|
|
218
|
+
run: "semgrep scan --config p/java --sarif --output .specgate/quality/semgrep.sarif --metrics off --quiet",
|
|
219
|
+
when: "end",
|
|
220
|
+
image: exports.IMAGES.semgrep,
|
|
221
|
+
sarif: ".specgate/quality/semgrep.sarif",
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
return checks;
|
|
225
|
+
}
|
|
226
|
+
function node(projectDir, level) {
|
|
227
|
+
let pkg = {};
|
|
228
|
+
try {
|
|
229
|
+
pkg = JSON.parse(read(projectDir, "package.json") || "{}");
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
pkg = {};
|
|
233
|
+
}
|
|
234
|
+
const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
|
|
235
|
+
const { lock, install } = nodeInstall(projectDir);
|
|
236
|
+
const slug = path
|
|
237
|
+
.basename(projectDir)
|
|
238
|
+
.toLowerCase()
|
|
239
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
240
|
+
.replace(/^-|-$/g, "") || "project";
|
|
241
|
+
// node_modules lives in a volume: the host's may hold another platform's binaries.
|
|
242
|
+
const volumes = [`specgate-nm-${slug}:/src/node_modules`, "specgate-npm:/root/.npm"];
|
|
243
|
+
const inNode = (cmd) => `${install} && ${cmd}`;
|
|
244
|
+
const tsconfig = fs.existsSync(path.join(projectDir, "tsconfig.json"));
|
|
245
|
+
const runner = deps.vitest ? "vitest" : deps.jest ? "jest" : "";
|
|
246
|
+
const checks = [...shared(projectDir, level, lock)];
|
|
247
|
+
if (tsconfig) {
|
|
248
|
+
checks.push({
|
|
249
|
+
name: "types",
|
|
250
|
+
run: inNode("npx --no-install tsc --noEmit"),
|
|
251
|
+
when: "attempt",
|
|
252
|
+
image: exports.IMAGES.node,
|
|
253
|
+
volumes,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
if (deps.eslint) {
|
|
257
|
+
checks.push({
|
|
258
|
+
name: "lint",
|
|
259
|
+
run: inNode("npx --no-install eslint ."),
|
|
260
|
+
when: "attempt",
|
|
261
|
+
image: exports.IMAGES.node,
|
|
262
|
+
volumes,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
checks.push({
|
|
266
|
+
name: "coverage",
|
|
267
|
+
run: inNode(runner === "jest"
|
|
268
|
+
? "npx --no-install jest --coverage --coverageReporters=lcov"
|
|
269
|
+
: "npx --no-install vitest run --coverage --coverage.reporter=lcov"),
|
|
270
|
+
when: "attempt",
|
|
271
|
+
image: exports.IMAGES.node,
|
|
272
|
+
volumes,
|
|
273
|
+
report: "lcov:coverage/lcov.info",
|
|
274
|
+
timeout: 1800,
|
|
275
|
+
missing: runner
|
|
276
|
+
? runner === "vitest" && !deps["@vitest/coverage-v8"] && !deps["@vitest/coverage-istanbul"]
|
|
277
|
+
? "Coverage needs @vitest/coverage-v8 in devDependencies; add it and uncomment:"
|
|
278
|
+
: undefined
|
|
279
|
+
: "Coverage needs Vitest or Jest; with one installed, uncomment:",
|
|
280
|
+
});
|
|
281
|
+
if (level === "strict") {
|
|
282
|
+
checks.push({
|
|
283
|
+
name: "semgrep",
|
|
284
|
+
run: "semgrep scan --config p/typescript --config p/react --sarif --output .specgate/quality/semgrep.sarif --metrics off --quiet",
|
|
285
|
+
when: "end",
|
|
286
|
+
image: exports.IMAGES.semgrep,
|
|
287
|
+
sarif: ".specgate/quality/semgrep.sarif",
|
|
288
|
+
}, {
|
|
289
|
+
name: "mutation",
|
|
290
|
+
run: inNode("npx --no-install stryker run --mutate {changed_src} --reporters json"),
|
|
291
|
+
when: "end",
|
|
292
|
+
image: exports.IMAGES.node,
|
|
293
|
+
volumes,
|
|
294
|
+
report: "stryker:reports/mutation/mutation.json",
|
|
295
|
+
timeout: 3600,
|
|
296
|
+
missing: deps["@stryker-mutator/core"]
|
|
297
|
+
? undefined
|
|
298
|
+
: "Mutation needs @stryker-mutator/core and its runner in devDependencies; add them and uncomment:",
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
return checks;
|
|
302
|
+
}
|
|
303
|
+
/** The `quality:` block a level writes for a project, as YAML lines. */
|
|
304
|
+
function presetYaml(projectDir, level) {
|
|
305
|
+
const stacks = detectStacks(projectDir);
|
|
306
|
+
const lines = [
|
|
307
|
+
"# Quality and security checks (ADR-0040), written by `specgate quality init`.",
|
|
308
|
+
"# Every check runs in Docker, with tools that need no account. Take the",
|
|
309
|
+
"# baseline once (`specgate quality baseline`) so only new findings fail.",
|
|
310
|
+
`quality: ${level}`,
|
|
311
|
+
"checks:",
|
|
312
|
+
// REQ-234: Specgate checks this itself — no tool, so no container either.
|
|
313
|
+
" - name: commits",
|
|
314
|
+
' run: "builtin:commits"',
|
|
315
|
+
" when: attempt",
|
|
316
|
+
" runner: local",
|
|
317
|
+
];
|
|
318
|
+
const sonar = [
|
|
319
|
+
" # SonarQube Community in Docker (REQ-226): starts a local server on first use",
|
|
320
|
+
" # (about 2 GB of memory) at http://127.0.0.1:9123, login admin/admin. Uncomment:",
|
|
321
|
+
" # - name: sonar",
|
|
322
|
+
' # run: "builtin:sonar"',
|
|
323
|
+
" # when: end",
|
|
324
|
+
" # runner: docker",
|
|
325
|
+
" # sarif: .specgate/quality/sonar.sarif",
|
|
326
|
+
" # timeout: 1800",
|
|
327
|
+
// REQ-227: a second agent reads the change against the requirement; it advises.
|
|
328
|
+
" - name: review",
|
|
329
|
+
' run: "builtin:review"',
|
|
330
|
+
" when: end",
|
|
331
|
+
" gate: false",
|
|
332
|
+
" runner: local",
|
|
333
|
+
];
|
|
334
|
+
const seen = new Set(["commits"]);
|
|
335
|
+
for (const stack of stacks.length ? stacks : ["node"]) {
|
|
336
|
+
const checks = stack === "maven"
|
|
337
|
+
? maven(projectDir, level)
|
|
338
|
+
: stack === "gradle"
|
|
339
|
+
? gradle(projectDir, level)
|
|
340
|
+
: node(projectDir, level);
|
|
341
|
+
for (const c of checks) {
|
|
342
|
+
// One secrets scan for the whole repository; per-stack checks get the stack's name.
|
|
343
|
+
const name = seen.has(c.name) ? `${c.name}-${stack}` : c.name;
|
|
344
|
+
if (seen.has(c.name) && (c.name === "secrets" || c.name === "semgrep"))
|
|
345
|
+
continue;
|
|
346
|
+
seen.add(name);
|
|
347
|
+
lines.push(...render({ ...c, name }));
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
if (level === "strict")
|
|
351
|
+
lines.push(...sonar);
|
|
352
|
+
return lines.join("\n") + "\n";
|
|
353
|
+
}
|
|
354
|
+
/** Keys the quality block owns in harness.config.yaml. */
|
|
355
|
+
const OWNED = ["quality", "diff_coverage", "mutation_score", "checks"];
|
|
356
|
+
/**
|
|
357
|
+
* harness.config.yaml with its quality block replaced by this one: every
|
|
358
|
+
* other line kept, the block's own comment lines dropped with it.
|
|
359
|
+
*/
|
|
360
|
+
function withPreset(config, preset) {
|
|
361
|
+
const lines = config.replace(/\r\n/g, "\n").split("\n");
|
|
362
|
+
const out = [];
|
|
363
|
+
let skipping = false;
|
|
364
|
+
for (const line of lines) {
|
|
365
|
+
const top = /^([a-z_]+):/.exec(line);
|
|
366
|
+
if (top)
|
|
367
|
+
skipping = OWNED.includes(top[1]);
|
|
368
|
+
else if (skipping && !/^(\s|#|$)/.test(line))
|
|
369
|
+
skipping = false;
|
|
370
|
+
if (skipping)
|
|
371
|
+
continue;
|
|
372
|
+
if (/^# (Quality and security checks|Every check runs in Docker|baseline once)/.test(line))
|
|
373
|
+
continue;
|
|
374
|
+
out.push(line);
|
|
375
|
+
}
|
|
376
|
+
return `${out.join("\n").trimEnd()}\n\n${preset}`;
|
|
377
|
+
}
|
|
378
|
+
//# 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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"}
|