cto-ai-cli 3.1.0 → 4.0.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/DOCS.md +352 -0
- package/README.md +192 -15
- package/dist/action/index.js +629 -83
- package/dist/api/dashboard.js +107 -23
- package/dist/api/dashboard.js.map +1 -1
- package/dist/api/server.js +108 -24
- package/dist/api/server.js.map +1 -1
- package/dist/cli/gateway.js +2925 -0
- package/dist/cli/score.js +3015 -237
- package/dist/cli/v2/index.js +133 -49
- package/dist/cli/v2/index.js.map +1 -1
- package/dist/engine/index.d.ts +85 -1
- package/dist/engine/index.js +665 -42
- package/dist/engine/index.js.map +1 -1
- package/dist/gateway/index.d.ts +281 -0
- package/dist/gateway/index.js +2803 -0
- package/dist/gateway/index.js.map +1 -0
- package/dist/govern/index.d.ts +67 -3
- package/dist/govern/index.js +462 -23
- package/dist/govern/index.js.map +1 -1
- package/dist/interact/index.js +108 -24
- package/dist/interact/index.js.map +1 -1
- package/dist/mcp/v2.js +130 -46
- package/dist/mcp/v2.js.map +1 -1
- package/package.json +3 -2
package/dist/action/index.js
CHANGED
|
@@ -2053,9 +2053,9 @@ var require_dispatcher_base = __commonJS({
|
|
|
2053
2053
|
}
|
|
2054
2054
|
close(callback) {
|
|
2055
2055
|
if (callback === void 0) {
|
|
2056
|
-
return new Promise((
|
|
2056
|
+
return new Promise((resolve7, reject) => {
|
|
2057
2057
|
this.close((err, data) => {
|
|
2058
|
-
return err ? reject(err) :
|
|
2058
|
+
return err ? reject(err) : resolve7(data);
|
|
2059
2059
|
});
|
|
2060
2060
|
});
|
|
2061
2061
|
}
|
|
@@ -2093,12 +2093,12 @@ var require_dispatcher_base = __commonJS({
|
|
|
2093
2093
|
err = null;
|
|
2094
2094
|
}
|
|
2095
2095
|
if (callback === void 0) {
|
|
2096
|
-
return new Promise((
|
|
2096
|
+
return new Promise((resolve7, reject) => {
|
|
2097
2097
|
this.destroy(err, (err2, data) => {
|
|
2098
2098
|
return err2 ? (
|
|
2099
2099
|
/* istanbul ignore next: should never error */
|
|
2100
2100
|
reject(err2)
|
|
2101
|
-
) :
|
|
2101
|
+
) : resolve7(data);
|
|
2102
2102
|
});
|
|
2103
2103
|
});
|
|
2104
2104
|
}
|
|
@@ -4365,8 +4365,8 @@ var require_util2 = __commonJS({
|
|
|
4365
4365
|
function createDeferredPromise() {
|
|
4366
4366
|
let res;
|
|
4367
4367
|
let rej;
|
|
4368
|
-
const promise = new Promise((
|
|
4369
|
-
res =
|
|
4368
|
+
const promise = new Promise((resolve7, reject) => {
|
|
4369
|
+
res = resolve7;
|
|
4370
4370
|
rej = reject;
|
|
4371
4371
|
});
|
|
4372
4372
|
return { promise, resolve: res, reject: rej };
|
|
@@ -6507,12 +6507,12 @@ upgrade: ${upgrade}\r
|
|
|
6507
6507
|
cb();
|
|
6508
6508
|
}
|
|
6509
6509
|
}
|
|
6510
|
-
const waitForDrain = () => new Promise((
|
|
6510
|
+
const waitForDrain = () => new Promise((resolve7, reject) => {
|
|
6511
6511
|
assert(callback === null);
|
|
6512
6512
|
if (socket[kError]) {
|
|
6513
6513
|
reject(socket[kError]);
|
|
6514
6514
|
} else {
|
|
6515
|
-
callback =
|
|
6515
|
+
callback = resolve7;
|
|
6516
6516
|
}
|
|
6517
6517
|
});
|
|
6518
6518
|
socket.on("close", onDrain).on("drain", onDrain);
|
|
@@ -7149,12 +7149,12 @@ var require_client_h2 = __commonJS({
|
|
|
7149
7149
|
cb();
|
|
7150
7150
|
}
|
|
7151
7151
|
}
|
|
7152
|
-
const waitForDrain = () => new Promise((
|
|
7152
|
+
const waitForDrain = () => new Promise((resolve7, reject) => {
|
|
7153
7153
|
assert(callback === null);
|
|
7154
7154
|
if (socket[kError]) {
|
|
7155
7155
|
reject(socket[kError]);
|
|
7156
7156
|
} else {
|
|
7157
|
-
callback =
|
|
7157
|
+
callback = resolve7;
|
|
7158
7158
|
}
|
|
7159
7159
|
});
|
|
7160
7160
|
h2stream.on("close", onDrain).on("drain", onDrain);
|
|
@@ -7631,16 +7631,16 @@ var require_client = __commonJS({
|
|
|
7631
7631
|
return this[kNeedDrain] < 2;
|
|
7632
7632
|
}
|
|
7633
7633
|
async [kClose]() {
|
|
7634
|
-
return new Promise((
|
|
7634
|
+
return new Promise((resolve7) => {
|
|
7635
7635
|
if (this[kSize]) {
|
|
7636
|
-
this[kClosedResolve] =
|
|
7636
|
+
this[kClosedResolve] = resolve7;
|
|
7637
7637
|
} else {
|
|
7638
|
-
|
|
7638
|
+
resolve7(null);
|
|
7639
7639
|
}
|
|
7640
7640
|
});
|
|
7641
7641
|
}
|
|
7642
7642
|
async [kDestroy](err) {
|
|
7643
|
-
return new Promise((
|
|
7643
|
+
return new Promise((resolve7) => {
|
|
7644
7644
|
const requests = this[kQueue].splice(this[kPendingIdx]);
|
|
7645
7645
|
for (let i = 0; i < requests.length; i++) {
|
|
7646
7646
|
const request2 = requests[i];
|
|
@@ -7651,7 +7651,7 @@ var require_client = __commonJS({
|
|
|
7651
7651
|
this[kClosedResolve]();
|
|
7652
7652
|
this[kClosedResolve] = null;
|
|
7653
7653
|
}
|
|
7654
|
-
|
|
7654
|
+
resolve7(null);
|
|
7655
7655
|
};
|
|
7656
7656
|
if (this[kHTTPContext]) {
|
|
7657
7657
|
this[kHTTPContext].destroy(err, callback);
|
|
@@ -7702,7 +7702,7 @@ var require_client = __commonJS({
|
|
|
7702
7702
|
});
|
|
7703
7703
|
}
|
|
7704
7704
|
try {
|
|
7705
|
-
const socket = await new Promise((
|
|
7705
|
+
const socket = await new Promise((resolve7, reject) => {
|
|
7706
7706
|
client[kConnector]({
|
|
7707
7707
|
host,
|
|
7708
7708
|
hostname,
|
|
@@ -7714,7 +7714,7 @@ var require_client = __commonJS({
|
|
|
7714
7714
|
if (err) {
|
|
7715
7715
|
reject(err);
|
|
7716
7716
|
} else {
|
|
7717
|
-
|
|
7717
|
+
resolve7(socket2);
|
|
7718
7718
|
}
|
|
7719
7719
|
});
|
|
7720
7720
|
});
|
|
@@ -8051,8 +8051,8 @@ var require_pool_base = __commonJS({
|
|
|
8051
8051
|
if (this[kQueue].isEmpty()) {
|
|
8052
8052
|
await Promise.all(this[kClients].map((c) => c.close()));
|
|
8053
8053
|
} else {
|
|
8054
|
-
await new Promise((
|
|
8055
|
-
this[kClosedResolve] =
|
|
8054
|
+
await new Promise((resolve7) => {
|
|
8055
|
+
this[kClosedResolve] = resolve7;
|
|
8056
8056
|
});
|
|
8057
8057
|
}
|
|
8058
8058
|
}
|
|
@@ -9267,7 +9267,7 @@ var require_readable = __commonJS({
|
|
|
9267
9267
|
if (this._readableState.closeEmitted) {
|
|
9268
9268
|
return null;
|
|
9269
9269
|
}
|
|
9270
|
-
return await new Promise((
|
|
9270
|
+
return await new Promise((resolve7, reject) => {
|
|
9271
9271
|
if (this[kContentLength] > limit) {
|
|
9272
9272
|
this.destroy(new AbortError());
|
|
9273
9273
|
}
|
|
@@ -9280,7 +9280,7 @@ var require_readable = __commonJS({
|
|
|
9280
9280
|
if (signal?.aborted) {
|
|
9281
9281
|
reject(signal.reason ?? new AbortError());
|
|
9282
9282
|
} else {
|
|
9283
|
-
|
|
9283
|
+
resolve7(null);
|
|
9284
9284
|
}
|
|
9285
9285
|
}).on("error", noop3).on("data", function(chunk) {
|
|
9286
9286
|
limit -= chunk.length;
|
|
@@ -9299,7 +9299,7 @@ var require_readable = __commonJS({
|
|
|
9299
9299
|
}
|
|
9300
9300
|
async function consume(stream, type) {
|
|
9301
9301
|
assert(!stream[kConsume]);
|
|
9302
|
-
return new Promise((
|
|
9302
|
+
return new Promise((resolve7, reject) => {
|
|
9303
9303
|
if (isUnusable(stream)) {
|
|
9304
9304
|
const rState = stream._readableState;
|
|
9305
9305
|
if (rState.destroyed && rState.closeEmitted === false) {
|
|
@@ -9316,7 +9316,7 @@ var require_readable = __commonJS({
|
|
|
9316
9316
|
stream[kConsume] = {
|
|
9317
9317
|
type,
|
|
9318
9318
|
stream,
|
|
9319
|
-
resolve:
|
|
9319
|
+
resolve: resolve7,
|
|
9320
9320
|
reject,
|
|
9321
9321
|
length: 0,
|
|
9322
9322
|
body: []
|
|
@@ -9386,18 +9386,18 @@ var require_readable = __commonJS({
|
|
|
9386
9386
|
return buffer;
|
|
9387
9387
|
}
|
|
9388
9388
|
function consumeEnd(consume2) {
|
|
9389
|
-
const { type, body, resolve:
|
|
9389
|
+
const { type, body, resolve: resolve7, stream, length } = consume2;
|
|
9390
9390
|
try {
|
|
9391
9391
|
if (type === "text") {
|
|
9392
|
-
|
|
9392
|
+
resolve7(chunksDecode(body, length));
|
|
9393
9393
|
} else if (type === "json") {
|
|
9394
|
-
|
|
9394
|
+
resolve7(JSON.parse(chunksDecode(body, length)));
|
|
9395
9395
|
} else if (type === "arrayBuffer") {
|
|
9396
|
-
|
|
9396
|
+
resolve7(chunksConcat(body, length).buffer);
|
|
9397
9397
|
} else if (type === "blob") {
|
|
9398
|
-
|
|
9398
|
+
resolve7(new Blob(body, { type: stream[kContentType] }));
|
|
9399
9399
|
} else if (type === "bytes") {
|
|
9400
|
-
|
|
9400
|
+
resolve7(chunksConcat(body, length));
|
|
9401
9401
|
}
|
|
9402
9402
|
consumeFinish(consume2);
|
|
9403
9403
|
} catch (err) {
|
|
@@ -9655,9 +9655,9 @@ var require_api_request = __commonJS({
|
|
|
9655
9655
|
};
|
|
9656
9656
|
function request2(opts, callback) {
|
|
9657
9657
|
if (callback === void 0) {
|
|
9658
|
-
return new Promise((
|
|
9658
|
+
return new Promise((resolve7, reject) => {
|
|
9659
9659
|
request2.call(this, opts, (err, data) => {
|
|
9660
|
-
return err ? reject(err) :
|
|
9660
|
+
return err ? reject(err) : resolve7(data);
|
|
9661
9661
|
});
|
|
9662
9662
|
});
|
|
9663
9663
|
}
|
|
@@ -9881,9 +9881,9 @@ var require_api_stream = __commonJS({
|
|
|
9881
9881
|
};
|
|
9882
9882
|
function stream(opts, factory, callback) {
|
|
9883
9883
|
if (callback === void 0) {
|
|
9884
|
-
return new Promise((
|
|
9884
|
+
return new Promise((resolve7, reject) => {
|
|
9885
9885
|
stream.call(this, opts, factory, (err, data) => {
|
|
9886
|
-
return err ? reject(err) :
|
|
9886
|
+
return err ? reject(err) : resolve7(data);
|
|
9887
9887
|
});
|
|
9888
9888
|
});
|
|
9889
9889
|
}
|
|
@@ -10168,9 +10168,9 @@ var require_api_upgrade = __commonJS({
|
|
|
10168
10168
|
};
|
|
10169
10169
|
function upgrade(opts, callback) {
|
|
10170
10170
|
if (callback === void 0) {
|
|
10171
|
-
return new Promise((
|
|
10171
|
+
return new Promise((resolve7, reject) => {
|
|
10172
10172
|
upgrade.call(this, opts, (err, data) => {
|
|
10173
|
-
return err ? reject(err) :
|
|
10173
|
+
return err ? reject(err) : resolve7(data);
|
|
10174
10174
|
});
|
|
10175
10175
|
});
|
|
10176
10176
|
}
|
|
@@ -10262,9 +10262,9 @@ var require_api_connect = __commonJS({
|
|
|
10262
10262
|
};
|
|
10263
10263
|
function connect(opts, callback) {
|
|
10264
10264
|
if (callback === void 0) {
|
|
10265
|
-
return new Promise((
|
|
10265
|
+
return new Promise((resolve7, reject) => {
|
|
10266
10266
|
connect.call(this, opts, (err, data) => {
|
|
10267
|
-
return err ? reject(err) :
|
|
10267
|
+
return err ? reject(err) : resolve7(data);
|
|
10268
10268
|
});
|
|
10269
10269
|
});
|
|
10270
10270
|
}
|
|
@@ -14126,7 +14126,7 @@ var require_fetch = __commonJS({
|
|
|
14126
14126
|
function dispatch({ body }) {
|
|
14127
14127
|
const url = requestCurrentURL(request2);
|
|
14128
14128
|
const agent = fetchParams.controller.dispatcher;
|
|
14129
|
-
return new Promise((
|
|
14129
|
+
return new Promise((resolve7, reject) => agent.dispatch(
|
|
14130
14130
|
{
|
|
14131
14131
|
path: url.pathname + url.search,
|
|
14132
14132
|
origin: url.origin,
|
|
@@ -14202,7 +14202,7 @@ var require_fetch = __commonJS({
|
|
|
14202
14202
|
}
|
|
14203
14203
|
}
|
|
14204
14204
|
const onError = this.onError.bind(this);
|
|
14205
|
-
|
|
14205
|
+
resolve7({
|
|
14206
14206
|
status,
|
|
14207
14207
|
statusText,
|
|
14208
14208
|
headersList,
|
|
@@ -14248,7 +14248,7 @@ var require_fetch = __commonJS({
|
|
|
14248
14248
|
for (let i = 0; i < rawHeaders.length; i += 2) {
|
|
14249
14249
|
headersList.append(bufferToLowerCasedHeaderName(rawHeaders[i]), rawHeaders[i + 1].toString("latin1"), true);
|
|
14250
14250
|
}
|
|
14251
|
-
|
|
14251
|
+
resolve7({
|
|
14252
14252
|
status,
|
|
14253
14253
|
statusText: STATUS_CODES[status],
|
|
14254
14254
|
headersList,
|
|
@@ -17841,8 +17841,8 @@ var require_util8 = __commonJS({
|
|
|
17841
17841
|
return true;
|
|
17842
17842
|
}
|
|
17843
17843
|
function delay(ms) {
|
|
17844
|
-
return new Promise((
|
|
17845
|
-
setTimeout(
|
|
17844
|
+
return new Promise((resolve7) => {
|
|
17845
|
+
setTimeout(resolve7, ms).unref();
|
|
17846
17846
|
});
|
|
17847
17847
|
}
|
|
17848
17848
|
module.exports = {
|
|
@@ -18646,11 +18646,11 @@ var require_lib = __commonJS({
|
|
|
18646
18646
|
})();
|
|
18647
18647
|
var __awaiter3 = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
18648
18648
|
function adopt(value) {
|
|
18649
|
-
return value instanceof P ? value : new P(function(
|
|
18650
|
-
|
|
18649
|
+
return value instanceof P ? value : new P(function(resolve7) {
|
|
18650
|
+
resolve7(value);
|
|
18651
18651
|
});
|
|
18652
18652
|
}
|
|
18653
|
-
return new (P || (P = Promise))(function(
|
|
18653
|
+
return new (P || (P = Promise))(function(resolve7, reject) {
|
|
18654
18654
|
function fulfilled(value) {
|
|
18655
18655
|
try {
|
|
18656
18656
|
step(generator.next(value));
|
|
@@ -18666,7 +18666,7 @@ var require_lib = __commonJS({
|
|
|
18666
18666
|
}
|
|
18667
18667
|
}
|
|
18668
18668
|
function step(result) {
|
|
18669
|
-
result.done ?
|
|
18669
|
+
result.done ? resolve7(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
18670
18670
|
}
|
|
18671
18671
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18672
18672
|
});
|
|
@@ -18753,26 +18753,26 @@ var require_lib = __commonJS({
|
|
|
18753
18753
|
}
|
|
18754
18754
|
readBody() {
|
|
18755
18755
|
return __awaiter3(this, void 0, void 0, function* () {
|
|
18756
|
-
return new Promise((
|
|
18756
|
+
return new Promise((resolve7) => __awaiter3(this, void 0, void 0, function* () {
|
|
18757
18757
|
let output = Buffer.alloc(0);
|
|
18758
18758
|
this.message.on("data", (chunk) => {
|
|
18759
18759
|
output = Buffer.concat([output, chunk]);
|
|
18760
18760
|
});
|
|
18761
18761
|
this.message.on("end", () => {
|
|
18762
|
-
|
|
18762
|
+
resolve7(output.toString());
|
|
18763
18763
|
});
|
|
18764
18764
|
}));
|
|
18765
18765
|
});
|
|
18766
18766
|
}
|
|
18767
18767
|
readBodyBuffer() {
|
|
18768
18768
|
return __awaiter3(this, void 0, void 0, function* () {
|
|
18769
|
-
return new Promise((
|
|
18769
|
+
return new Promise((resolve7) => __awaiter3(this, void 0, void 0, function* () {
|
|
18770
18770
|
const chunks = [];
|
|
18771
18771
|
this.message.on("data", (chunk) => {
|
|
18772
18772
|
chunks.push(chunk);
|
|
18773
18773
|
});
|
|
18774
18774
|
this.message.on("end", () => {
|
|
18775
|
-
|
|
18775
|
+
resolve7(Buffer.concat(chunks));
|
|
18776
18776
|
});
|
|
18777
18777
|
}));
|
|
18778
18778
|
});
|
|
@@ -18980,14 +18980,14 @@ var require_lib = __commonJS({
|
|
|
18980
18980
|
*/
|
|
18981
18981
|
requestRaw(info2, data) {
|
|
18982
18982
|
return __awaiter3(this, void 0, void 0, function* () {
|
|
18983
|
-
return new Promise((
|
|
18983
|
+
return new Promise((resolve7, reject) => {
|
|
18984
18984
|
function callbackForResult(err, res) {
|
|
18985
18985
|
if (err) {
|
|
18986
18986
|
reject(err);
|
|
18987
18987
|
} else if (!res) {
|
|
18988
18988
|
reject(new Error("Unknown error"));
|
|
18989
18989
|
} else {
|
|
18990
|
-
|
|
18990
|
+
resolve7(res);
|
|
18991
18991
|
}
|
|
18992
18992
|
}
|
|
18993
18993
|
this.requestRawWithCallback(info2, data, callbackForResult);
|
|
@@ -19231,12 +19231,12 @@ var require_lib = __commonJS({
|
|
|
19231
19231
|
return __awaiter3(this, void 0, void 0, function* () {
|
|
19232
19232
|
retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber);
|
|
19233
19233
|
const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber);
|
|
19234
|
-
return new Promise((
|
|
19234
|
+
return new Promise((resolve7) => setTimeout(() => resolve7(), ms));
|
|
19235
19235
|
});
|
|
19236
19236
|
}
|
|
19237
19237
|
_processResponse(res, options) {
|
|
19238
19238
|
return __awaiter3(this, void 0, void 0, function* () {
|
|
19239
|
-
return new Promise((
|
|
19239
|
+
return new Promise((resolve7, reject) => __awaiter3(this, void 0, void 0, function* () {
|
|
19240
19240
|
const statusCode = res.message.statusCode || 0;
|
|
19241
19241
|
const response = {
|
|
19242
19242
|
statusCode,
|
|
@@ -19244,7 +19244,7 @@ var require_lib = __commonJS({
|
|
|
19244
19244
|
headers: {}
|
|
19245
19245
|
};
|
|
19246
19246
|
if (statusCode === HttpCodes2.NotFound) {
|
|
19247
|
-
|
|
19247
|
+
resolve7(response);
|
|
19248
19248
|
}
|
|
19249
19249
|
function dateTimeDeserializer(key, value) {
|
|
19250
19250
|
if (typeof value === "string") {
|
|
@@ -19283,7 +19283,7 @@ var require_lib = __commonJS({
|
|
|
19283
19283
|
err.result = response.result;
|
|
19284
19284
|
reject(err);
|
|
19285
19285
|
} else {
|
|
19286
|
-
|
|
19286
|
+
resolve7(response);
|
|
19287
19287
|
}
|
|
19288
19288
|
}));
|
|
19289
19289
|
});
|
|
@@ -19552,11 +19552,11 @@ import { EOL as EOL3 } from "os";
|
|
|
19552
19552
|
import { constants, promises } from "fs";
|
|
19553
19553
|
var __awaiter = function(thisArg, _arguments, P, generator) {
|
|
19554
19554
|
function adopt(value) {
|
|
19555
|
-
return value instanceof P ? value : new P(function(
|
|
19556
|
-
|
|
19555
|
+
return value instanceof P ? value : new P(function(resolve7) {
|
|
19556
|
+
resolve7(value);
|
|
19557
19557
|
});
|
|
19558
19558
|
}
|
|
19559
|
-
return new (P || (P = Promise))(function(
|
|
19559
|
+
return new (P || (P = Promise))(function(resolve7, reject) {
|
|
19560
19560
|
function fulfilled(value) {
|
|
19561
19561
|
try {
|
|
19562
19562
|
step(generator.next(value));
|
|
@@ -19572,7 +19572,7 @@ var __awaiter = function(thisArg, _arguments, P, generator) {
|
|
|
19572
19572
|
}
|
|
19573
19573
|
}
|
|
19574
19574
|
function step(result) {
|
|
19575
|
-
result.done ?
|
|
19575
|
+
result.done ? resolve7(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
19576
19576
|
}
|
|
19577
19577
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
19578
19578
|
});
|
|
@@ -19939,11 +19939,11 @@ var httpClient = __toESM(require_lib(), 1);
|
|
|
19939
19939
|
var import_undici2 = __toESM(require_undici(), 1);
|
|
19940
19940
|
var __awaiter2 = function(thisArg, _arguments, P, generator) {
|
|
19941
19941
|
function adopt(value) {
|
|
19942
|
-
return value instanceof P ? value : new P(function(
|
|
19943
|
-
|
|
19942
|
+
return value instanceof P ? value : new P(function(resolve7) {
|
|
19943
|
+
resolve7(value);
|
|
19944
19944
|
});
|
|
19945
19945
|
}
|
|
19946
|
-
return new (P || (P = Promise))(function(
|
|
19946
|
+
return new (P || (P = Promise))(function(resolve7, reject) {
|
|
19947
19947
|
function fulfilled(value) {
|
|
19948
19948
|
try {
|
|
19949
19949
|
step(generator.next(value));
|
|
@@ -19959,7 +19959,7 @@ var __awaiter2 = function(thisArg, _arguments, P, generator) {
|
|
|
19959
19959
|
}
|
|
19960
19960
|
}
|
|
19961
19961
|
function step(result) {
|
|
19962
|
-
result.done ?
|
|
19962
|
+
result.done ? resolve7(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
19963
19963
|
}
|
|
19964
19964
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
19965
19965
|
});
|
|
@@ -23589,7 +23589,7 @@ function getOctokit(token, options, ...additionalPlugins) {
|
|
|
23589
23589
|
}
|
|
23590
23590
|
|
|
23591
23591
|
// src/action/index.ts
|
|
23592
|
-
import { resolve as
|
|
23592
|
+
import { resolve as resolve6 } from "path";
|
|
23593
23593
|
|
|
23594
23594
|
// src/engine/analyzer.ts
|
|
23595
23595
|
import { readFile as readFile2, readdir as readdir2, stat as stat3 } from "fs/promises";
|
|
@@ -24295,11 +24295,13 @@ function mergeConfig(base, overrides) {
|
|
|
24295
24295
|
}
|
|
24296
24296
|
|
|
24297
24297
|
// src/engine/selector.ts
|
|
24298
|
-
import { createHash as
|
|
24298
|
+
import { createHash as createHash3 } from "crypto";
|
|
24299
24299
|
|
|
24300
24300
|
// src/govern/secrets.ts
|
|
24301
24301
|
import { readFile as readFile3 } from "fs/promises";
|
|
24302
|
-
import {
|
|
24302
|
+
import { readFileSync as readFileSync2, existsSync as existsSync4, mkdirSync, writeFileSync } from "fs";
|
|
24303
|
+
import { resolve as resolve3, relative as relative3, join as join3, dirname as dirname2 } from "path";
|
|
24304
|
+
import { createHash as createHash2 } from "crypto";
|
|
24303
24305
|
var BUILTIN_PATTERNS = [
|
|
24304
24306
|
// API Keys
|
|
24305
24307
|
{ type: "api-key", source: `(?:api[_-]?key|apikey)\\s*[:=]\\s*['"]?([a-zA-Z0-9_\\-]{20,})['"]?`, flags: "gi", severity: "critical", description: "API Key" },
|
|
@@ -24324,15 +24326,66 @@ var BUILTIN_PATTERNS = [
|
|
|
24324
24326
|
{ type: "connection-string", source: `(?:mongodb(?:\\+srv)?|postgres(?:ql)?|mysql|redis|amqp):\\/\\/[^\\s'"]+:[^\\s'"]+@[^\\s'"]+`, flags: "gi", severity: "critical", description: "Database Connection String" },
|
|
24325
24327
|
{ type: "connection-string", source: `(?:DATABASE_URL|REDIS_URL|MONGODB_URI)\\s*[:=]\\s*['"]?([^\\s'"]{10,})['"]?`, flags: "gi", severity: "high", description: "Database URL" },
|
|
24326
24328
|
// Environment variables with secrets
|
|
24327
|
-
{ type: "env-variable", source: `(?:SECRET|PRIVATE|ENCRYPTION)[_-]?(?:KEY|TOKEN|PASS)\\s*[:=]\\s*['"]?([^\\s'"]{8,})['"]?`, flags: "gi", severity: "high", description: "Secret Environment Variable" }
|
|
24329
|
+
{ type: "env-variable", source: `(?:SECRET|PRIVATE|ENCRYPTION)[_-]?(?:KEY|TOKEN|PASS)\\s*[:=]\\s*['"]?([^\\s'"]{8,})['"]?`, flags: "gi", severity: "high", description: "Secret Environment Variable" },
|
|
24330
|
+
// Stripe
|
|
24331
|
+
{ type: "api-key", source: "sk_live_[a-zA-Z0-9]{24,}", flags: "g", severity: "critical", description: "Stripe Live Secret Key" },
|
|
24332
|
+
{ type: "api-key", source: "pk_live_[a-zA-Z0-9]{24,}", flags: "g", severity: "high", description: "Stripe Live Publishable Key" },
|
|
24333
|
+
{ type: "api-key", source: "rk_live_[a-zA-Z0-9]{24,}", flags: "g", severity: "critical", description: "Stripe Restricted Key" },
|
|
24334
|
+
// Slack
|
|
24335
|
+
{ type: "token", source: "xoxb-[0-9]{10,}-[0-9]{10,}-[a-zA-Z0-9]{24,}", flags: "g", severity: "critical", description: "Slack Bot Token" },
|
|
24336
|
+
{ type: "token", source: "xoxp-[0-9]{10,}-[0-9]{10,}-[a-zA-Z0-9]{24,}", flags: "g", severity: "critical", description: "Slack User Token" },
|
|
24337
|
+
{ type: "api-key", source: "https://hooks\\.slack\\.com/services/T[a-zA-Z0-9_]+/B[a-zA-Z0-9_]+/[a-zA-Z0-9_]+", flags: "g", severity: "high", description: "Slack Webhook URL" },
|
|
24338
|
+
// Google
|
|
24339
|
+
{ type: "api-key", source: "AIza[0-9A-Za-z_-]{35}", flags: "g", severity: "high", description: "Google API Key" },
|
|
24340
|
+
{ type: "token", source: "ya29\\.[0-9A-Za-z_-]+", flags: "g", severity: "high", description: "Google OAuth Token" },
|
|
24341
|
+
// Azure
|
|
24342
|
+
{ type: "api-key", source: "(?:AccountKey|SharedAccessKey)\\s*=\\s*[a-zA-Z0-9+/=]{40,}", flags: "g", severity: "critical", description: "Azure Storage Key" },
|
|
24343
|
+
// Twilio
|
|
24344
|
+
{ type: "api-key", source: "AC[a-f0-9]{32}", flags: "g", severity: "high", description: "Twilio Account SID" },
|
|
24345
|
+
// SendGrid
|
|
24346
|
+
{ type: "api-key", source: "SG\\.[a-zA-Z0-9_-]{22}\\.[a-zA-Z0-9_-]{43}", flags: "g", severity: "critical", description: "SendGrid API Key" },
|
|
24347
|
+
// JWT
|
|
24348
|
+
{ type: "token", source: "eyJ[a-zA-Z0-9_-]{10,}\\.eyJ[a-zA-Z0-9_-]{10,}\\.[a-zA-Z0-9_-]{10,}", flags: "g", severity: "high", description: "JSON Web Token" },
|
|
24349
|
+
// Datadog
|
|
24350
|
+
{ type: "api-key", source: `(?:DD_API_KEY|DATADOG_API_KEY)\\s*[:=]\\s*['"]?([a-f0-9]{32})['"]?`, flags: "gi", severity: "critical", description: "Datadog API Key" },
|
|
24351
|
+
{ type: "api-key", source: `(?:DD_APP_KEY|DATADOG_APP_KEY)\\s*[:=]\\s*['"]?([a-f0-9]{40})['"]?`, flags: "gi", severity: "critical", description: "Datadog App Key" },
|
|
24352
|
+
// Sentry
|
|
24353
|
+
{ type: "connection-string", source: "https://[a-f0-9]{32}@[a-z0-9]+\\.ingest\\.sentry\\.io/[0-9]+", flags: "g", severity: "high", description: "Sentry DSN" },
|
|
24354
|
+
// Firebase
|
|
24355
|
+
{ type: "api-key", source: `(?:FIREBASE_API_KEY|FIREBASE_KEY)\\s*[:=]\\s*['"]?([a-zA-Z0-9_\\-]{30,})['"]?`, flags: "gi", severity: "high", description: "Firebase API Key" },
|
|
24356
|
+
{ type: "connection-string", source: `firebase[a-z]*:\\/\\/[^\\s'"]+`, flags: "gi", severity: "high", description: "Firebase URL" },
|
|
24357
|
+
// Supabase
|
|
24358
|
+
{ type: "api-key", source: "sbp_[a-f0-9]{40}", flags: "g", severity: "critical", description: "Supabase Service Key" },
|
|
24359
|
+
{ type: "token", source: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\\.[a-zA-Z0-9_-]{20,}\\.[a-zA-Z0-9_-]{20,}", flags: "g", severity: "high", description: "Supabase Anon/Service JWT" },
|
|
24360
|
+
// Vercel
|
|
24361
|
+
{ type: "token", source: `(?:VERCEL_TOKEN|VERCEL_API_TOKEN)\\s*[:=]\\s*['"]?([a-zA-Z0-9]{24,})['"]?`, flags: "gi", severity: "critical", description: "Vercel Token" },
|
|
24362
|
+
// Heroku
|
|
24363
|
+
{ type: "api-key", source: `(?:HEROKU_API_KEY|HEROKU_TOKEN)\\s*[:=]\\s*['"]?([a-f0-9\\-]{36,})['"]?`, flags: "gi", severity: "critical", description: "Heroku API Key" },
|
|
24364
|
+
// DigitalOcean
|
|
24365
|
+
{ type: "token", source: "dop_v1_[a-f0-9]{64}", flags: "g", severity: "critical", description: "DigitalOcean Personal Access Token" },
|
|
24366
|
+
{ type: "token", source: "doo_v1_[a-f0-9]{64}", flags: "g", severity: "critical", description: "DigitalOcean OAuth Token" },
|
|
24367
|
+
// Mailgun
|
|
24368
|
+
{ type: "api-key", source: "key-[a-zA-Z0-9]{32}", flags: "g", severity: "high", description: "Mailgun API Key" },
|
|
24369
|
+
// PII
|
|
24370
|
+
{ type: "pii", source: "\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b", flags: "g", severity: "medium", description: "Email Address (PII)" },
|
|
24371
|
+
{ type: "pii", source: "\\b(?!000|666|9\\d{2})(\\d{3})[-.]?(?!00)(\\d{2})[-.]?(?!0000)(\\d{4})\\b", flags: "g", severity: "high", description: "Possible SSN (PII)" }
|
|
24328
24372
|
];
|
|
24373
|
+
var _cachedBuiltinPatterns = null;
|
|
24374
|
+
function getBuiltinPatterns() {
|
|
24375
|
+
if (!_cachedBuiltinPatterns) {
|
|
24376
|
+
_cachedBuiltinPatterns = BUILTIN_PATTERNS.map((def) => ({
|
|
24377
|
+
type: def.type,
|
|
24378
|
+
pattern: new RegExp(def.source, def.flags),
|
|
24379
|
+
severity: def.severity,
|
|
24380
|
+
description: def.description
|
|
24381
|
+
}));
|
|
24382
|
+
}
|
|
24383
|
+
return _cachedBuiltinPatterns;
|
|
24384
|
+
}
|
|
24329
24385
|
function buildPatterns(customPatterns = []) {
|
|
24330
|
-
const
|
|
24331
|
-
|
|
24332
|
-
|
|
24333
|
-
severity: def.severity,
|
|
24334
|
-
description: def.description
|
|
24335
|
-
}));
|
|
24386
|
+
const builtins = getBuiltinPatterns();
|
|
24387
|
+
if (customPatterns.length === 0) return builtins;
|
|
24388
|
+
const patterns = [...builtins];
|
|
24336
24389
|
for (const custom of customPatterns) {
|
|
24337
24390
|
try {
|
|
24338
24391
|
patterns.push({
|
|
@@ -24346,7 +24399,7 @@ function buildPatterns(customPatterns = []) {
|
|
|
24346
24399
|
}
|
|
24347
24400
|
return patterns;
|
|
24348
24401
|
}
|
|
24349
|
-
function scanContentForSecrets(content, filePath, customPatterns = []) {
|
|
24402
|
+
function scanContentForSecrets(content, filePath, customPatterns = [], extraPiiSafeDomains) {
|
|
24350
24403
|
const findings = [];
|
|
24351
24404
|
const lines = content.split("\n");
|
|
24352
24405
|
const allPatterns = buildPatterns(customPatterns);
|
|
@@ -24358,6 +24411,7 @@ function scanContentForSecrets(content, filePath, customPatterns = []) {
|
|
|
24358
24411
|
while ((match = secretPattern.pattern.exec(line)) !== null) {
|
|
24359
24412
|
const matchText = match[0];
|
|
24360
24413
|
if (isTemplateOrPlaceholder(matchText)) continue;
|
|
24414
|
+
if (secretPattern.type === "pii" && isSafeEmail(matchText, extraPiiSafeDomains)) continue;
|
|
24361
24415
|
findings.push({
|
|
24362
24416
|
type: secretPattern.type,
|
|
24363
24417
|
file: filePath,
|
|
@@ -24405,6 +24459,36 @@ function isTemplateOrPlaceholder(value) {
|
|
|
24405
24459
|
];
|
|
24406
24460
|
return placeholders.some((p) => p.test(value));
|
|
24407
24461
|
}
|
|
24462
|
+
var PII_SAFE_EMAIL_DOMAINS = /* @__PURE__ */ new Set([
|
|
24463
|
+
"example.com",
|
|
24464
|
+
"example.org",
|
|
24465
|
+
"example.net",
|
|
24466
|
+
"test.com",
|
|
24467
|
+
"test.org",
|
|
24468
|
+
"test.net",
|
|
24469
|
+
"localhost",
|
|
24470
|
+
"localhost.localdomain",
|
|
24471
|
+
"email.com",
|
|
24472
|
+
"mail.com",
|
|
24473
|
+
"foo.com",
|
|
24474
|
+
"bar.com",
|
|
24475
|
+
"baz.com",
|
|
24476
|
+
"acme.com",
|
|
24477
|
+
"company.com",
|
|
24478
|
+
"corp.com",
|
|
24479
|
+
"noreply.com",
|
|
24480
|
+
"no-reply.com",
|
|
24481
|
+
"users.noreply.github.com",
|
|
24482
|
+
"placeholder.com"
|
|
24483
|
+
]);
|
|
24484
|
+
function isSafeEmail(value, extraDomains) {
|
|
24485
|
+
const match = value.match(/@([a-zA-Z0-9.-]+)$/);
|
|
24486
|
+
if (!match) return false;
|
|
24487
|
+
const domain = match[1].toLowerCase();
|
|
24488
|
+
if (PII_SAFE_EMAIL_DOMAINS.has(domain)) return true;
|
|
24489
|
+
if (extraDomains && extraDomains.has(domain)) return true;
|
|
24490
|
+
return false;
|
|
24491
|
+
}
|
|
24408
24492
|
function deduplicateFindings(findings) {
|
|
24409
24493
|
const seen = /* @__PURE__ */ new Set();
|
|
24410
24494
|
return findings.filter((f) => {
|
|
@@ -24414,12 +24498,281 @@ function deduplicateFindings(findings) {
|
|
|
24414
24498
|
return true;
|
|
24415
24499
|
});
|
|
24416
24500
|
}
|
|
24501
|
+
function fingerprintFinding(f) {
|
|
24502
|
+
return createHash2("sha256").update(`${f.file}:${f.type}:${f.match}`).digest("hex").slice(0, 32);
|
|
24503
|
+
}
|
|
24504
|
+
function getAllowlistPath(projectPath) {
|
|
24505
|
+
return join3(projectPath, ".cto", "audit", "allowlist.json");
|
|
24506
|
+
}
|
|
24507
|
+
function loadAllowlist(projectPath) {
|
|
24508
|
+
const filePath = getAllowlistPath(projectPath);
|
|
24509
|
+
if (!existsSync4(filePath)) return [];
|
|
24510
|
+
try {
|
|
24511
|
+
return JSON.parse(readFileSync2(filePath, "utf-8"));
|
|
24512
|
+
} catch {
|
|
24513
|
+
return [];
|
|
24514
|
+
}
|
|
24515
|
+
}
|
|
24516
|
+
function filterByAllowlist(findings, projectPath) {
|
|
24517
|
+
const allowlist = loadAllowlist(projectPath);
|
|
24518
|
+
if (allowlist.length === 0) return { filtered: findings, allowed: [] };
|
|
24519
|
+
const allowedFingerprints = new Set(allowlist.map((e) => e.fingerprint));
|
|
24520
|
+
const filtered = [];
|
|
24521
|
+
const allowed = [];
|
|
24522
|
+
for (const f of findings) {
|
|
24523
|
+
if (allowedFingerprints.has(fingerprintFinding(f))) {
|
|
24524
|
+
allowed.push(f);
|
|
24525
|
+
} else {
|
|
24526
|
+
filtered.push(f);
|
|
24527
|
+
}
|
|
24528
|
+
}
|
|
24529
|
+
return { filtered, allowed };
|
|
24530
|
+
}
|
|
24531
|
+
function getHashCachePath(projectPath) {
|
|
24532
|
+
return join3(projectPath, ".cto", "audit", ".hashcache.json");
|
|
24533
|
+
}
|
|
24534
|
+
function loadHashCache(projectPath) {
|
|
24535
|
+
const filePath = getHashCachePath(projectPath);
|
|
24536
|
+
if (!existsSync4(filePath)) return {};
|
|
24537
|
+
try {
|
|
24538
|
+
return JSON.parse(readFileSync2(filePath, "utf-8"));
|
|
24539
|
+
} catch {
|
|
24540
|
+
return {};
|
|
24541
|
+
}
|
|
24542
|
+
}
|
|
24543
|
+
function saveHashCache(projectPath, cache) {
|
|
24544
|
+
const filePath = getHashCachePath(projectPath);
|
|
24545
|
+
mkdirSync(dirname2(filePath), { recursive: true });
|
|
24546
|
+
writeFileSync(filePath, JSON.stringify(cache));
|
|
24547
|
+
}
|
|
24548
|
+
function hashContent(content) {
|
|
24549
|
+
return createHash2("sha256").update(content).digest("hex").slice(0, 16);
|
|
24550
|
+
}
|
|
24551
|
+
function getChangedFiles(projectPath, filePaths) {
|
|
24552
|
+
const oldCache = loadHashCache(projectPath);
|
|
24553
|
+
const newCache = {};
|
|
24554
|
+
const changed = [];
|
|
24555
|
+
const unchanged = [];
|
|
24556
|
+
for (const fp of filePaths) {
|
|
24557
|
+
try {
|
|
24558
|
+
const content = readFileSync2(fp, "utf-8");
|
|
24559
|
+
const relPath = relative3(resolve3(projectPath), resolve3(fp));
|
|
24560
|
+
const hash = hashContent(content);
|
|
24561
|
+
newCache[relPath] = hash;
|
|
24562
|
+
if (oldCache[relPath] === hash) {
|
|
24563
|
+
unchanged.push(fp);
|
|
24564
|
+
} else {
|
|
24565
|
+
changed.push(fp);
|
|
24566
|
+
}
|
|
24567
|
+
} catch {
|
|
24568
|
+
changed.push(fp);
|
|
24569
|
+
}
|
|
24570
|
+
}
|
|
24571
|
+
return { changed, unchanged, cache: newCache };
|
|
24572
|
+
}
|
|
24573
|
+
var DEFAULT_AUDIT_CONFIG = {
|
|
24574
|
+
severityOverrides: {},
|
|
24575
|
+
piiSafeDomains: [],
|
|
24576
|
+
customPatterns: [],
|
|
24577
|
+
entropyThreshold: 5,
|
|
24578
|
+
includePII: true,
|
|
24579
|
+
incrementalScan: true
|
|
24580
|
+
};
|
|
24581
|
+
function getAuditConfigPath(projectPath) {
|
|
24582
|
+
return join3(projectPath, ".cto", "audit", "config.json");
|
|
24583
|
+
}
|
|
24584
|
+
function loadAuditConfig(projectPath) {
|
|
24585
|
+
const filePath = getAuditConfigPath(projectPath);
|
|
24586
|
+
if (!existsSync4(filePath)) return { ...DEFAULT_AUDIT_CONFIG };
|
|
24587
|
+
try {
|
|
24588
|
+
const loaded = JSON.parse(readFileSync2(filePath, "utf-8"));
|
|
24589
|
+
return { ...DEFAULT_AUDIT_CONFIG, ...loaded };
|
|
24590
|
+
} catch {
|
|
24591
|
+
return { ...DEFAULT_AUDIT_CONFIG };
|
|
24592
|
+
}
|
|
24593
|
+
}
|
|
24594
|
+
function applySeverityOverrides(findings, overrides) {
|
|
24595
|
+
if (Object.keys(overrides).length === 0) return findings;
|
|
24596
|
+
return findings.map((f) => {
|
|
24597
|
+
const override = overrides[f.type];
|
|
24598
|
+
if (override) return { ...f, severity: override };
|
|
24599
|
+
return f;
|
|
24600
|
+
});
|
|
24601
|
+
}
|
|
24602
|
+
function shannonEntropy(str) {
|
|
24603
|
+
const freq = /* @__PURE__ */ new Map();
|
|
24604
|
+
for (const ch of str) {
|
|
24605
|
+
freq.set(ch, (freq.get(ch) || 0) + 1);
|
|
24606
|
+
}
|
|
24607
|
+
let entropy = 0;
|
|
24608
|
+
for (const count of freq.values()) {
|
|
24609
|
+
const p = count / str.length;
|
|
24610
|
+
if (p > 0) entropy -= p * Math.log2(p);
|
|
24611
|
+
}
|
|
24612
|
+
return entropy;
|
|
24613
|
+
}
|
|
24614
|
+
var HIGH_ENTROPY_RE = /['"]([a-zA-Z0-9+/=_\-]{30,})['"]|=\s*['"]?([a-zA-Z0-9+/=_\-]{30,})['"]?/g;
|
|
24615
|
+
var ENTROPY_SKIP = [
|
|
24616
|
+
/^[a-f0-9]{32,}$/i,
|
|
24617
|
+
// hex hashes
|
|
24618
|
+
/^[A-Z_]{30,}$/,
|
|
24619
|
+
// all-caps constants
|
|
24620
|
+
/^[a-z_]{30,}$/,
|
|
24621
|
+
// all-lowercase identifiers
|
|
24622
|
+
/^[a-zA-Z0-9+/]+=+$/,
|
|
24623
|
+
// base64 padding
|
|
24624
|
+
/^[a-z]+[A-Z][a-zA-Z]+$/,
|
|
24625
|
+
// camelCase identifiers
|
|
24626
|
+
/sha\d+-/i
|
|
24627
|
+
// integrity hashes (sha256-, sha512-)
|
|
24628
|
+
];
|
|
24629
|
+
function scanContentForHighEntropy(content, filePath, threshold = 5) {
|
|
24630
|
+
const findings = [];
|
|
24631
|
+
const lines = content.split("\n");
|
|
24632
|
+
for (let i = 0; i < lines.length; i++) {
|
|
24633
|
+
const line = lines[i];
|
|
24634
|
+
if (line.trim().startsWith("//") || line.trim().startsWith("#") || line.trim().startsWith("*")) continue;
|
|
24635
|
+
HIGH_ENTROPY_RE.lastIndex = 0;
|
|
24636
|
+
let match;
|
|
24637
|
+
while ((match = HIGH_ENTROPY_RE.exec(line)) !== null) {
|
|
24638
|
+
const value = match[1] || match[2];
|
|
24639
|
+
if (!value || value.length < 40) continue;
|
|
24640
|
+
if (isTemplateOrPlaceholder(value)) continue;
|
|
24641
|
+
if (ENTROPY_SKIP.some((p) => p.test(value))) continue;
|
|
24642
|
+
const entropy = shannonEntropy(value);
|
|
24643
|
+
if (entropy >= threshold) {
|
|
24644
|
+
findings.push({
|
|
24645
|
+
type: "high-entropy",
|
|
24646
|
+
file: filePath,
|
|
24647
|
+
line: i + 1,
|
|
24648
|
+
match: value,
|
|
24649
|
+
redacted: redactSecret(value),
|
|
24650
|
+
severity: entropy >= 5 ? "high" : "medium"
|
|
24651
|
+
});
|
|
24652
|
+
}
|
|
24653
|
+
}
|
|
24654
|
+
}
|
|
24655
|
+
return deduplicateFindings(findings);
|
|
24656
|
+
}
|
|
24657
|
+
async function auditProject(projectPath, filePaths, options = {}) {
|
|
24658
|
+
const savedConfig = loadAuditConfig(projectPath);
|
|
24659
|
+
const customPatterns = options.customPatterns ?? savedConfig.customPatterns;
|
|
24660
|
+
const entropyThreshold = options.entropyThreshold ?? savedConfig.entropyThreshold;
|
|
24661
|
+
const includePII = options.includePII ?? savedConfig.includePII;
|
|
24662
|
+
const useAllowlist = options.useAllowlist ?? true;
|
|
24663
|
+
const incrementalScan = options.incrementalScan ?? savedConfig.incrementalScan;
|
|
24664
|
+
const severityOverrides = options.severityOverrides ?? savedConfig.severityOverrides;
|
|
24665
|
+
let extraPiiDomains;
|
|
24666
|
+
const allExtraDomains = [...options.piiSafeDomains || [], ...savedConfig.piiSafeDomains];
|
|
24667
|
+
if (allExtraDomains.length > 0) {
|
|
24668
|
+
extraPiiDomains = new Set(allExtraDomains.map((d) => d.toLowerCase()));
|
|
24669
|
+
}
|
|
24670
|
+
let filesToScan = filePaths;
|
|
24671
|
+
let unchangedCount = 0;
|
|
24672
|
+
let newCache = null;
|
|
24673
|
+
if (incrementalScan) {
|
|
24674
|
+
const { changed, unchanged, cache } = getChangedFiles(projectPath, filePaths);
|
|
24675
|
+
newCache = cache;
|
|
24676
|
+
if (changed.length < filePaths.length) {
|
|
24677
|
+
filesToScan = changed;
|
|
24678
|
+
unchangedCount = unchanged.length;
|
|
24679
|
+
}
|
|
24680
|
+
}
|
|
24681
|
+
const allFindings = [];
|
|
24682
|
+
const filesWithSecrets = /* @__PURE__ */ new Set();
|
|
24683
|
+
for (const fp of filesToScan) {
|
|
24684
|
+
try {
|
|
24685
|
+
const content = await readFile3(fp, "utf-8");
|
|
24686
|
+
const relPath = relative3(resolve3(projectPath), resolve3(fp));
|
|
24687
|
+
const isTestFile = /\.(test|spec|mock)\.[jt]sx?$/.test(relPath) || relPath.includes("__tests__");
|
|
24688
|
+
const isDtsFile = relPath.endsWith(".d.ts");
|
|
24689
|
+
let findings = scanContentForSecrets(content, relPath, customPatterns, extraPiiDomains);
|
|
24690
|
+
if (!includePII) {
|
|
24691
|
+
findings = findings.filter((f) => f.type !== "pii");
|
|
24692
|
+
}
|
|
24693
|
+
const entropyFindings = isTestFile || isDtsFile ? [] : scanContentForHighEntropy(content, relPath, entropyThreshold);
|
|
24694
|
+
const combined = [...findings, ...entropyFindings];
|
|
24695
|
+
if (combined.length > 0) {
|
|
24696
|
+
filesWithSecrets.add(relPath);
|
|
24697
|
+
allFindings.push(...combined);
|
|
24698
|
+
}
|
|
24699
|
+
} catch {
|
|
24700
|
+
}
|
|
24701
|
+
}
|
|
24702
|
+
let finalFindings = applySeverityOverrides(allFindings, severityOverrides);
|
|
24703
|
+
let allowedCount = 0;
|
|
24704
|
+
if (useAllowlist) {
|
|
24705
|
+
const { filtered, allowed } = filterByAllowlist(finalFindings, projectPath);
|
|
24706
|
+
finalFindings = filtered;
|
|
24707
|
+
allowedCount = allowed.length;
|
|
24708
|
+
}
|
|
24709
|
+
finalFindings.sort((a, b) => {
|
|
24710
|
+
const order = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
24711
|
+
return order[a.severity] - order[b.severity];
|
|
24712
|
+
});
|
|
24713
|
+
if (newCache) {
|
|
24714
|
+
saveHashCache(projectPath, newCache);
|
|
24715
|
+
}
|
|
24716
|
+
const bySeverity = { critical: 0, high: 0, medium: 0, low: 0 };
|
|
24717
|
+
const byType = {};
|
|
24718
|
+
for (const f of finalFindings) {
|
|
24719
|
+
bySeverity[f.severity]++;
|
|
24720
|
+
byType[f.type] = (byType[f.type] || 0) + 1;
|
|
24721
|
+
}
|
|
24722
|
+
const recommendations = [];
|
|
24723
|
+
if (bySeverity.critical > 0) {
|
|
24724
|
+
recommendations.push("CRITICAL: Rotate all detected credentials immediately. They may already be compromised.");
|
|
24725
|
+
}
|
|
24726
|
+
if (byType["password"] > 0) {
|
|
24727
|
+
recommendations.push("Move passwords to environment variables or a secrets manager (AWS Secrets Manager, Vault, etc.).");
|
|
24728
|
+
}
|
|
24729
|
+
if (byType["api-key"] > 0 || byType["aws-key"] > 0) {
|
|
24730
|
+
recommendations.push("Use environment variables for API keys. Never commit them to source control.");
|
|
24731
|
+
}
|
|
24732
|
+
if (byType["connection-string"] > 0) {
|
|
24733
|
+
recommendations.push("Database connection strings should use environment variables, not hardcoded values.");
|
|
24734
|
+
}
|
|
24735
|
+
if (byType["private-key"] > 0) {
|
|
24736
|
+
recommendations.push("Private keys should NEVER be in source code. Use a key management service.");
|
|
24737
|
+
}
|
|
24738
|
+
if (byType["pii"] > 0) {
|
|
24739
|
+
recommendations.push("PII detected. Review for GDPR/CCPA compliance. Consider data anonymization.");
|
|
24740
|
+
}
|
|
24741
|
+
if (byType["high-entropy"] > 0) {
|
|
24742
|
+
recommendations.push("High-entropy strings detected that may be secrets. Review manually.");
|
|
24743
|
+
}
|
|
24744
|
+
if (finalFindings.length > 0) {
|
|
24745
|
+
recommendations.push("Add a .gitignore entry for .env files if not already present.");
|
|
24746
|
+
recommendations.push("Run `npx cto-ai-cli --audit` regularly or add to CI pipeline.");
|
|
24747
|
+
}
|
|
24748
|
+
if (finalFindings.length === 0) {
|
|
24749
|
+
recommendations.push("No secrets detected. Great job keeping your codebase clean!");
|
|
24750
|
+
}
|
|
24751
|
+
if (allowedCount > 0) {
|
|
24752
|
+
recommendations.push(`${allowedCount} finding(s) skipped via allowlist (.cto/audit/allowlist.json).`);
|
|
24753
|
+
}
|
|
24754
|
+
if (unchangedCount > 0) {
|
|
24755
|
+
recommendations.push(`${unchangedCount} unchanged file(s) skipped (incremental scan).`);
|
|
24756
|
+
}
|
|
24757
|
+
return {
|
|
24758
|
+
findings: finalFindings,
|
|
24759
|
+
summary: {
|
|
24760
|
+
totalFiles: filePaths.length,
|
|
24761
|
+
filesScanned: filesToScan.length,
|
|
24762
|
+
filesWithSecrets: filesWithSecrets.size,
|
|
24763
|
+
totalFindings: finalFindings.length,
|
|
24764
|
+
bySeverity,
|
|
24765
|
+
byType
|
|
24766
|
+
},
|
|
24767
|
+
recommendations
|
|
24768
|
+
};
|
|
24769
|
+
}
|
|
24417
24770
|
|
|
24418
24771
|
// src/engine/pruner.ts
|
|
24419
24772
|
import { Project as Project2, SyntaxKind as SyntaxKind2 } from "ts-morph";
|
|
24420
24773
|
import { readFile as readFile4 } from "fs/promises";
|
|
24421
|
-
import { existsSync as
|
|
24422
|
-
import { join as
|
|
24774
|
+
import { existsSync as existsSync5 } from "fs";
|
|
24775
|
+
import { join as join4 } from "path";
|
|
24423
24776
|
var TS_EXTENSIONS2 = /* @__PURE__ */ new Set(["ts", "tsx", "js", "jsx", "mts", "mjs"]);
|
|
24424
24777
|
async function pruneFile(file, level) {
|
|
24425
24778
|
if (level === "excluded") {
|
|
@@ -24665,9 +25018,9 @@ function addJSDoc(node, parts) {
|
|
|
24665
25018
|
function findTsConfig(filePath) {
|
|
24666
25019
|
let dir = filePath;
|
|
24667
25020
|
for (let i = 0; i < 10; i++) {
|
|
24668
|
-
dir =
|
|
24669
|
-
const candidate =
|
|
24670
|
-
if (
|
|
25021
|
+
dir = join4(dir, "..");
|
|
25022
|
+
const candidate = join4(dir, "tsconfig.json");
|
|
25023
|
+
if (existsSync5(candidate)) return candidate;
|
|
24671
25024
|
}
|
|
24672
25025
|
return void 0;
|
|
24673
25026
|
}
|
|
@@ -24934,7 +25287,7 @@ async function selectContext(input) {
|
|
|
24934
25287
|
);
|
|
24935
25288
|
const excludedRisk = excludedFiles.length > 0 ? Math.round(excludedFiles.reduce((s, f) => s + f.riskScore, 0) / excludedFiles.length) : 0;
|
|
24936
25289
|
const hashInput = selectedFiles.map((f) => `${f.relativePath}:${f.pruneLevel}`).sort().join("|") + `|budget:${budget}`;
|
|
24937
|
-
const hash =
|
|
25290
|
+
const hash = createHash3("sha256").update(hashInput).digest("hex").substring(0, 16);
|
|
24938
25291
|
return {
|
|
24939
25292
|
files: selectedFiles,
|
|
24940
25293
|
totalTokens: usedTokens,
|
|
@@ -25578,10 +25931,182 @@ function emptyResult2(baseBranch) {
|
|
|
25578
25931
|
};
|
|
25579
25932
|
}
|
|
25580
25933
|
|
|
25934
|
+
// src/engine/quality-gate.ts
|
|
25935
|
+
import { readFile as readFile5, writeFile as writeFile3, mkdir as mkdir2 } from "fs/promises";
|
|
25936
|
+
import { resolve as resolve5 } from "path";
|
|
25937
|
+
import { existsSync as existsSync6 } from "fs";
|
|
25938
|
+
var DEFAULT_GATE_CONFIG = {
|
|
25939
|
+
threshold: 70,
|
|
25940
|
+
failOnSecrets: true,
|
|
25941
|
+
failOnRegression: true,
|
|
25942
|
+
regressionLimit: 5,
|
|
25943
|
+
baselinePath: ".cto/baseline.json",
|
|
25944
|
+
secretSeverities: ["critical", "high"]
|
|
25945
|
+
};
|
|
25946
|
+
async function loadBaseline(projectPath, baselinePath) {
|
|
25947
|
+
const filePath = resolve5(projectPath, baselinePath || ".cto/baseline.json");
|
|
25948
|
+
if (!existsSync6(filePath)) return null;
|
|
25949
|
+
try {
|
|
25950
|
+
const content = await readFile5(filePath, "utf-8");
|
|
25951
|
+
return JSON.parse(content);
|
|
25952
|
+
} catch {
|
|
25953
|
+
return null;
|
|
25954
|
+
}
|
|
25955
|
+
}
|
|
25956
|
+
async function saveBaseline(projectPath, score, commit, branch, baselinePath) {
|
|
25957
|
+
const dir = resolve5(projectPath, ".cto");
|
|
25958
|
+
if (!existsSync6(dir)) await mkdir2(dir, { recursive: true });
|
|
25959
|
+
const baseline = {
|
|
25960
|
+
score: score.overall,
|
|
25961
|
+
grade: score.grade,
|
|
25962
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
25963
|
+
commit,
|
|
25964
|
+
branch,
|
|
25965
|
+
dimensions: {
|
|
25966
|
+
efficiency: score.dimensions.efficiency.score,
|
|
25967
|
+
coverage: score.dimensions.coverage.score,
|
|
25968
|
+
riskControl: score.dimensions.riskControl.score,
|
|
25969
|
+
structure: score.dimensions.structure.score,
|
|
25970
|
+
governance: score.dimensions.governance.score
|
|
25971
|
+
}
|
|
25972
|
+
};
|
|
25973
|
+
const filePath = resolve5(projectPath, baselinePath || ".cto/baseline.json");
|
|
25974
|
+
await writeFile3(filePath, JSON.stringify(baseline, null, 2));
|
|
25975
|
+
}
|
|
25976
|
+
async function runQualityGate(score, analysis, secretFindings, config = {}) {
|
|
25977
|
+
const cfg = { ...DEFAULT_GATE_CONFIG, ...config };
|
|
25978
|
+
const checks = [];
|
|
25979
|
+
const baseline = await loadBaseline(analysis.projectPath, cfg.baselinePath);
|
|
25980
|
+
const previousScore = baseline?.score ?? null;
|
|
25981
|
+
const delta = previousScore !== null ? score.overall - previousScore : null;
|
|
25982
|
+
const thresholdPassed = score.overall >= cfg.threshold;
|
|
25983
|
+
checks.push({
|
|
25984
|
+
name: "Score threshold",
|
|
25985
|
+
passed: thresholdPassed,
|
|
25986
|
+
detail: thresholdPassed ? `Score ${score.overall} \u2265 threshold ${cfg.threshold}` : `Score ${score.overall} < threshold ${cfg.threshold}`,
|
|
25987
|
+
severity: thresholdPassed ? "info" : "error"
|
|
25988
|
+
});
|
|
25989
|
+
const dangerousSecrets = secretFindings.filter(
|
|
25990
|
+
(f) => cfg.secretSeverities.includes(f.severity)
|
|
25991
|
+
);
|
|
25992
|
+
const secretsPassed = !cfg.failOnSecrets || dangerousSecrets.length === 0;
|
|
25993
|
+
checks.push({
|
|
25994
|
+
name: "No secrets detected",
|
|
25995
|
+
passed: secretsPassed,
|
|
25996
|
+
detail: secretsPassed ? "No critical/high severity secrets found" : `${dangerousSecrets.length} secret(s) with ${cfg.secretSeverities.join("/")} severity`,
|
|
25997
|
+
severity: secretsPassed ? "info" : "error"
|
|
25998
|
+
});
|
|
25999
|
+
let regressionPassed = true;
|
|
26000
|
+
if (cfg.failOnRegression && delta !== null) {
|
|
26001
|
+
regressionPassed = delta >= -cfg.regressionLimit;
|
|
26002
|
+
}
|
|
26003
|
+
checks.push({
|
|
26004
|
+
name: "No score regression",
|
|
26005
|
+
passed: regressionPassed,
|
|
26006
|
+
detail: delta !== null ? regressionPassed ? `Score changed by ${delta >= 0 ? "+" : ""}${delta} (limit: -${cfg.regressionLimit})` : `Score dropped by ${Math.abs(delta)} points (limit: -${cfg.regressionLimit})` : "No baseline found (first run)",
|
|
26007
|
+
severity: regressionPassed ? delta !== null && delta < 0 ? "warning" : "info" : "error"
|
|
26008
|
+
});
|
|
26009
|
+
const weakDimensions = Object.entries(score.dimensions).filter(([_, d]) => d.score < 50).map(([name]) => name);
|
|
26010
|
+
const dimensionsPassed = weakDimensions.length === 0;
|
|
26011
|
+
checks.push({
|
|
26012
|
+
name: "Dimension health",
|
|
26013
|
+
passed: dimensionsPassed,
|
|
26014
|
+
detail: dimensionsPassed ? "All dimensions above 50%" : `Weak dimensions: ${weakDimensions.join(", ")}`,
|
|
26015
|
+
severity: dimensionsPassed ? "info" : "warning"
|
|
26016
|
+
});
|
|
26017
|
+
const passed = checks.filter((c) => c.severity === "error").every((c) => c.passed);
|
|
26018
|
+
const prComment = generatePRComment(score, analysis, checks, baseline, delta);
|
|
26019
|
+
const summary2 = generateSummary(score, checks, passed);
|
|
26020
|
+
return {
|
|
26021
|
+
passed,
|
|
26022
|
+
score: score.overall,
|
|
26023
|
+
grade: score.grade,
|
|
26024
|
+
previousScore,
|
|
26025
|
+
delta,
|
|
26026
|
+
checks,
|
|
26027
|
+
baseline,
|
|
26028
|
+
prComment,
|
|
26029
|
+
summary: summary2
|
|
26030
|
+
};
|
|
26031
|
+
}
|
|
26032
|
+
function generatePRComment(score, analysis, checks, baseline, delta) {
|
|
26033
|
+
const gradeEmoji = score.grade.startsWith("A") ? "\u{1F7E2}" : score.grade.startsWith("B") ? "\u{1F535}" : score.grade.startsWith("C") ? "\u{1F7E1}" : "\u{1F534}";
|
|
26034
|
+
const allPassed = checks.filter((c) => c.severity === "error").every((c) => c.passed);
|
|
26035
|
+
const statusIcon = allPassed ? "\u2705" : "\u274C";
|
|
26036
|
+
const deltaStr = delta !== null ? ` (${delta >= 0 ? "+" : ""}${delta})` : "";
|
|
26037
|
+
const lines = [
|
|
26038
|
+
`## ${statusIcon} CTO Quality Gate ${allPassed ? "Passed" : "Failed"}`,
|
|
26039
|
+
"",
|
|
26040
|
+
`### ${gradeEmoji} Context Score: ${score.overall}/100 (${score.grade})${deltaStr}`,
|
|
26041
|
+
"",
|
|
26042
|
+
`> **${analysis.projectName}** \xB7 ${analysis.totalFiles} files \xB7 ${Math.round(analysis.totalTokens / 1e3)}K tokens`,
|
|
26043
|
+
"",
|
|
26044
|
+
"### Checks",
|
|
26045
|
+
"",
|
|
26046
|
+
"| Check | Status | Detail |",
|
|
26047
|
+
"|-------|--------|--------|"
|
|
26048
|
+
];
|
|
26049
|
+
for (const check of checks) {
|
|
26050
|
+
const icon = check.passed ? "\u2705" : check.severity === "warning" ? "\u26A0\uFE0F" : "\u274C";
|
|
26051
|
+
lines.push(`| ${check.name} | ${icon} | ${check.detail} |`);
|
|
26052
|
+
}
|
|
26053
|
+
lines.push("");
|
|
26054
|
+
lines.push("### Dimensions");
|
|
26055
|
+
lines.push("");
|
|
26056
|
+
lines.push("| Dimension | Score | vs Baseline |");
|
|
26057
|
+
lines.push("|-----------|-------|-------------|");
|
|
26058
|
+
for (const [name, dim] of Object.entries(score.dimensions)) {
|
|
26059
|
+
const prev = baseline?.dimensions[name];
|
|
26060
|
+
const diff = prev !== void 0 ? dim.score - prev : null;
|
|
26061
|
+
const diffStr = diff !== null ? `${diff >= 0 ? "+" : ""}${diff}` : "\u2014";
|
|
26062
|
+
const bar = renderBar(dim.score);
|
|
26063
|
+
lines.push(`| ${name} | ${bar} ${dim.score}% | ${diffStr} |`);
|
|
26064
|
+
}
|
|
26065
|
+
lines.push("");
|
|
26066
|
+
lines.push("### Savings");
|
|
26067
|
+
lines.push("");
|
|
26068
|
+
lines.push(`| Metric | Value |`);
|
|
26069
|
+
lines.push(`|--------|-------|`);
|
|
26070
|
+
lines.push(`| Tokens saved | ${score.comparison.savedTokens.toLocaleString()} (${score.comparison.savedPercent}%) |`);
|
|
26071
|
+
lines.push(`| Monthly savings | $${score.comparison.monthlySavingsUSD.toFixed(2)} |`);
|
|
26072
|
+
if (score.insights.length > 0) {
|
|
26073
|
+
lines.push("");
|
|
26074
|
+
lines.push("### Insights");
|
|
26075
|
+
lines.push("");
|
|
26076
|
+
for (const insight of score.insights.slice(0, 5)) {
|
|
26077
|
+
const icon = insight.type === "strength" ? "\u2705" : insight.type === "weakness" ? "\u26A0\uFE0F" : "\u{1F4A1}";
|
|
26078
|
+
lines.push(`- ${icon} **${insight.title}** \u2014 ${insight.detail}`);
|
|
26079
|
+
}
|
|
26080
|
+
}
|
|
26081
|
+
lines.push("");
|
|
26082
|
+
lines.push("---");
|
|
26083
|
+
lines.push(`<sub>Generated by [CTO Quality Gate](https://npmjs.com/package/cto-ai-cli) \xB7 ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}</sub>`);
|
|
26084
|
+
return lines.join("\n");
|
|
26085
|
+
}
|
|
26086
|
+
function renderBar(score) {
|
|
26087
|
+
const filled = Math.round(score / 10);
|
|
26088
|
+
return "\u2588".repeat(filled) + "\u2591".repeat(10 - filled);
|
|
26089
|
+
}
|
|
26090
|
+
function generateSummary(score, checks, passed) {
|
|
26091
|
+
const status = passed ? "\u2705 PASSED" : "\u274C FAILED";
|
|
26092
|
+
const failedChecks = checks.filter((c) => !c.passed && c.severity === "error");
|
|
26093
|
+
const warnings = checks.filter((c) => !c.passed && c.severity === "warning");
|
|
26094
|
+
let summary2 = `Quality Gate ${status} \u2014 Score: ${score.overall}/100 (${score.grade})`;
|
|
26095
|
+
if (failedChecks.length > 0) {
|
|
26096
|
+
summary2 += `
|
|
26097
|
+
Failed: ${failedChecks.map((c) => c.name).join(", ")}`;
|
|
26098
|
+
}
|
|
26099
|
+
if (warnings.length > 0) {
|
|
26100
|
+
summary2 += `
|
|
26101
|
+
Warnings: ${warnings.map((c) => c.name).join(", ")}`;
|
|
26102
|
+
}
|
|
26103
|
+
return summary2;
|
|
26104
|
+
}
|
|
26105
|
+
|
|
25581
26106
|
// src/action/index.ts
|
|
25582
26107
|
async function run() {
|
|
25583
26108
|
try {
|
|
25584
|
-
const projectPath =
|
|
26109
|
+
const projectPath = resolve6(getInput("path") || ".");
|
|
25585
26110
|
const budget = parseInt(getInput("budget") || "50000", 10);
|
|
25586
26111
|
const task = getInput("task") || "general code review and refactoring";
|
|
25587
26112
|
const token = getInput("github-token") || process.env.GITHUB_TOKEN || "";
|
|
@@ -25658,11 +26183,30 @@ async function run() {
|
|
|
25658
26183
|
`---`,
|
|
25659
26184
|
`<sub>Generated by [CTO Context Score](https://github.com/cto-ai/cto-ai-cli) \xB7 ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}</sub>`
|
|
25660
26185
|
].join("\n");
|
|
26186
|
+
const threshold = parseInt(getInput("threshold") || "70", 10);
|
|
26187
|
+
const failOnSecrets = getInput("fail-on-secrets") !== "false";
|
|
26188
|
+
const failOnRegression = getInput("fail-on-regression") !== "false";
|
|
26189
|
+
const shouldSaveBaseline = getInput("save-baseline") !== "false";
|
|
26190
|
+
const filePaths = analysis.files.map((f) => f.path);
|
|
26191
|
+
const auditResult = await auditProject(projectPath, filePaths, { includePII: false });
|
|
26192
|
+
info(` Secrets scan: ${auditResult.summary.totalFindings} findings`);
|
|
26193
|
+
const gateResult = await runQualityGate(score, analysis, auditResult.findings, {
|
|
26194
|
+
threshold,
|
|
26195
|
+
failOnSecrets,
|
|
26196
|
+
failOnRegression
|
|
26197
|
+
});
|
|
26198
|
+
info(` Quality Gate: ${gateResult.passed ? "PASSED" : "FAILED"}`);
|
|
26199
|
+
if (shouldSaveBaseline) {
|
|
26200
|
+
await saveBaseline(projectPath, score);
|
|
26201
|
+
info(" Baseline saved");
|
|
26202
|
+
}
|
|
25661
26203
|
setOutput("score", score.overall.toString());
|
|
25662
26204
|
setOutput("grade", score.grade);
|
|
26205
|
+
setOutput("passed", gateResult.passed.toString());
|
|
25663
26206
|
setOutput("saved-percent", score.comparison.savedPercent.toString());
|
|
25664
26207
|
setOutput("monthly-savings", score.comparison.monthlySavingsUSD.toFixed(2));
|
|
25665
|
-
setOutput("
|
|
26208
|
+
setOutput("gate-summary", gateResult.summary);
|
|
26209
|
+
setOutput("json", JSON.stringify({ score, benchmark, gate: gateResult }));
|
|
25666
26210
|
if (commentOnPR && isPR && token) {
|
|
25667
26211
|
const octokit = getOctokit(token);
|
|
25668
26212
|
const { owner, repo } = context2.repo;
|
|
@@ -25698,6 +26242,8 @@ async function run() {
|
|
|
25698
26242
|
summary.addHeading(`${gradeEmoji} Context Score: ${score.overall}/100 (${score.grade})`).addRaw(body).write();
|
|
25699
26243
|
if (failBelow > 0 && score.overall < failBelow) {
|
|
25700
26244
|
setFailed(`Context Score ${score.overall} is below threshold ${failBelow}`);
|
|
26245
|
+
} else if (!gateResult.passed) {
|
|
26246
|
+
setFailed(gateResult.summary);
|
|
25701
26247
|
}
|
|
25702
26248
|
} catch (error2) {
|
|
25703
26249
|
if (error2 instanceof Error) {
|