@quikit/quikpilot-runner 8.2.7 → 8.2.8
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/dist/index.js +93 -17
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -73,10 +73,11 @@ async function describeQuikTrackFailure(res) {
|
|
|
73
73
|
|
|
74
74
|
// src/callback.ts
|
|
75
75
|
async function reportBack(params) {
|
|
76
|
-
const { callbackUrl, runToken, status, branch, warnings, targeting, baselineFindings } = params;
|
|
76
|
+
const { callbackUrl, runToken, status, branch, warnings, targeting, baselineFindings, unresolved } = params;
|
|
77
77
|
const body = { status };
|
|
78
78
|
if (branch) body.branch = branch;
|
|
79
79
|
if (warnings && warnings.length > 0) body.warnings = warnings;
|
|
80
|
+
if (unresolved && unresolved.length > 0) body.unresolved = unresolved;
|
|
80
81
|
if (targeting) body.targeting = targeting;
|
|
81
82
|
if (baselineFindings) body.baselineFindings = baselineFindings;
|
|
82
83
|
const res = await fetch(callbackUrl, {
|
|
@@ -250,6 +251,16 @@ function findDeniedContextPath(contextPaths, patterns) {
|
|
|
250
251
|
return null;
|
|
251
252
|
}
|
|
252
253
|
|
|
254
|
+
// src/runtimeReplyError.ts
|
|
255
|
+
var RuntimeReplyError = class extends Error {
|
|
256
|
+
summary;
|
|
257
|
+
constructor(message, summary) {
|
|
258
|
+
super(message);
|
|
259
|
+
this.name = "RuntimeReplyError";
|
|
260
|
+
this.summary = summary;
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
|
|
253
264
|
// src/envelope.ts
|
|
254
265
|
var HARD_FAILURE_CODES = /* @__PURE__ */ new Set(["SEMANTIC_MISMATCH", "CONTRACT_REJECTED"]);
|
|
255
266
|
function checkHardFailure(envelope, useCase, target) {
|
|
@@ -257,17 +268,25 @@ function checkHardFailure(envelope, useCase, target) {
|
|
|
257
268
|
if (typeof code === "string" && HARD_FAILURE_CODES.has(code)) {
|
|
258
269
|
const detail = envelope.error ?? envelope.normalizedText ?? "no detail";
|
|
259
270
|
const where = target ? ` for ${target}` : "";
|
|
260
|
-
throw new
|
|
271
|
+
throw new RuntimeReplyError(
|
|
272
|
+
`${useCase} failed${where} (${code}, not retried): ${detail}`,
|
|
273
|
+
`${useCase} failed${where} (${code}, not retried)`
|
|
274
|
+
);
|
|
261
275
|
}
|
|
262
276
|
}
|
|
263
277
|
function unwrapExecute(envelope, useCase) {
|
|
264
278
|
if (envelope?.success === false) {
|
|
265
|
-
|
|
266
|
-
|
|
279
|
+
const code = envelope.errorCode ?? "UNKNOWN";
|
|
280
|
+
throw new RuntimeReplyError(
|
|
281
|
+
`${useCase} failed: ${code} \u2014 ${envelope.error ?? envelope.normalizedText ?? "no message"}`,
|
|
282
|
+
`${useCase} failed: ${code}`
|
|
267
283
|
);
|
|
268
284
|
}
|
|
269
285
|
if (!envelope?.structuredJson || typeof envelope.structuredJson !== "object") {
|
|
270
|
-
throw new
|
|
286
|
+
throw new RuntimeReplyError(
|
|
287
|
+
`${useCase} returned no structuredJson: ${JSON.stringify(envelope)}`,
|
|
288
|
+
`${useCase} returned no structuredJson`
|
|
289
|
+
);
|
|
271
290
|
}
|
|
272
291
|
return envelope.structuredJson;
|
|
273
292
|
}
|
|
@@ -419,7 +438,7 @@ function narrowJudgedByForTarget(pool, targets, codeTargetPath) {
|
|
|
419
438
|
function toWireJudgedBy(pool) {
|
|
420
439
|
return pool.map(({ automationId: _automationId, ...rest }) => rest);
|
|
421
440
|
}
|
|
422
|
-
async function runCodegen(gateway, targets, workspaceListing, requiredTests, deniedPaths, judgedByPool, warnings, contextLog) {
|
|
441
|
+
async function runCodegen(gateway, targets, workspaceListing, requiredTests, deniedPaths, judgedByPool, warnings, contextLog, outOfScope = []) {
|
|
423
442
|
const results = [];
|
|
424
443
|
const listing = new Set(workspaceListing);
|
|
425
444
|
for (const target of targets) {
|
|
@@ -468,6 +487,9 @@ async function runCodegen(gateway, targets, workspaceListing, requiredTests, den
|
|
|
468
487
|
if (deniedPaths.length > 0) {
|
|
469
488
|
contextData.deniedPaths = deniedPaths;
|
|
470
489
|
}
|
|
490
|
+
if (outOfScope.length > 0) {
|
|
491
|
+
contextData.outOfScope = outOfScope;
|
|
492
|
+
}
|
|
471
493
|
if (target.automationIds && target.automationIds.length > 0) {
|
|
472
494
|
const wanted = new Set(target.automationIds);
|
|
473
495
|
contextData.requiredTests = requiredTests.filter((tc) => wanted.has(tc.automationId));
|
|
@@ -521,16 +543,23 @@ async function runCodegen(gateway, targets, workspaceListing, requiredTests, den
|
|
|
521
543
|
}
|
|
522
544
|
if (typeof envelope?.errorCode === "string" && NOT_RETRIED_CODES.has(envelope.errorCode)) {
|
|
523
545
|
const detail = envelope.error ? `: ${envelope.error}` : "";
|
|
524
|
-
throw new
|
|
546
|
+
throw new RuntimeReplyError(
|
|
547
|
+
`Codegen refused ${target.path}: ${envelope.errorCode} (not retried)${detail}`,
|
|
548
|
+
`Codegen refused ${target.path}: ${envelope.errorCode} (not retried)`
|
|
549
|
+
);
|
|
525
550
|
}
|
|
526
551
|
if (envelope?.errorCode === JUDGED_BY_TOO_LARGE_CODE) {
|
|
527
552
|
const detail = envelope.error ? `: ${envelope.error}` : "";
|
|
528
|
-
throw new
|
|
553
|
+
throw new RuntimeReplyError(
|
|
554
|
+
`Codegen refused ${target.path}: ${envelope.errorCode} (after narrowing)${detail}`,
|
|
555
|
+
`Codegen refused ${target.path}: ${envelope.errorCode} (after narrowing)`
|
|
556
|
+
);
|
|
529
557
|
}
|
|
530
558
|
const body = unwrapExecute(envelope, "pilot.codegen");
|
|
531
559
|
if (body.outcome !== "GENERATED" || typeof body.newContent !== "string") {
|
|
532
|
-
throw new
|
|
533
|
-
`Codegen refused ${target.path}${body.refusalReason ? `: ${body.refusalReason}` : ""}
|
|
560
|
+
throw new RuntimeReplyError(
|
|
561
|
+
`Codegen refused ${target.path}${body.refusalReason ? `: ${body.refusalReason}` : ""}`,
|
|
562
|
+
`Codegen refused ${target.path}`
|
|
534
563
|
);
|
|
535
564
|
}
|
|
536
565
|
if (!isNewFile) {
|
|
@@ -1360,6 +1389,36 @@ async function runBaselineCheck(params) {
|
|
|
1360
1389
|
}
|
|
1361
1390
|
}
|
|
1362
1391
|
|
|
1392
|
+
// src/failureReason.ts
|
|
1393
|
+
var MAX_FAILURE_REASON = 1e3;
|
|
1394
|
+
var MIN_SECRET_LENGTH = 8;
|
|
1395
|
+
var CREDENTIAL_PATTERNS = [
|
|
1396
|
+
/\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{20,}/g,
|
|
1397
|
+
/\bgithub_pat_[A-Za-z0-9_]{20,}/g,
|
|
1398
|
+
/x-access-token:[^@\s'"]+/gi,
|
|
1399
|
+
// Only the header form ("Authorization: basic <token>"), or a bearer value that contains a digit: a bare
|
|
1400
|
+
// "basic authentication" or "bearer of the news" is prose, not a credential.
|
|
1401
|
+
/\bauthorization:\s*(?:basic|bearer|token)\s+[^\s'"]{8,}/gi,
|
|
1402
|
+
/\bbearer\s+(?=[A-Za-z0-9._~+/=-]*\d)[A-Za-z0-9._~+/=-]{12,}/gi,
|
|
1403
|
+
// A signed JWT is three dot-separated segments; QuikPilot's own run token is an encrypted JWT (alg dir) of five, the
|
|
1404
|
+
// second one empty. The run token is also matched by exact value, but one that has expired or rotated is not the
|
|
1405
|
+
// current value, so its shape has to catch it.
|
|
1406
|
+
/\beyJ[A-Za-z0-9_-]{8,}(?:\.[A-Za-z0-9_-]*){2,4}/g
|
|
1407
|
+
];
|
|
1408
|
+
function failureSummary(err) {
|
|
1409
|
+
if (err instanceof RuntimeReplyError) return err.summary;
|
|
1410
|
+
return err instanceof Error ? err.message : String(err);
|
|
1411
|
+
}
|
|
1412
|
+
function describeFailureReason(message, secrets = []) {
|
|
1413
|
+
let text = message;
|
|
1414
|
+
for (const secret of secrets) {
|
|
1415
|
+
if (secret.length >= MIN_SECRET_LENGTH) text = text.split(secret).join("***");
|
|
1416
|
+
}
|
|
1417
|
+
for (const pattern of CREDENTIAL_PATTERNS) text = text.replace(pattern, "***");
|
|
1418
|
+
text = text.replace(/\s*\n\s*/g, " | ").trim();
|
|
1419
|
+
return text.length > MAX_FAILURE_REASON ? `${text.slice(0, MAX_FAILURE_REASON)}\u2026` : text;
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1363
1422
|
// src/scopeCheck.ts
|
|
1364
1423
|
var import_node_fs7 = require("node:fs");
|
|
1365
1424
|
var ROUTE_METHOD_RE = /\b(GET|POST|PUT|PATCH|DELETE)\b/i;
|
|
@@ -1474,7 +1533,7 @@ function validateTarget(target, workspaceRoot, workspaceListing, deniedPaths) {
|
|
|
1474
1533
|
);
|
|
1475
1534
|
}
|
|
1476
1535
|
}
|
|
1477
|
-
async function runTargeting(gateway, design, workspaceRoot, workspaceListing, requiredTests, deniedPaths, testDiscovery) {
|
|
1536
|
+
async function runTargeting(gateway, design, workspaceRoot, workspaceListing, requiredTests, deniedPaths, testDiscovery, outOfScope = []) {
|
|
1478
1537
|
const contextData = {
|
|
1479
1538
|
// NESTED, NOT FLATTENED — a second vocabulary for the design shape is exactly what
|
|
1480
1539
|
// QUIKTR-1034 cost.
|
|
@@ -1489,6 +1548,9 @@ async function runTargeting(gateway, design, workspaceRoot, workspaceListing, re
|
|
|
1489
1548
|
if (deniedPaths.length > 0) {
|
|
1490
1549
|
contextData.deniedPaths = deniedPaths;
|
|
1491
1550
|
}
|
|
1551
|
+
if (outOfScope.length > 0) {
|
|
1552
|
+
contextData.outOfScope = outOfScope;
|
|
1553
|
+
}
|
|
1492
1554
|
contextData.testDiscovery = testDiscovery;
|
|
1493
1555
|
const res = await fetchWithRetry(`${gateway.baseUrl}/ai/execute`, {
|
|
1494
1556
|
method: "POST",
|
|
@@ -1511,7 +1573,10 @@ async function runTargeting(gateway, design, workspaceRoot, workspaceListing, re
|
|
|
1511
1573
|
return { outcome: "NO_TARGET", reason: body.noTargetReason ?? null };
|
|
1512
1574
|
}
|
|
1513
1575
|
if (body.outcome !== "TARGETED" || !Array.isArray(body.targets)) {
|
|
1514
|
-
throw new
|
|
1576
|
+
throw new RuntimeReplyError(
|
|
1577
|
+
`pilot.targeting returned an unexpected shape: ${JSON.stringify(body)}`,
|
|
1578
|
+
"pilot.targeting returned an unexpected shape"
|
|
1579
|
+
);
|
|
1515
1580
|
}
|
|
1516
1581
|
const listing = new Set(workspaceListing);
|
|
1517
1582
|
for (const target of body.targets) {
|
|
@@ -1690,6 +1755,13 @@ async function run(env2) {
|
|
|
1690
1755
|
let branch;
|
|
1691
1756
|
let runToken;
|
|
1692
1757
|
const warnings = [];
|
|
1758
|
+
const failureReasons = [];
|
|
1759
|
+
const recordFailure = (err) => {
|
|
1760
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1761
|
+
console.error(message);
|
|
1762
|
+
const reason = describeFailureReason(failureSummary(err), runToken ? [runToken] : []);
|
|
1763
|
+
if (reason) failureReasons.push(reason);
|
|
1764
|
+
};
|
|
1693
1765
|
let targeted = false;
|
|
1694
1766
|
let generatedFilePaths = [];
|
|
1695
1767
|
let targetingResult;
|
|
@@ -1700,6 +1772,7 @@ async function run(env2) {
|
|
|
1700
1772
|
packet = await fetchPacket(env2.packetUrl, runToken, env2.githubRunId);
|
|
1701
1773
|
checkoutTargetBranch(packet.targetBranch);
|
|
1702
1774
|
const workspaceListing = listWorkspaceFiles(packet.workspaceRoot);
|
|
1775
|
+
const outOfScope = (packet.outOfScope ?? []).map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
1703
1776
|
const targeting = await runTargeting(
|
|
1704
1777
|
packet.gateway,
|
|
1705
1778
|
packet.design,
|
|
@@ -1707,7 +1780,8 @@ async function run(env2) {
|
|
|
1707
1780
|
workspaceListing,
|
|
1708
1781
|
packet.requiredTests,
|
|
1709
1782
|
packet.guardrails.deniedPaths,
|
|
1710
|
-
packet.testDiscovery
|
|
1783
|
+
packet.testDiscovery,
|
|
1784
|
+
outOfScope
|
|
1711
1785
|
);
|
|
1712
1786
|
targetingResult = targeting;
|
|
1713
1787
|
if (targeting.outcome === "NO_TARGET") {
|
|
@@ -1755,7 +1829,8 @@ async function run(env2) {
|
|
|
1755
1829
|
packet.guardrails.deniedPaths,
|
|
1756
1830
|
judgedByPool,
|
|
1757
1831
|
warnings,
|
|
1758
|
-
contextLog
|
|
1832
|
+
contextLog,
|
|
1833
|
+
outOfScope
|
|
1759
1834
|
)
|
|
1760
1835
|
]);
|
|
1761
1836
|
const depCheck = checkImportDependencies(
|
|
@@ -1818,7 +1893,7 @@ async function run(env2) {
|
|
|
1818
1893
|
}
|
|
1819
1894
|
} catch (err) {
|
|
1820
1895
|
hardFailure = true;
|
|
1821
|
-
|
|
1896
|
+
recordFailure(err);
|
|
1822
1897
|
}
|
|
1823
1898
|
if (!runToken) {
|
|
1824
1899
|
console.error("No run token \u2014 the OIDC exchange failed before QuikTrack could be reached.");
|
|
@@ -1855,7 +1930,7 @@ async function run(env2) {
|
|
|
1855
1930
|
branch = result.branch;
|
|
1856
1931
|
} catch (err) {
|
|
1857
1932
|
hardFailure = true;
|
|
1858
|
-
|
|
1933
|
+
recordFailure(err);
|
|
1859
1934
|
}
|
|
1860
1935
|
}
|
|
1861
1936
|
await reportBack({
|
|
@@ -1866,7 +1941,8 @@ async function run(env2) {
|
|
|
1866
1941
|
warnings,
|
|
1867
1942
|
// Omitted when targeting itself never produced a result (nothing exists to record).
|
|
1868
1943
|
targeting: targetingResult ? buildTargetingRecord(targetingResult, contextLog) : void 0,
|
|
1869
|
-
baselineFindings
|
|
1944
|
+
baselineFindings,
|
|
1945
|
+
unresolved: failureReasons.length > 0 ? failureReasons : void 0
|
|
1870
1946
|
});
|
|
1871
1947
|
return { hardFailure };
|
|
1872
1948
|
}
|