securewithtrace 0.31.0 → 0.32.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/dist/index.js +1894 -495
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6322,29 +6322,29 @@ var ZodFunction = class _ZodFunction extends ZodType {
|
|
|
6322
6322
|
const params = { errorMap: ctx.common.contextualErrorMap };
|
|
6323
6323
|
const fn = ctx.data;
|
|
6324
6324
|
if (this._def.returns instanceof ZodPromise) {
|
|
6325
|
-
const
|
|
6325
|
+
const me2 = this;
|
|
6326
6326
|
return OK(async function(...args) {
|
|
6327
6327
|
const error48 = new ZodError([]);
|
|
6328
|
-
const parsedArgs = await
|
|
6328
|
+
const parsedArgs = await me2._def.args.parseAsync(args, params).catch((e2) => {
|
|
6329
6329
|
error48.addIssue(makeArgsIssue(args, e2));
|
|
6330
6330
|
throw error48;
|
|
6331
6331
|
});
|
|
6332
6332
|
const result = await Reflect.apply(fn, this, parsedArgs);
|
|
6333
|
-
const parsedReturns = await
|
|
6333
|
+
const parsedReturns = await me2._def.returns._def.type.parseAsync(result, params).catch((e2) => {
|
|
6334
6334
|
error48.addIssue(makeReturnsIssue(result, e2));
|
|
6335
6335
|
throw error48;
|
|
6336
6336
|
});
|
|
6337
6337
|
return parsedReturns;
|
|
6338
6338
|
});
|
|
6339
6339
|
} else {
|
|
6340
|
-
const
|
|
6340
|
+
const me2 = this;
|
|
6341
6341
|
return OK(function(...args) {
|
|
6342
|
-
const parsedArgs =
|
|
6342
|
+
const parsedArgs = me2._def.args.safeParse(args, params);
|
|
6343
6343
|
if (!parsedArgs.success) {
|
|
6344
6344
|
throw new ZodError([makeArgsIssue(args, parsedArgs.error)]);
|
|
6345
6345
|
}
|
|
6346
6346
|
const result = Reflect.apply(fn, this, parsedArgs.data);
|
|
6347
|
-
const parsedReturns =
|
|
6347
|
+
const parsedReturns = me2._def.returns.safeParse(result, params);
|
|
6348
6348
|
if (!parsedReturns.success) {
|
|
6349
6349
|
throw new ZodError([makeReturnsIssue(result, parsedReturns.error)]);
|
|
6350
6350
|
}
|
|
@@ -10176,7 +10176,7 @@ var $ZodBase64 = /* @__PURE__ */ $constructor("$ZodBase64", (inst, def) => {
|
|
|
10176
10176
|
function isValidBase64URL(data) {
|
|
10177
10177
|
if (!base64url.test(data))
|
|
10178
10178
|
return false;
|
|
10179
|
-
const base643 = data.replace(/[-_]/g, (
|
|
10179
|
+
const base643 = data.replace(/[-_]/g, (c49) => c49 === "-" ? "+" : "/");
|
|
10180
10180
|
const padded = base643.padEnd(Math.ceil(base643.length / 4) * 4, "=");
|
|
10181
10181
|
return isValidBase64(padded);
|
|
10182
10182
|
}
|
|
@@ -20220,9 +20220,9 @@ var ZodDate2 = /* @__PURE__ */ $constructor("ZodDate", (inst, def) => {
|
|
|
20220
20220
|
inst._zod.processJSONSchema = (ctx, json2, params) => dateProcessor(inst, ctx, json2, params);
|
|
20221
20221
|
inst.min = (value, params) => inst.check(_gte(value, params));
|
|
20222
20222
|
inst.max = (value, params) => inst.check(_lte(value, params));
|
|
20223
|
-
const
|
|
20224
|
-
inst.minDate =
|
|
20225
|
-
inst.maxDate =
|
|
20223
|
+
const c49 = inst._zod.bag;
|
|
20224
|
+
inst.minDate = c49.minimum ? new Date(c49.minimum) : null;
|
|
20225
|
+
inst.maxDate = c49.maximum ? new Date(c49.maximum) : null;
|
|
20226
20226
|
});
|
|
20227
20227
|
function date3(params) {
|
|
20228
20228
|
return _date(ZodDate2, params);
|
|
@@ -21504,7 +21504,8 @@ var PentestEditEntityValues = [
|
|
|
21504
21504
|
"PENTEST_TOOL_RUN",
|
|
21505
21505
|
"PENTEST_ATTESTATION",
|
|
21506
21506
|
"PENTEST_REPORT",
|
|
21507
|
-
"PENTEST_EXPLOIT_ARTIFACT"
|
|
21507
|
+
"PENTEST_EXPLOIT_ARTIFACT",
|
|
21508
|
+
"PENTEST_FINDING_RETEST"
|
|
21508
21509
|
];
|
|
21509
21510
|
var PentestEditEntity = external_exports.enum(PentestEditEntityValues);
|
|
21510
21511
|
var PentestEditActionValues = [
|
|
@@ -21688,10 +21689,11 @@ var AgentSessionIdParamsSchema = AgentSessionsParamsSchema.extend({
|
|
|
21688
21689
|
var AgentSessionEventIdParamsSchema = AgentSessionIdParamsSchema.extend({
|
|
21689
21690
|
eventId: external_exports.uuid()
|
|
21690
21691
|
});
|
|
21692
|
+
var MAX_AGENT_SESSION_MAX_USD = 1500;
|
|
21691
21693
|
var CreateAgentSessionCommonSchema = external_exports.object({
|
|
21692
21694
|
provider: AgentSessionProvider.optional(),
|
|
21693
21695
|
model: external_exports.string().min(1).max(200).optional(),
|
|
21694
|
-
maxUsd: external_exports.number().positive().max(
|
|
21696
|
+
maxUsd: external_exports.number().positive().max(MAX_AGENT_SESSION_MAX_USD).optional(),
|
|
21695
21697
|
maxWallClockMin: external_exports.number().int().positive().max(24 * 60).optional()
|
|
21696
21698
|
});
|
|
21697
21699
|
var CreateAgentSessionRequestSchema = external_exports.discriminatedUnion("type", [
|
|
@@ -21701,7 +21703,17 @@ var CreateAgentSessionRequestSchema = external_exports.discriminatedUnion("type"
|
|
|
21701
21703
|
}),
|
|
21702
21704
|
CreateAgentSessionCommonSchema.extend({
|
|
21703
21705
|
type: external_exports.literal("CODE_REVIEW"),
|
|
21704
|
-
focus: external_exports.string().min(1).max(2e3).optional()
|
|
21706
|
+
focus: external_exports.string().min(1).max(2e3).optional(),
|
|
21707
|
+
/**
|
|
21708
|
+
* Which bound application this review reads the codebase through (multi-application
|
|
21709
|
+
* PR 4). REQUIRED once 2+ applications are bound — omitting it there is
|
|
21710
|
+
* `APPLICATION_REQUIRED`, because the silent alternative is N reviews all scoping
|
|
21711
|
+
* their threat model to the first binding and overwriting each other. Defaults to
|
|
21712
|
+
* the sole binding at 1, and is legitimately absent for a bindingless engagement.
|
|
21713
|
+
* Only CODE_REVIEW and PRODUCT_RECON carry it: the other types are engagement-wide
|
|
21714
|
+
* by design, and the discriminated union is what keeps it off them.
|
|
21715
|
+
*/
|
|
21716
|
+
applicationId: external_exports.uuid().optional()
|
|
21705
21717
|
}),
|
|
21706
21718
|
CreateAgentSessionCommonSchema.extend({
|
|
21707
21719
|
type: external_exports.literal("VALIDATION"),
|
|
@@ -21736,7 +21748,10 @@ var CreateAgentSessionRequestSchema = external_exports.discriminatedUnion("type"
|
|
|
21736
21748
|
// / VALIDATION / RECON.
|
|
21737
21749
|
CreateAgentSessionCommonSchema.extend({
|
|
21738
21750
|
type: external_exports.literal("PRODUCT_RECON"),
|
|
21739
|
-
focus: external_exports.string().min(1).max(2e3).optional()
|
|
21751
|
+
focus: external_exports.string().min(1).max(2e3).optional(),
|
|
21752
|
+
/** Which bound application this recon learns. Same rules as CODE_REVIEW's, except
|
|
21753
|
+
* a bindingless engagement is already rejected at prep (PRODUCT_RECON_NO_APPLICATION). */
|
|
21754
|
+
applicationId: external_exports.uuid().optional()
|
|
21740
21755
|
}),
|
|
21741
21756
|
// REPORT (report-generation-session RS3): the report-authoring session. The
|
|
21742
21757
|
// objective is server-built from the engagement (no repo/creds); `focus` is
|
|
@@ -21752,8 +21767,10 @@ var SendAgentSessionMessageRequestSchema = external_exports.object({
|
|
|
21752
21767
|
var ResumeAgentSessionRequestSchema = external_exports.object({
|
|
21753
21768
|
/** Manual failover: relaunch on the other provider (cold cache accepted). */
|
|
21754
21769
|
provider: AgentSessionProvider.optional(),
|
|
21755
|
-
/** Budget raise — required to leave WAITING_ON_STAFF(BUDGET_EXHAUSTED).
|
|
21756
|
-
|
|
21770
|
+
/** Budget raise — required to leave WAITING_ON_STAFF(BUDGET_EXHAUSTED). Same
|
|
21771
|
+
* lifetime ceiling as create: a raise past it is not expressible, which is why
|
|
21772
|
+
* the create cap had to move for the engagement-wide validator. */
|
|
21773
|
+
maxUsd: external_exports.number().positive().max(MAX_AGENT_SESSION_MAX_USD).optional()
|
|
21757
21774
|
});
|
|
21758
21775
|
var ListAgentSessionEventsQuerySchema = external_exports.object({
|
|
21759
21776
|
/** Return events with seq > sinceSeq (poll cursor). */
|
|
@@ -21765,6 +21782,12 @@ var AgentSessionSummarySchema = external_exports.object({
|
|
|
21765
21782
|
organizationId: external_exports.uuid(),
|
|
21766
21783
|
pentestId: external_exports.uuid(),
|
|
21767
21784
|
type: AgentSessionType,
|
|
21785
|
+
/**
|
|
21786
|
+
* The application this session is scoped to, or null for engagement-wide (PR 4).
|
|
21787
|
+
* Id only — `toSummary` is a pure row mapper feeding six call sites, and the staff
|
|
21788
|
+
* console already holds the bound applications it needs to resolve a name.
|
|
21789
|
+
*/
|
|
21790
|
+
applicationId: external_exports.uuid().nullable(),
|
|
21768
21791
|
status: AgentSessionStatus,
|
|
21769
21792
|
waitingReason: AgentSessionWaitingReason.nullable(),
|
|
21770
21793
|
failureReason: AgentSessionFailureReason.nullable(),
|
|
@@ -21861,11 +21884,30 @@ var OperatorPentestContextSchema = external_exports.object({
|
|
|
21861
21884
|
customerPriorityCategories: external_exports.array(external_exports.string()),
|
|
21862
21885
|
status: PentestStatus,
|
|
21863
21886
|
currentStage: PentestStage,
|
|
21887
|
+
/**
|
|
21888
|
+
* The lowest-ordinal binding. RETAINED rather than replaced by `applications`:
|
|
21889
|
+
* `apps/agent-session-host` mirrors this interface by hand and raw-casts the JSON
|
|
21890
|
+
* without a schema parse (`api-client.ts:858-872`), so dropping this field would
|
|
21891
|
+
* give a parked or in-flight session `undefined` for its application block with no
|
|
21892
|
+
* parse error and no log. It retires a release after no parked session predates
|
|
21893
|
+
* `applications`.
|
|
21894
|
+
*/
|
|
21864
21895
|
primaryApplication: external_exports.object({
|
|
21865
21896
|
name: external_exports.string(),
|
|
21866
21897
|
type: external_exports.string(),
|
|
21867
21898
|
applicationUrl: external_exports.string().nullable()
|
|
21868
21899
|
}).nullable(),
|
|
21900
|
+
/**
|
|
21901
|
+
* Every bound application, ordinal-ascending. Optional for the same host
|
|
21902
|
+
* raw-cast reason: an older host image ignores what it does not know about.
|
|
21903
|
+
*/
|
|
21904
|
+
applications: external_exports.array(
|
|
21905
|
+
external_exports.object({
|
|
21906
|
+
name: external_exports.string(),
|
|
21907
|
+
type: external_exports.string(),
|
|
21908
|
+
applicationUrl: external_exports.string().nullable()
|
|
21909
|
+
})
|
|
21910
|
+
).optional(),
|
|
21869
21911
|
environments: external_exports.array(
|
|
21870
21912
|
external_exports.object({
|
|
21871
21913
|
name: external_exports.string(),
|
|
@@ -22197,36 +22239,9 @@ function roleDisplay(role, roleLabel) {
|
|
|
22197
22239
|
return APPLICATION_REPOSITORY_ROLE_LABELS[role] ?? null;
|
|
22198
22240
|
}
|
|
22199
22241
|
|
|
22200
|
-
// ../../packages/core/src/ai-tooling/profile.ts
|
|
22201
|
-
var AI_TOOL_DETECTION = ["claude-code", "codex", "both", "neither"];
|
|
22202
|
-
var AI_TOOL_OVERRIDE = ["claude-code", "codex"];
|
|
22203
|
-
var Sha40 = external_exports.string().regex(/^[a-f0-9]{40}$/, "expected a 40-char hex git SHA");
|
|
22204
|
-
var AiToolingProfileSchema = external_exports.object({
|
|
22205
|
-
schemaVersion: external_exports.literal(1),
|
|
22206
|
-
detectedTool: external_exports.enum(AI_TOOL_DETECTION),
|
|
22207
|
-
overrideTool: external_exports.enum(AI_TOOL_OVERRIDE).nullable(),
|
|
22208
|
-
/** null = no detection has run yet (override-only seed); refresh on next scan. */
|
|
22209
|
-
detectedAt: external_exports.iso.datetime().nullable(),
|
|
22210
|
-
/** Scan commit-sha the detection ran against. null when detectedAt is null. */
|
|
22211
|
-
detectedCommitSha: Sha40.nullable(),
|
|
22212
|
-
evidence: external_exports.object({
|
|
22213
|
-
claudeMdSha: Sha40.nullable(),
|
|
22214
|
-
agentsMdSha: Sha40.nullable(),
|
|
22215
|
-
claudeMdMtime: external_exports.iso.datetime().nullable(),
|
|
22216
|
-
agentsMdMtime: external_exports.iso.datetime().nullable()
|
|
22217
|
-
}).strict()
|
|
22218
|
-
}).strict();
|
|
22219
|
-
|
|
22220
22242
|
// ../../packages/api-contracts/src/schemas/api/v1/repository.api.ts
|
|
22221
22243
|
var PlatformValues = ["GITHUB", "GITLAB", "BITBUCKET"];
|
|
22222
22244
|
var RepositoryStatusValues = ["CONNECTED", "DISCONNECTED"];
|
|
22223
|
-
var SetAiToolingProfileOverrideRequestSchema = external_exports.object({
|
|
22224
|
-
/** null clears the override and reverts to detection-driven resolution. */
|
|
22225
|
-
overrideTool: external_exports.enum(AI_TOOL_OVERRIDE).nullable()
|
|
22226
|
-
}).strict();
|
|
22227
|
-
var SetAiToolingProfileOverrideResponseSchema = external_exports.object({
|
|
22228
|
-
aiToolingProfile: AiToolingProfileSchema.nullable()
|
|
22229
|
-
}).strict();
|
|
22230
22245
|
var RepositoryIdParamsSchema = OrgIdParamsSchema.extend({
|
|
22231
22246
|
repositoryId: external_exports.uuid()
|
|
22232
22247
|
});
|
|
@@ -22251,13 +22266,6 @@ var RepositoryResponseSchema = external_exports.object({
|
|
|
22251
22266
|
githubDefaultBranch: external_exports.string(),
|
|
22252
22267
|
scanningBranch: external_exports.string().nullable(),
|
|
22253
22268
|
primaryLanguage: external_exports.string().nullable().optional(),
|
|
22254
|
-
/**
|
|
22255
|
-
* Null until the first post-scan detection writes a row, OR when the raw
|
|
22256
|
-
* JSONB fails strict-schema parsing (mapper falls back to null so the
|
|
22257
|
-
* response stays valid). PATCH override writes always preserve the live
|
|
22258
|
-
* `overrideTool` via `parseOverrideTool`.
|
|
22259
|
-
*/
|
|
22260
|
-
aiToolingProfile: AiToolingProfileSchema.nullable(),
|
|
22261
22269
|
createdAt: external_exports.date(),
|
|
22262
22270
|
updatedAt: external_exports.date()
|
|
22263
22271
|
});
|
|
@@ -22345,7 +22353,8 @@ var ConfirmScanningBranchDefaultsResponseSchema = external_exports.object({
|
|
|
22345
22353
|
});
|
|
22346
22354
|
|
|
22347
22355
|
// ../../packages/api-contracts/src/schemas/api/v1/application.api.ts
|
|
22348
|
-
var ApplicationTypeValues = ["WEB", "CLI", "MOBILE", "API_SERVICE"];
|
|
22356
|
+
var ApplicationTypeValues = ["WEB", "CLI", "MOBILE", "DESKTOP", "API_SERVICE"];
|
|
22357
|
+
var APPLICATION_NOTES_MAX_CHARS = 2e3;
|
|
22349
22358
|
var ApplicationRepositoryRoleValues = [
|
|
22350
22359
|
"FRONTEND",
|
|
22351
22360
|
"BACKEND_API",
|
|
@@ -22356,12 +22365,27 @@ var ApplicationRepositoryRoleValues = [
|
|
|
22356
22365
|
"MOBILE_CLIENT",
|
|
22357
22366
|
"OTHER"
|
|
22358
22367
|
];
|
|
22368
|
+
var ScopeDomainSourceValues = ["DERIVED", "MANUAL"];
|
|
22359
22369
|
var ApplicationIdParamsSchema = OrgIdParamsSchema.extend({
|
|
22360
22370
|
applicationId: external_exports.uuid()
|
|
22361
22371
|
});
|
|
22362
22372
|
var ApplicationRepositoryIdParamsSchema = ApplicationIdParamsSchema.extend({
|
|
22363
22373
|
applicationRepositoryId: external_exports.uuid()
|
|
22364
22374
|
});
|
|
22375
|
+
var AuthorizedDomainIdParamsSchema = ApplicationIdParamsSchema.extend({
|
|
22376
|
+
applicationAuthorizedDomainId: external_exports.uuid()
|
|
22377
|
+
});
|
|
22378
|
+
var AuthorizedDomainResponseSchema = external_exports.object({
|
|
22379
|
+
applicationAuthorizedDomainId: external_exports.uuid(),
|
|
22380
|
+
applicationId: external_exports.uuid(),
|
|
22381
|
+
organizationId: external_exports.uuid(),
|
|
22382
|
+
domain: external_exports.string(),
|
|
22383
|
+
source: external_exports.enum(ScopeDomainSourceValues),
|
|
22384
|
+
createdAt: external_exports.date()
|
|
22385
|
+
});
|
|
22386
|
+
var CreateAuthorizedDomainRequestSchema = external_exports.object({
|
|
22387
|
+
domain: external_exports.string().trim().min(1).max(253)
|
|
22388
|
+
}).strict();
|
|
22365
22389
|
var ApplicationRepositorySummarySchema = external_exports.object({
|
|
22366
22390
|
applicationRepositoryId: external_exports.uuid().nullable(),
|
|
22367
22391
|
applicationId: external_exports.uuid(),
|
|
@@ -22393,9 +22417,20 @@ var ApplicationResponseSchema = external_exports.object({
|
|
|
22393
22417
|
// reject application rows.
|
|
22394
22418
|
type: external_exports.enum(ApplicationTypeValues).default("WEB"),
|
|
22395
22419
|
applicationUrl: external_exports.string().nullable(),
|
|
22420
|
+
// Customer-authored free-text context, any type ("Advanced → Notes").
|
|
22421
|
+
notes: external_exports.string().nullable(),
|
|
22396
22422
|
helpCenterUrl: external_exports.string().nullable(),
|
|
22397
22423
|
documentationUrl: external_exports.string().nullable(),
|
|
22398
22424
|
repositories: external_exports.array(ApplicationRepositorySummarySchema),
|
|
22425
|
+
// Registrable domains RECON is authorized to discover subdomains under. The
|
|
22426
|
+
// Environments-tab panel hydrates from this payload (no client GET). Defaulted
|
|
22427
|
+
// (like `type`) so a new client reading a pre-this-release API during a rolling
|
|
22428
|
+
// deploy doesn't reject application rows that predate the field.
|
|
22429
|
+
authorizedDomains: external_exports.array(AuthorizedDomainResponseSchema).default([]),
|
|
22430
|
+
// Signed S3 URL for the Overview screenshot. Defaulted null so a new client
|
|
22431
|
+
// reading a pre-this-release API during a rolling deploy doesn't reject rows
|
|
22432
|
+
// that omit the field. The raw S3 key is never on the wire.
|
|
22433
|
+
screenshotUrl: external_exports.url().nullable().default(null),
|
|
22399
22434
|
createdAt: external_exports.date(),
|
|
22400
22435
|
updatedAt: external_exports.date()
|
|
22401
22436
|
});
|
|
@@ -22404,6 +22439,7 @@ var CreateApplicationRequestSchema = external_exports.object({
|
|
|
22404
22439
|
name: external_exports.string().min(1).max(200),
|
|
22405
22440
|
type: external_exports.enum(ApplicationTypeValues).default("WEB"),
|
|
22406
22441
|
applicationUrl: external_exports.url().max(2048).optional(),
|
|
22442
|
+
notes: external_exports.string().max(APPLICATION_NOTES_MAX_CHARS).optional(),
|
|
22407
22443
|
repositoryId: external_exports.uuid().optional(),
|
|
22408
22444
|
repositoryPath: external_exports.string().max(500).optional(),
|
|
22409
22445
|
helpCenterUrl: external_exports.url().max(2048).optional(),
|
|
@@ -22431,6 +22467,7 @@ var UpdateApplicationRepositoryLinkRequestSchema = external_exports.object({
|
|
|
22431
22467
|
var UpdateApplicationRequestSchema = external_exports.object({
|
|
22432
22468
|
name: external_exports.string().min(1).max(200).optional(),
|
|
22433
22469
|
applicationUrl: external_exports.url().max(2048).optional(),
|
|
22470
|
+
notes: external_exports.string().max(APPLICATION_NOTES_MAX_CHARS).nullable().optional(),
|
|
22434
22471
|
repositoryId: external_exports.uuid().nullable().optional(),
|
|
22435
22472
|
repositoryPath: external_exports.string().max(500).nullable().optional(),
|
|
22436
22473
|
helpCenterUrl: external_exports.url().max(2048).nullable().optional(),
|
|
@@ -22565,6 +22602,35 @@ var applicationContract = c4.router({
|
|
|
22565
22602
|
409: ErrorResponseSchema,
|
|
22566
22603
|
500: ErrorResponseSchema
|
|
22567
22604
|
}
|
|
22605
|
+
},
|
|
22606
|
+
addAuthorizedDomain: {
|
|
22607
|
+
method: "POST",
|
|
22608
|
+
path: "/organizations/:organizationId/applications/:applicationId/authorized-domains",
|
|
22609
|
+
pathParams: ApplicationIdParamsSchema,
|
|
22610
|
+
body: CreateAuthorizedDomainRequestSchema,
|
|
22611
|
+
responses: {
|
|
22612
|
+
201: AuthorizedDomainResponseSchema,
|
|
22613
|
+
// 400 = INVALID_DOMAIN (not a registrable domain / IP / bare suffix);
|
|
22614
|
+
// 409 = DOMAIN_ALREADY_AUTHORIZED.
|
|
22615
|
+
400: ErrorResponseSchema,
|
|
22616
|
+
401: ErrorResponseSchema,
|
|
22617
|
+
403: ErrorResponseSchema,
|
|
22618
|
+
404: ErrorResponseSchema,
|
|
22619
|
+
409: ErrorResponseSchema,
|
|
22620
|
+
500: ErrorResponseSchema
|
|
22621
|
+
}
|
|
22622
|
+
},
|
|
22623
|
+
deleteAuthorizedDomain: {
|
|
22624
|
+
method: "DELETE",
|
|
22625
|
+
path: "/organizations/:organizationId/applications/:applicationId/authorized-domains/:applicationAuthorizedDomainId",
|
|
22626
|
+
pathParams: AuthorizedDomainIdParamsSchema,
|
|
22627
|
+
responses: {
|
|
22628
|
+
204: DeleteResponseSchema,
|
|
22629
|
+
401: ErrorResponseSchema,
|
|
22630
|
+
403: ErrorResponseSchema,
|
|
22631
|
+
404: ErrorResponseSchema,
|
|
22632
|
+
500: ErrorResponseSchema
|
|
22633
|
+
}
|
|
22568
22634
|
}
|
|
22569
22635
|
});
|
|
22570
22636
|
|
|
@@ -22794,7 +22860,7 @@ var chatSessionContract = c6.router({
|
|
|
22794
22860
|
});
|
|
22795
22861
|
|
|
22796
22862
|
// ../../packages/api-contracts/src/schemas/api/v1/cloud-integration.api.ts
|
|
22797
|
-
var CloudProviderValues = ["AWS", "GCP", "AZURE", "VERCEL"];
|
|
22863
|
+
var CloudProviderValues = ["AWS", "GCP", "AZURE", "VERCEL", "CONVEX"];
|
|
22798
22864
|
var CloudIntegrationStatusValues = [
|
|
22799
22865
|
"PENDING",
|
|
22800
22866
|
"ACTIVE",
|
|
@@ -23304,6 +23370,107 @@ var DisconnectGcpCloudIntegrationResponseSchema = external_exports.object({
|
|
|
23304
23370
|
var CancelPendingGcpCloudIntegrationResponseSchema = external_exports.object({
|
|
23305
23371
|
deleted: external_exports.literal(true)
|
|
23306
23372
|
}).strict();
|
|
23373
|
+
var ConvexAccountIdParamsSchema = CloudIntegrationIdParamsSchema.extend({
|
|
23374
|
+
cloudProviderAccountId: external_exports.uuid()
|
|
23375
|
+
});
|
|
23376
|
+
var ConvexDeploymentIdParamsSchema = CloudIntegrationIdParamsSchema.extend({
|
|
23377
|
+
convexLinkedDeploymentId: external_exports.uuid()
|
|
23378
|
+
});
|
|
23379
|
+
var CreateConvexInstallIntentRequestSchema = external_exports.object({
|
|
23380
|
+
displayName: external_exports.string().trim().min(1).max(120).optional()
|
|
23381
|
+
}).strict();
|
|
23382
|
+
var FinalizeConvexCallbackRequestSchema = external_exports.object({
|
|
23383
|
+
code: external_exports.string().trim().min(1).max(4096),
|
|
23384
|
+
state: external_exports.string().trim().min(32).max(512)
|
|
23385
|
+
}).strict();
|
|
23386
|
+
var ConvexCloudIntegrationSummarySchema = external_exports.object({
|
|
23387
|
+
cloudIntegrationId: external_exports.uuid(),
|
|
23388
|
+
organizationId: external_exports.uuid(),
|
|
23389
|
+
provider: external_exports.literal("CONVEX"),
|
|
23390
|
+
status: CloudIntegrationStatusSchema,
|
|
23391
|
+
displayName: external_exports.string(),
|
|
23392
|
+
templateVersion: external_exports.string(),
|
|
23393
|
+
verifiedAt: external_exports.date().nullable(),
|
|
23394
|
+
disconnectedAt: external_exports.date().nullable(),
|
|
23395
|
+
disconnectedById: external_exports.uuid().nullable(),
|
|
23396
|
+
lastErrorCode: external_exports.string().nullable(),
|
|
23397
|
+
lastErrorMessage: external_exports.string().nullable(),
|
|
23398
|
+
createdAt: external_exports.date(),
|
|
23399
|
+
updatedAt: external_exports.date()
|
|
23400
|
+
}).strict();
|
|
23401
|
+
var ConvexLinkedDeploymentSummarySchema = external_exports.object({
|
|
23402
|
+
convexLinkedDeploymentId: external_exports.uuid(),
|
|
23403
|
+
organizationId: external_exports.uuid(),
|
|
23404
|
+
cloudIntegrationId: external_exports.uuid(),
|
|
23405
|
+
cloudProviderAccountId: external_exports.uuid(),
|
|
23406
|
+
cloudProviderConnectionId: external_exports.uuid(),
|
|
23407
|
+
convexProjectId: external_exports.number().int(),
|
|
23408
|
+
deploymentName: external_exports.string(),
|
|
23409
|
+
deploymentType: external_exports.string(),
|
|
23410
|
+
deploymentRegion: external_exports.string().nullable(),
|
|
23411
|
+
convexCloudUrl: external_exports.string(),
|
|
23412
|
+
convexSiteUrl: external_exports.string().nullable(),
|
|
23413
|
+
deploymentExpiresAt: external_exports.date().nullable(),
|
|
23414
|
+
/**
|
|
23415
|
+
* Whether a usable credential envelope is stored. NOT a scope claim: the key is
|
|
23416
|
+
* full-access, because Convex cannot mint a scoped one for an OAuth app. Read-only
|
|
23417
|
+
* is enforced by the broker that holds the key, never by the credential.
|
|
23418
|
+
*/
|
|
23419
|
+
hasStoredKey: external_exports.boolean(),
|
|
23420
|
+
status: CloudIntegrationStatusSchema,
|
|
23421
|
+
lastVerifiedAt: external_exports.date().nullable(),
|
|
23422
|
+
lastAuthErrorCode: external_exports.string().nullable(),
|
|
23423
|
+
createdAt: external_exports.date(),
|
|
23424
|
+
updatedAt: external_exports.date()
|
|
23425
|
+
}).strict();
|
|
23426
|
+
var ConvexCloudIntegrationListItemSchema = external_exports.object({
|
|
23427
|
+
integration: ConvexCloudIntegrationSummarySchema,
|
|
23428
|
+
deployments: external_exports.array(ConvexLinkedDeploymentSummarySchema)
|
|
23429
|
+
}).strict();
|
|
23430
|
+
var ListConvexCloudIntegrationsResponseSchema = external_exports.object({
|
|
23431
|
+
integrations: external_exports.array(ConvexCloudIntegrationListItemSchema)
|
|
23432
|
+
}).strict();
|
|
23433
|
+
var CreateConvexInstallIntentResponseSchema = external_exports.object({
|
|
23434
|
+
integration: ConvexCloudIntegrationSummarySchema,
|
|
23435
|
+
installUrl: external_exports.url()
|
|
23436
|
+
}).strict();
|
|
23437
|
+
var FinalizeConvexCallbackResponseSchema = external_exports.object({
|
|
23438
|
+
integration: ConvexCloudIntegrationSummarySchema,
|
|
23439
|
+
deployments: external_exports.array(ConvexLinkedDeploymentSummarySchema),
|
|
23440
|
+
/** Deployments beyond the CONVEX_MAX_DEPLOYMENTS cap that were not connected. */
|
|
23441
|
+
droppedDeploymentCount: external_exports.number().int().nonnegative()
|
|
23442
|
+
}).strict();
|
|
23443
|
+
var DisconnectConvexCloudIntegrationResponseSchema = external_exports.object({
|
|
23444
|
+
integration: ConvexCloudIntegrationSummarySchema,
|
|
23445
|
+
deploymentCount: external_exports.number().int().nonnegative(),
|
|
23446
|
+
clearedKeyCount: external_exports.number().int().nonnegative(),
|
|
23447
|
+
/**
|
|
23448
|
+
* Trace cannot revoke a Convex deploy key: there is no deployment-plane endpoint,
|
|
23449
|
+
* the key is not returned by list_deploy_keys, and delete_deploy_key needs an id
|
|
23450
|
+
* the mint never returns. Removing the Trace OAuth app is the only lever the
|
|
23451
|
+
* customer has. A closed union, so PR 2 owns the wording.
|
|
23452
|
+
*/
|
|
23453
|
+
revocationHint: external_exports.literal("REVOKE_OAUTH_APP"),
|
|
23454
|
+
convexApplicationsUrl: external_exports.url().nullable()
|
|
23455
|
+
}).strict();
|
|
23456
|
+
var DisconnectConvexProjectResponseSchema = external_exports.object({
|
|
23457
|
+
integration: ConvexCloudIntegrationSummarySchema,
|
|
23458
|
+
convexProjectId: external_exports.number().int(),
|
|
23459
|
+
deploymentCount: external_exports.number().int().nonnegative(),
|
|
23460
|
+
clearedKeyCount: external_exports.number().int().nonnegative(),
|
|
23461
|
+
revocationHint: external_exports.literal("REVOKE_OAUTH_APP"),
|
|
23462
|
+
convexApplicationsUrl: external_exports.url().nullable()
|
|
23463
|
+
}).strict();
|
|
23464
|
+
var DisconnectConvexDeploymentResponseSchema = external_exports.object({
|
|
23465
|
+
integration: ConvexCloudIntegrationSummarySchema,
|
|
23466
|
+
deployment: ConvexLinkedDeploymentSummarySchema,
|
|
23467
|
+
revocationHint: external_exports.literal("REVOKE_OAUTH_APP"),
|
|
23468
|
+
convexApplicationsUrl: external_exports.url().nullable()
|
|
23469
|
+
}).strict();
|
|
23470
|
+
var ReverifyConvexDeploymentResponseSchema = external_exports.object({
|
|
23471
|
+
integration: ConvexCloudIntegrationSummarySchema,
|
|
23472
|
+
deployment: ConvexLinkedDeploymentSummarySchema
|
|
23473
|
+
}).strict();
|
|
23307
23474
|
|
|
23308
23475
|
// ../../packages/api-contracts/src/contracts/v1/cloud-integration.ts
|
|
23309
23476
|
var c7 = initContract();
|
|
@@ -23604,6 +23771,103 @@ var cloudIntegrationContract = c7.router({
|
|
|
23604
23771
|
503: ErrorResponseSchema,
|
|
23605
23772
|
500: ErrorResponseSchema
|
|
23606
23773
|
}
|
|
23774
|
+
},
|
|
23775
|
+
listConvexIntegrations: {
|
|
23776
|
+
method: "GET",
|
|
23777
|
+
path: "/organizations/:organizationId/cloud-integrations/convex",
|
|
23778
|
+
pathParams: OrgIdParamsSchema,
|
|
23779
|
+
responses: {
|
|
23780
|
+
200: ListConvexCloudIntegrationsResponseSchema,
|
|
23781
|
+
401: ErrorResponseSchema,
|
|
23782
|
+
403: ErrorResponseSchema,
|
|
23783
|
+
404: ErrorResponseSchema,
|
|
23784
|
+
500: ErrorResponseSchema
|
|
23785
|
+
}
|
|
23786
|
+
},
|
|
23787
|
+
createConvexInstallIntent: {
|
|
23788
|
+
method: "POST",
|
|
23789
|
+
path: "/organizations/:organizationId/cloud-integrations/convex/install-intents",
|
|
23790
|
+
pathParams: OrgIdParamsSchema,
|
|
23791
|
+
body: CreateConvexInstallIntentRequestSchema,
|
|
23792
|
+
responses: {
|
|
23793
|
+
201: CreateConvexInstallIntentResponseSchema,
|
|
23794
|
+
400: ErrorResponseSchema,
|
|
23795
|
+
401: ErrorResponseSchema,
|
|
23796
|
+
403: ErrorResponseSchema,
|
|
23797
|
+
404: ErrorResponseSchema,
|
|
23798
|
+
409: ErrorResponseSchema,
|
|
23799
|
+
500: ErrorResponseSchema
|
|
23800
|
+
}
|
|
23801
|
+
},
|
|
23802
|
+
finalizeConvexCallback: {
|
|
23803
|
+
method: "POST",
|
|
23804
|
+
path: "/organizations/:organizationId/cloud-integrations/convex/callback",
|
|
23805
|
+
pathParams: OrgIdParamsSchema,
|
|
23806
|
+
body: FinalizeConvexCallbackRequestSchema,
|
|
23807
|
+
responses: {
|
|
23808
|
+
200: FinalizeConvexCallbackResponseSchema,
|
|
23809
|
+
400: ErrorResponseSchema,
|
|
23810
|
+
401: ErrorResponseSchema,
|
|
23811
|
+
403: ErrorResponseSchema,
|
|
23812
|
+
404: ErrorResponseSchema,
|
|
23813
|
+
409: ErrorResponseSchema,
|
|
23814
|
+
503: ErrorResponseSchema,
|
|
23815
|
+
500: ErrorResponseSchema
|
|
23816
|
+
}
|
|
23817
|
+
},
|
|
23818
|
+
disconnectConvexIntegration: {
|
|
23819
|
+
method: "DELETE",
|
|
23820
|
+
path: "/organizations/:organizationId/cloud-integrations/:cloudIntegrationId/convex",
|
|
23821
|
+
pathParams: CloudIntegrationIdParamsSchema,
|
|
23822
|
+
responses: {
|
|
23823
|
+
200: DisconnectConvexCloudIntegrationResponseSchema,
|
|
23824
|
+
401: ErrorResponseSchema,
|
|
23825
|
+
403: ErrorResponseSchema,
|
|
23826
|
+
404: ErrorResponseSchema,
|
|
23827
|
+
500: ErrorResponseSchema
|
|
23828
|
+
}
|
|
23829
|
+
},
|
|
23830
|
+
disconnectConvexProject: {
|
|
23831
|
+
method: "DELETE",
|
|
23832
|
+
path: "/organizations/:organizationId/cloud-integrations/:cloudIntegrationId/convex/accounts/:cloudProviderAccountId",
|
|
23833
|
+
pathParams: ConvexAccountIdParamsSchema,
|
|
23834
|
+
responses: {
|
|
23835
|
+
200: DisconnectConvexProjectResponseSchema,
|
|
23836
|
+
400: ErrorResponseSchema,
|
|
23837
|
+
401: ErrorResponseSchema,
|
|
23838
|
+
403: ErrorResponseSchema,
|
|
23839
|
+
404: ErrorResponseSchema,
|
|
23840
|
+
500: ErrorResponseSchema
|
|
23841
|
+
}
|
|
23842
|
+
},
|
|
23843
|
+
disconnectConvexDeployment: {
|
|
23844
|
+
method: "DELETE",
|
|
23845
|
+
path: "/organizations/:organizationId/cloud-integrations/:cloudIntegrationId/convex/deployments/:convexLinkedDeploymentId",
|
|
23846
|
+
pathParams: ConvexDeploymentIdParamsSchema,
|
|
23847
|
+
responses: {
|
|
23848
|
+
200: DisconnectConvexDeploymentResponseSchema,
|
|
23849
|
+
400: ErrorResponseSchema,
|
|
23850
|
+
401: ErrorResponseSchema,
|
|
23851
|
+
403: ErrorResponseSchema,
|
|
23852
|
+
404: ErrorResponseSchema,
|
|
23853
|
+
500: ErrorResponseSchema
|
|
23854
|
+
}
|
|
23855
|
+
},
|
|
23856
|
+
reverifyConvexDeployment: {
|
|
23857
|
+
method: "POST",
|
|
23858
|
+
path: "/organizations/:organizationId/cloud-integrations/:cloudIntegrationId/convex/deployments/:convexLinkedDeploymentId/reverify",
|
|
23859
|
+
pathParams: ConvexDeploymentIdParamsSchema,
|
|
23860
|
+
body: c7.noBody(),
|
|
23861
|
+
responses: {
|
|
23862
|
+
200: ReverifyConvexDeploymentResponseSchema,
|
|
23863
|
+
400: ErrorResponseSchema,
|
|
23864
|
+
401: ErrorResponseSchema,
|
|
23865
|
+
403: ErrorResponseSchema,
|
|
23866
|
+
404: ErrorResponseSchema,
|
|
23867
|
+
409: ErrorResponseSchema,
|
|
23868
|
+
503: ErrorResponseSchema,
|
|
23869
|
+
500: ErrorResponseSchema
|
|
23870
|
+
}
|
|
23607
23871
|
}
|
|
23608
23872
|
});
|
|
23609
23873
|
|
|
@@ -23714,13 +23978,13 @@ var StorageStateSchema = external_exports.object({
|
|
|
23714
23978
|
} catch {
|
|
23715
23979
|
return;
|
|
23716
23980
|
}
|
|
23717
|
-
s.cookies.forEach((
|
|
23718
|
-
const d2 =
|
|
23981
|
+
s.cookies.forEach((c49, i) => {
|
|
23982
|
+
const d2 = c49.domain.replace(/^\./, "").toLowerCase();
|
|
23719
23983
|
if (d2 !== host && !host.endsWith(`.${d2}`)) {
|
|
23720
23984
|
ctx.addIssue({
|
|
23721
23985
|
code: "custom",
|
|
23722
23986
|
path: ["cookies", i, "domain"],
|
|
23723
|
-
message: `cookie domain "${
|
|
23987
|
+
message: `cookie domain "${c49.domain}" is not the capture origin host "${host}" or a parent domain of it`
|
|
23724
23988
|
});
|
|
23725
23989
|
}
|
|
23726
23990
|
});
|
|
@@ -23751,10 +24015,42 @@ var CredentialIdParamsSchema = OrgIdParamsSchema.extend({
|
|
|
23751
24015
|
var EnvironmentCredentialsParamsSchema = OrgIdParamsSchema.extend({
|
|
23752
24016
|
environmentId: external_exports.uuid()
|
|
23753
24017
|
});
|
|
24018
|
+
var OPAQUE_SECRET_SHAPE = { secretValue: external_exports.string().min(1).max(8192) };
|
|
24019
|
+
var SessionStateSecretValueSchema = external_exports.string().min(1).refine((s) => Buffer.byteLength(s, "utf8") <= 262144, "session state must be \u2264256KB").superRefine((s, ctx) => {
|
|
24020
|
+
const parsed = StorageStateSchema.safeParse(parseJsonOrUndefined(s));
|
|
24021
|
+
if (parsed.success) return;
|
|
24022
|
+
if (parsed.error.issues.length === 0) {
|
|
24023
|
+
ctx.addIssue({
|
|
24024
|
+
code: "custom",
|
|
24025
|
+
message: "secretValue is not a valid StorageState capture"
|
|
24026
|
+
});
|
|
24027
|
+
return;
|
|
24028
|
+
}
|
|
24029
|
+
for (const issue2 of parsed.error.issues) {
|
|
24030
|
+
ctx.addIssue({ code: "custom", message: issue2.message, path: issue2.path });
|
|
24031
|
+
}
|
|
24032
|
+
});
|
|
24033
|
+
var SECRET_SHAPES = {
|
|
24034
|
+
BEARER_TOKEN: OPAQUE_SECRET_SHAPE,
|
|
24035
|
+
JWT_TOKEN: OPAQUE_SECRET_SHAPE,
|
|
24036
|
+
API_KEY: OPAQUE_SECRET_SHAPE,
|
|
24037
|
+
PASSPHRASE: OPAQUE_SECRET_SHAPE,
|
|
24038
|
+
COOKIE: { secretValue: external_exports.string().min(1).max(16384) },
|
|
24039
|
+
// secretValue IS the test-account email (login id + inbox ref). Validated as
|
|
24040
|
+
// an address so a typo is rejected at create/rotate time rather than failing
|
|
24041
|
+
// later when the agent uses it as a login/inbox. 320 = RFC 5321 max length.
|
|
24042
|
+
MAGIC_AUTH: { secretValue: external_exports.email().max(320) },
|
|
24043
|
+
USERNAME_PASSWORD: {
|
|
24044
|
+
username: external_exports.string().min(1).max(500),
|
|
24045
|
+
password: external_exports.string().min(1).max(2048)
|
|
24046
|
+
},
|
|
24047
|
+
SESSION_STATE: { secretValue: SessionStateSecretValueSchema }
|
|
24048
|
+
};
|
|
24049
|
+
var CreateLabelSchema = external_exports.string().max(200).optional();
|
|
23754
24050
|
var CreateBearerSchema = external_exports.object({
|
|
23755
24051
|
credentialType: external_exports.literal("BEARER_TOKEN"),
|
|
23756
|
-
label:
|
|
23757
|
-
|
|
24052
|
+
label: CreateLabelSchema,
|
|
24053
|
+
...SECRET_SHAPES.BEARER_TOKEN,
|
|
23758
24054
|
authConfig: external_exports.object({
|
|
23759
24055
|
type: external_exports.literal("BEARER_TOKEN"),
|
|
23760
24056
|
headerName: external_exports.string().min(1).max(200).optional(),
|
|
@@ -23763,8 +24059,8 @@ var CreateBearerSchema = external_exports.object({
|
|
|
23763
24059
|
}).strict();
|
|
23764
24060
|
var CreateJwtSchema = external_exports.object({
|
|
23765
24061
|
credentialType: external_exports.literal("JWT_TOKEN"),
|
|
23766
|
-
label:
|
|
23767
|
-
|
|
24062
|
+
label: CreateLabelSchema,
|
|
24063
|
+
...SECRET_SHAPES.JWT_TOKEN,
|
|
23768
24064
|
authConfig: external_exports.object({
|
|
23769
24065
|
type: external_exports.literal("JWT_TOKEN"),
|
|
23770
24066
|
headerName: external_exports.string().min(1).max(200).optional(),
|
|
@@ -23773,8 +24069,8 @@ var CreateJwtSchema = external_exports.object({
|
|
|
23773
24069
|
}).strict();
|
|
23774
24070
|
var CreateApiKeySchema = external_exports.object({
|
|
23775
24071
|
credentialType: external_exports.literal("API_KEY"),
|
|
23776
|
-
label:
|
|
23777
|
-
|
|
24072
|
+
label: CreateLabelSchema,
|
|
24073
|
+
...SECRET_SHAPES.API_KEY,
|
|
23778
24074
|
authConfig: external_exports.object({
|
|
23779
24075
|
type: external_exports.literal("API_KEY"),
|
|
23780
24076
|
placement: external_exports.enum(["header", "query"]),
|
|
@@ -23783,16 +24079,15 @@ var CreateApiKeySchema = external_exports.object({
|
|
|
23783
24079
|
}).strict();
|
|
23784
24080
|
var CreatePassphraseSchema = external_exports.object({
|
|
23785
24081
|
credentialType: external_exports.literal("PASSPHRASE"),
|
|
23786
|
-
label:
|
|
23787
|
-
|
|
24082
|
+
label: CreateLabelSchema,
|
|
24083
|
+
...SECRET_SHAPES.PASSPHRASE,
|
|
23788
24084
|
// Passphrases are non-HTTP context — authConfig is empty by design.
|
|
23789
24085
|
authConfig: external_exports.object({ type: external_exports.literal("PASSPHRASE") }).strict().optional()
|
|
23790
24086
|
}).strict();
|
|
23791
24087
|
var CreateUsernamePasswordSchema = external_exports.object({
|
|
23792
24088
|
credentialType: external_exports.literal("USERNAME_PASSWORD"),
|
|
23793
|
-
label:
|
|
23794
|
-
|
|
23795
|
-
password: external_exports.string().min(1).max(2048),
|
|
24089
|
+
label: CreateLabelSchema,
|
|
24090
|
+
...SECRET_SHAPES.USERNAME_PASSWORD,
|
|
23796
24091
|
authConfig: external_exports.object({
|
|
23797
24092
|
type: external_exports.literal("USERNAME_PASSWORD"),
|
|
23798
24093
|
method: external_exports.enum(["form", "basic", "json"]),
|
|
@@ -23806,8 +24101,8 @@ var CreateUsernamePasswordSchema = external_exports.object({
|
|
|
23806
24101
|
}).strict();
|
|
23807
24102
|
var CreateCookieSchema = external_exports.object({
|
|
23808
24103
|
credentialType: external_exports.literal("COOKIE"),
|
|
23809
|
-
label:
|
|
23810
|
-
|
|
24104
|
+
label: CreateLabelSchema,
|
|
24105
|
+
...SECRET_SHAPES.COOKIE,
|
|
23811
24106
|
authConfig: external_exports.object({
|
|
23812
24107
|
type: external_exports.literal("COOKIE"),
|
|
23813
24108
|
cookieName: external_exports.string().min(1).max(200),
|
|
@@ -23817,11 +24112,8 @@ var CreateCookieSchema = external_exports.object({
|
|
|
23817
24112
|
}).strict();
|
|
23818
24113
|
var CreateMagicAuthSchema = external_exports.object({
|
|
23819
24114
|
credentialType: external_exports.literal("MAGIC_AUTH"),
|
|
23820
|
-
label:
|
|
23821
|
-
|
|
23822
|
-
// an address so a typo is rejected at create time rather than failing later
|
|
23823
|
-
// when the agent uses it as a login/inbox. 320 = RFC 5321 max length.
|
|
23824
|
-
secretValue: external_exports.email().max(320),
|
|
24115
|
+
label: CreateLabelSchema,
|
|
24116
|
+
...SECRET_SHAPES.MAGIC_AUTH,
|
|
23825
24117
|
authConfig: external_exports.object({
|
|
23826
24118
|
type: external_exports.literal("MAGIC_AUTH"),
|
|
23827
24119
|
/** @deprecated inert — retained for back-compat only. */
|
|
@@ -23830,21 +24122,8 @@ var CreateMagicAuthSchema = external_exports.object({
|
|
|
23830
24122
|
}).strict();
|
|
23831
24123
|
var CreateSessionStateSchema = external_exports.object({
|
|
23832
24124
|
credentialType: external_exports.literal("SESSION_STATE"),
|
|
23833
|
-
label:
|
|
23834
|
-
|
|
23835
|
-
const parsed = StorageStateSchema.safeParse(parseJsonOrUndefined(s));
|
|
23836
|
-
if (parsed.success) return;
|
|
23837
|
-
if (parsed.error.issues.length === 0) {
|
|
23838
|
-
ctx.addIssue({
|
|
23839
|
-
code: "custom",
|
|
23840
|
-
message: "secretValue is not a valid StorageState capture"
|
|
23841
|
-
});
|
|
23842
|
-
return;
|
|
23843
|
-
}
|
|
23844
|
-
for (const issue2 of parsed.error.issues) {
|
|
23845
|
-
ctx.addIssue({ code: "custom", message: issue2.message, path: issue2.path });
|
|
23846
|
-
}
|
|
23847
|
-
})
|
|
24125
|
+
label: CreateLabelSchema,
|
|
24126
|
+
...SECRET_SHAPES.SESSION_STATE
|
|
23848
24127
|
}).strict();
|
|
23849
24128
|
var CreateCredentialRequestSchema = external_exports.discriminatedUnion("credentialType", [
|
|
23850
24129
|
CreateBearerSchema,
|
|
@@ -23864,7 +24143,15 @@ var CredentialResponseSchema = external_exports.object({
|
|
|
23864
24143
|
credentialType: CredentialType,
|
|
23865
24144
|
authConfig: CredentialAuthConfigSchema.nullable(),
|
|
23866
24145
|
createdAt: external_exports.date(),
|
|
23867
|
-
updatedAt: external_exports.date()
|
|
24146
|
+
updatedAt: external_exports.date(),
|
|
24147
|
+
/**
|
|
24148
|
+
* When the encrypted secret was last REPLACED. Null for a credential never
|
|
24149
|
+
* rotated (including every one created before rotation existed). Distinct
|
|
24150
|
+
* from `updatedAt`, which also moves on label / environment / authConfig
|
|
24151
|
+
* edits — so only this field can evidence a secret change. Not secret
|
|
24152
|
+
* material: a timestamp, safe on the read path.
|
|
24153
|
+
*/
|
|
24154
|
+
secretRotatedAt: external_exports.date().nullable()
|
|
23868
24155
|
}).strict();
|
|
23869
24156
|
var ListCredentialsResponseSchema = external_exports.array(CredentialResponseSchema);
|
|
23870
24157
|
var UpdateCredentialRequestSchema = external_exports.object({
|
|
@@ -23872,6 +24159,37 @@ var UpdateCredentialRequestSchema = external_exports.object({
|
|
|
23872
24159
|
environmentId: external_exports.uuid().optional(),
|
|
23873
24160
|
authConfig: CredentialAuthConfigSchema.nullable().optional()
|
|
23874
24161
|
}).strict();
|
|
24162
|
+
var RotateCredentialSecretRequestSchema = external_exports.discriminatedUnion("credentialType", [
|
|
24163
|
+
external_exports.object({ credentialType: external_exports.literal("BEARER_TOKEN"), ...SECRET_SHAPES.BEARER_TOKEN }).strict(),
|
|
24164
|
+
external_exports.object({ credentialType: external_exports.literal("JWT_TOKEN"), ...SECRET_SHAPES.JWT_TOKEN }).strict(),
|
|
24165
|
+
external_exports.object({ credentialType: external_exports.literal("API_KEY"), ...SECRET_SHAPES.API_KEY }).strict(),
|
|
24166
|
+
external_exports.object({ credentialType: external_exports.literal("PASSPHRASE"), ...SECRET_SHAPES.PASSPHRASE }).strict(),
|
|
24167
|
+
external_exports.object({ credentialType: external_exports.literal("COOKIE"), ...SECRET_SHAPES.COOKIE }).strict(),
|
|
24168
|
+
external_exports.object({ credentialType: external_exports.literal("MAGIC_AUTH"), ...SECRET_SHAPES.MAGIC_AUTH }).strict(),
|
|
24169
|
+
external_exports.object({
|
|
24170
|
+
credentialType: external_exports.literal("USERNAME_PASSWORD"),
|
|
24171
|
+
...SECRET_SHAPES.USERNAME_PASSWORD
|
|
24172
|
+
}).strict(),
|
|
24173
|
+
external_exports.object({ credentialType: external_exports.literal("SESSION_STATE"), ...SECRET_SHAPES.SESSION_STATE }).strict()
|
|
24174
|
+
]);
|
|
24175
|
+
var RevealCredentialSecretResponseSchema = external_exports.discriminatedUnion("credentialType", [
|
|
24176
|
+
external_exports.object({
|
|
24177
|
+
credentialType: external_exports.literal("USERNAME_PASSWORD"),
|
|
24178
|
+
username: external_exports.string(),
|
|
24179
|
+
password: external_exports.string()
|
|
24180
|
+
}).strict(),
|
|
24181
|
+
external_exports.object({
|
|
24182
|
+
credentialType: external_exports.enum([
|
|
24183
|
+
"BEARER_TOKEN",
|
|
24184
|
+
"JWT_TOKEN",
|
|
24185
|
+
"API_KEY",
|
|
24186
|
+
"PASSPHRASE",
|
|
24187
|
+
"COOKIE",
|
|
24188
|
+
"MAGIC_AUTH"
|
|
24189
|
+
]),
|
|
24190
|
+
secretValue: external_exports.string()
|
|
24191
|
+
}).strict()
|
|
24192
|
+
]);
|
|
23875
24193
|
|
|
23876
24194
|
// ../../packages/api-contracts/src/contracts/v1/credential.ts
|
|
23877
24195
|
var c8 = initContract();
|
|
@@ -23930,6 +24248,55 @@ var credentialContract = c8.router({
|
|
|
23930
24248
|
500: ErrorResponseSchema
|
|
23931
24249
|
}
|
|
23932
24250
|
},
|
|
24251
|
+
// Replace the stored secret IN PLACE — same credentialId, new KMS envelope.
|
|
24252
|
+
// Separate from PATCH so every route touching KMS or plaintext is greppable
|
|
24253
|
+
// at its own URL. PUT (not PATCH) because the body carries the COMPLETE
|
|
24254
|
+
// secret for the type, so the same request twice yields the same end state.
|
|
24255
|
+
//
|
|
24256
|
+
// Deliberately NOT subject to the CREDENTIAL_IN_USE guard that blocks delete
|
|
24257
|
+
// and env-move during a live pentest: rotation preserves credentialId, so the
|
|
24258
|
+
// engagement's credential set and its ScanCredential rows are untouched —
|
|
24259
|
+
// which is the invariant that guard protects. Mid-engagement is precisely when
|
|
24260
|
+
// a wrong password needs fixing.
|
|
24261
|
+
rotateCredentialSecret: {
|
|
24262
|
+
method: "PUT",
|
|
24263
|
+
path: "/organizations/:organizationId/environments/:environmentId/credentials/:credentialId/secret",
|
|
24264
|
+
pathParams: CredentialIdParamsSchema,
|
|
24265
|
+
body: RotateCredentialSecretRequestSchema,
|
|
24266
|
+
responses: {
|
|
24267
|
+
// Unchanged response shape — a rotate NEVER echoes the secret back.
|
|
24268
|
+
200: CredentialResponseSchema,
|
|
24269
|
+
400: ErrorResponseSchema,
|
|
24270
|
+
401: ErrorResponseSchema,
|
|
24271
|
+
403: ErrorResponseSchema,
|
|
24272
|
+
404: ErrorResponseSchema,
|
|
24273
|
+
// 422 — body's credentialType differs from the stored row's
|
|
24274
|
+
// (errorCode CREDENTIAL_ROTATE_TYPE_MISMATCH). Type changes stay
|
|
24275
|
+
// delete + recreate.
|
|
24276
|
+
422: ErrorResponseSchema,
|
|
24277
|
+
500: ErrorResponseSchema
|
|
24278
|
+
}
|
|
24279
|
+
},
|
|
24280
|
+
// Return the stored plaintext to an authorized human. POST, not GET: it must
|
|
24281
|
+
// never sit in an access log, a browser history entry, or a cacheable read.
|
|
24282
|
+
// Requires a user principal — API keys are rejected, so a leaked trace_sk_*
|
|
24283
|
+
// cannot exfiltrate customer credentials.
|
|
24284
|
+
revealCredentialSecret: {
|
|
24285
|
+
method: "POST",
|
|
24286
|
+
path: "/organizations/:organizationId/environments/:environmentId/credentials/:credentialId/reveal",
|
|
24287
|
+
pathParams: CredentialIdParamsSchema,
|
|
24288
|
+
body: c8.noBody(),
|
|
24289
|
+
responses: {
|
|
24290
|
+
200: RevealCredentialSecretResponseSchema,
|
|
24291
|
+
401: ErrorResponseSchema,
|
|
24292
|
+
403: ErrorResponseSchema,
|
|
24293
|
+
404: ErrorResponseSchema,
|
|
24294
|
+
// 422 — SESSION_STATE has no reveal variant by construction
|
|
24295
|
+
// (errorCode CREDENTIAL_REVEAL_UNSUPPORTED).
|
|
24296
|
+
422: ErrorResponseSchema,
|
|
24297
|
+
500: ErrorResponseSchema
|
|
24298
|
+
}
|
|
24299
|
+
},
|
|
23933
24300
|
deleteCredential: {
|
|
23934
24301
|
method: "DELETE",
|
|
23935
24302
|
path: "/organizations/:organizationId/environments/:environmentId/credentials/:credentialId",
|
|
@@ -25714,7 +26081,7 @@ var CreateLinearTicketsParamsSchema = OrgIdParamsSchema.extend({
|
|
|
25714
26081
|
});
|
|
25715
26082
|
var CreateLinearTicketsRequestSchema = external_exports.object({
|
|
25716
26083
|
/** UUID or PTF-N display id. Cap sized to the ~30s synchronous request budget. */
|
|
25717
|
-
findingIds: external_exports.array(external_exports.string().min(1).max(64)).min(1).max(
|
|
26084
|
+
findingIds: external_exports.array(external_exports.string().min(1).max(64)).min(1).max(50),
|
|
25718
26085
|
/** Single-finding requests only — a title with >1 finding is a 400. */
|
|
25719
26086
|
title: external_exports.string().min(1).max(255).optional(),
|
|
25720
26087
|
/** Destination overrides — ADMIN ONLY (MANAGE_ORGANIZATION); a non-admin sending any is a 403. */
|
|
@@ -25965,8 +26332,7 @@ var OrgCapabilityValues = [
|
|
|
25965
26332
|
"SCAN_SECRETS",
|
|
25966
26333
|
"SCAN_DAST",
|
|
25967
26334
|
"AUTO_PR_SCANS",
|
|
25968
|
-
"AUTO_PUSH_SCANS"
|
|
25969
|
-
"AUTO_FIX_PR"
|
|
26335
|
+
"AUTO_PUSH_SCANS"
|
|
25970
26336
|
];
|
|
25971
26337
|
var UpdateOrganizationRequestSchema = external_exports.object({
|
|
25972
26338
|
name: external_exports.string().min(1).max(255).optional(),
|
|
@@ -26053,6 +26419,14 @@ var StaffOrganizationSummarySchema = external_exports.object({
|
|
|
26053
26419
|
createdAt: external_exports.date()
|
|
26054
26420
|
});
|
|
26055
26421
|
var ListAllOrganizationsResponseSchema = external_exports.array(StaffOrganizationSummarySchema);
|
|
26422
|
+
var CreateOrganizationRequestSchema = external_exports.object({
|
|
26423
|
+
name: external_exports.string().trim().min(2, "Organization name must be at least 2 characters").max(100, "Organization name must be 100 characters or fewer")
|
|
26424
|
+
});
|
|
26425
|
+
var CreateOrganizationResponseSchema = external_exports.object({
|
|
26426
|
+
organizationId: external_exports.uuid(),
|
|
26427
|
+
slug: external_exports.string(),
|
|
26428
|
+
name: external_exports.string()
|
|
26429
|
+
});
|
|
26056
26430
|
var OnboardingItemValues = [
|
|
26057
26431
|
"CONNECT_CODE",
|
|
26058
26432
|
"CONNECT_CLOUD",
|
|
@@ -26109,6 +26483,19 @@ var organizationContract = c20.router({
|
|
|
26109
26483
|
},
|
|
26110
26484
|
summary: "List every organization (Trace staff only)"
|
|
26111
26485
|
},
|
|
26486
|
+
createOrganization: {
|
|
26487
|
+
method: "POST",
|
|
26488
|
+
path: "/staff/organizations",
|
|
26489
|
+
body: CreateOrganizationRequestSchema,
|
|
26490
|
+
responses: {
|
|
26491
|
+
201: CreateOrganizationResponseSchema,
|
|
26492
|
+
400: ErrorResponseSchema,
|
|
26493
|
+
401: ErrorResponseSchema,
|
|
26494
|
+
403: ErrorResponseSchema,
|
|
26495
|
+
500: ErrorResponseSchema
|
|
26496
|
+
},
|
|
26497
|
+
summary: "Create an organization (Trace staff only)"
|
|
26498
|
+
},
|
|
26112
26499
|
getOrganization: {
|
|
26113
26500
|
method: "GET",
|
|
26114
26501
|
path: "/organizations/:organizationId",
|
|
@@ -26525,10 +26912,189 @@ var CustomerPriorityCategoryValues = [
|
|
|
26525
26912
|
];
|
|
26526
26913
|
var CustomerPriorityCategory = external_exports.enum(CustomerPriorityCategoryValues);
|
|
26527
26914
|
|
|
26915
|
+
// ../../packages/api-contracts/src/schemas/domain/pentest-customer-intake.schema.ts
|
|
26916
|
+
var IntakeSurfaceValues = [
|
|
26917
|
+
"WEB",
|
|
26918
|
+
"PUBLIC_API",
|
|
26919
|
+
"INTERNAL_API",
|
|
26920
|
+
"GRAPHQL",
|
|
26921
|
+
"WEBHOOKS",
|
|
26922
|
+
"MCP",
|
|
26923
|
+
"AI_AGENTS",
|
|
26924
|
+
"MOBILE",
|
|
26925
|
+
"DESKTOP",
|
|
26926
|
+
"CLI",
|
|
26927
|
+
"BACKGROUND_JOBS"
|
|
26928
|
+
];
|
|
26929
|
+
var IntakeSurface = external_exports.enum(IntakeSurfaceValues);
|
|
26930
|
+
var PentestCustomerIntakeAnswersShape = external_exports.object({
|
|
26931
|
+
issueClasses: external_exports.array(CustomerPriorityCategory).max(11).optional(),
|
|
26932
|
+
issueClassesNotes: external_exports.string().max(5e3).optional(),
|
|
26933
|
+
focusAreas: external_exports.string().max(5e3).optional(),
|
|
26934
|
+
rolesAndPermissions: external_exports.string().max(1e4).optional(),
|
|
26935
|
+
authenticationSetup: external_exports.string().max(5e3).optional(),
|
|
26936
|
+
tenantIsolationExpectation: external_exports.string().max(5e3).optional(),
|
|
26937
|
+
surfaces: external_exports.array(IntakeSurface).max(11).optional(),
|
|
26938
|
+
surfacesNotes: external_exports.string().max(5e3).optional(),
|
|
26939
|
+
thirdParties: external_exports.string().max(5e3).optional(),
|
|
26940
|
+
sensitiveData: external_exports.string().max(5e3).optional(),
|
|
26941
|
+
neverTouch: external_exports.string().max(5e3).optional(),
|
|
26942
|
+
knownRisks: external_exports.string().max(5e3).optional(),
|
|
26943
|
+
tribalKnowledge: external_exports.string().max(1e4).optional()
|
|
26944
|
+
});
|
|
26945
|
+
var PentestCustomerIntakeAnswersSchema = PentestCustomerIntakeAnswersShape.strict();
|
|
26946
|
+
var PentestCustomerIntakeStoredAnswersSchema = PentestCustomerIntakeAnswersShape;
|
|
26947
|
+
var PentestCustomerIntakeWriteAnswersSchema = PentestCustomerIntakeAnswersShape.extend({
|
|
26948
|
+
/** @deprecated Retired question. Accepted for in-flight clients, never stored. */
|
|
26949
|
+
testEnvironment: external_exports.string().max(100).optional(),
|
|
26950
|
+
/** @deprecated Retired question. Accepted for in-flight clients, never stored. */
|
|
26951
|
+
reposAndBranches: external_exports.string().max(5e3).optional()
|
|
26952
|
+
}).strict();
|
|
26953
|
+
var PENTEST_CUSTOMER_INTAKE_ANSWER_KEYS = [
|
|
26954
|
+
"issueClasses",
|
|
26955
|
+
"issueClassesNotes",
|
|
26956
|
+
"focusAreas",
|
|
26957
|
+
"rolesAndPermissions",
|
|
26958
|
+
"authenticationSetup",
|
|
26959
|
+
"tenantIsolationExpectation",
|
|
26960
|
+
"surfaces",
|
|
26961
|
+
"surfacesNotes",
|
|
26962
|
+
"thirdParties",
|
|
26963
|
+
"sensitiveData",
|
|
26964
|
+
"neverTouch",
|
|
26965
|
+
"knownRisks",
|
|
26966
|
+
"tribalKnowledge"
|
|
26967
|
+
];
|
|
26968
|
+
var PENTEST_CUSTOMER_INTAKE_LABELS = {
|
|
26969
|
+
issueClasses: "Issue classes to prioritize",
|
|
26970
|
+
issueClassesNotes: "Issue classes, additional notes",
|
|
26971
|
+
focusAreas: "Focus areas",
|
|
26972
|
+
rolesAndPermissions: "Roles and permissions",
|
|
26973
|
+
authenticationSetup: "Authentication setup",
|
|
26974
|
+
tenantIsolationExpectation: "Tenant isolation expectations",
|
|
26975
|
+
surfaces: "Surfaces in scope",
|
|
26976
|
+
surfacesNotes: "Surfaces, additional notes",
|
|
26977
|
+
thirdParties: "Third parties and integrations",
|
|
26978
|
+
sensitiveData: "Sensitive data",
|
|
26979
|
+
neverTouch: "Out of bounds / never touch",
|
|
26980
|
+
knownRisks: "Known risks",
|
|
26981
|
+
tribalKnowledge: "Tribal knowledge"
|
|
26982
|
+
};
|
|
26983
|
+
var PENTEST_CUSTOMER_INTAKE_QUESTIONS = [
|
|
26984
|
+
{
|
|
26985
|
+
kind: "multiSelect",
|
|
26986
|
+
key: "issueClasses",
|
|
26987
|
+
notesKey: "issueClassesNotes",
|
|
26988
|
+
question: "Which issue classes worry you most?",
|
|
26989
|
+
helper: "(authn bypass / broken access control / injection / data exposure / supply chain / infra exposure / multi-tenant isolation / crypto / business logic / SSRF / XSS)",
|
|
26990
|
+
notesQuestion: "Anything else about issue classes?"
|
|
26991
|
+
},
|
|
26992
|
+
{
|
|
26993
|
+
kind: "text",
|
|
26994
|
+
key: "focusAreas",
|
|
26995
|
+
question: "Is there any particular application or area you want us to spend extra focus on?"
|
|
26996
|
+
},
|
|
26997
|
+
{
|
|
26998
|
+
kind: "text",
|
|
26999
|
+
key: "rolesAndPermissions",
|
|
27000
|
+
question: "What roles/permissions can users take in your application?",
|
|
27001
|
+
helper: "Explain each role and what it should/shouldn't be able to do."
|
|
27002
|
+
},
|
|
27003
|
+
{
|
|
27004
|
+
kind: "text",
|
|
27005
|
+
key: "authenticationSetup",
|
|
27006
|
+
question: "Anything we should know about your authentication setup?",
|
|
27007
|
+
helper: "(e.g. mid-migration between providers, legacy login still live; otherwise we'll figure it out from the code)"
|
|
27008
|
+
},
|
|
27009
|
+
{
|
|
27010
|
+
kind: "text",
|
|
27011
|
+
key: "tenantIsolationExpectation",
|
|
27012
|
+
question: "What's your expectation for isolation between tenants/organizations?",
|
|
27013
|
+
helper: "What should never be reachable across that boundary?"
|
|
27014
|
+
},
|
|
27015
|
+
{
|
|
27016
|
+
kind: "multiSelect",
|
|
27017
|
+
key: "surfaces",
|
|
27018
|
+
notesKey: "surfacesNotes",
|
|
27019
|
+
question: "Which surfaces exist?",
|
|
27020
|
+
helper: "(web / public API / internal API / GraphQL / webhooks / MCP / AI agents / mobile / desktop / CLI / background jobs)",
|
|
27021
|
+
notesQuestion: "Anything else about your surfaces?"
|
|
27022
|
+
},
|
|
27023
|
+
{
|
|
27024
|
+
kind: "text",
|
|
27025
|
+
key: "thirdParties",
|
|
27026
|
+
question: "Which third parties do you connect to, and should we mock them or stand them up?",
|
|
27027
|
+
helper: "(e.g. CRMs, payment/bank APIs, identity providers, email/SMS, LLM providers)"
|
|
27028
|
+
},
|
|
27029
|
+
{
|
|
27030
|
+
kind: "text",
|
|
27031
|
+
key: "sensitiveData",
|
|
27032
|
+
question: "What data must no attacker ever access?",
|
|
27033
|
+
helper: "And what data do you not care about?"
|
|
27034
|
+
},
|
|
27035
|
+
{
|
|
27036
|
+
kind: "text",
|
|
27037
|
+
key: "neverTouch",
|
|
27038
|
+
question: "What must we never touch or trigger?",
|
|
27039
|
+
helper: "(destructive endpoints, real customer emails/SMS, third-party prod accounts, specific tenants)"
|
|
27040
|
+
},
|
|
27041
|
+
{
|
|
27042
|
+
kind: "text",
|
|
27043
|
+
key: "knownRisks",
|
|
27044
|
+
question: "What do you already know is broken or risky (i.e. what keeps you up at night)?"
|
|
27045
|
+
},
|
|
27046
|
+
{
|
|
27047
|
+
kind: "text",
|
|
27048
|
+
key: "tribalKnowledge",
|
|
27049
|
+
question: "What tribal knowledge would we only learn by asking?",
|
|
27050
|
+
helper: "Anything intentionally weird, counter-intuitive, or likely to trip us up; behavior that looks like a bug but isn't, dead code that's still deployed, a service that isn't what its name suggests."
|
|
27051
|
+
}
|
|
27052
|
+
];
|
|
27053
|
+
var PENTEST_CUSTOMER_INTAKE_QUESTION_COUNT = PENTEST_CUSTOMER_INTAKE_QUESTIONS.length;
|
|
27054
|
+
var INTAKE_ISSUE_CLASS_LABELS = {
|
|
27055
|
+
AUTHN_BYPASS: "Authn bypass",
|
|
27056
|
+
AUTHZ_IDOR: "Broken access control",
|
|
27057
|
+
INJECTION: "Injection",
|
|
27058
|
+
DATA_EXPOSURE: "Data exposure",
|
|
27059
|
+
SUPPLY_CHAIN: "Supply chain",
|
|
27060
|
+
INFRA_EXPOSURE: "Infra exposure",
|
|
27061
|
+
MULTI_TENANT_ISOLATION: "Multi-tenant isolation",
|
|
27062
|
+
CRYPTO_WEAKNESS: "Crypto",
|
|
27063
|
+
BUSINESS_LOGIC: "Business logic",
|
|
27064
|
+
SSRF: "SSRF",
|
|
27065
|
+
XSS: "XSS"
|
|
27066
|
+
};
|
|
27067
|
+
var INTAKE_SURFACE_LABELS = {
|
|
27068
|
+
WEB: "Web",
|
|
27069
|
+
PUBLIC_API: "Public API",
|
|
27070
|
+
INTERNAL_API: "Internal API",
|
|
27071
|
+
GRAPHQL: "GraphQL",
|
|
27072
|
+
WEBHOOKS: "Webhooks",
|
|
27073
|
+
MCP: "MCP",
|
|
27074
|
+
AI_AGENTS: "AI agents",
|
|
27075
|
+
MOBILE: "Mobile",
|
|
27076
|
+
DESKTOP: "Desktop",
|
|
27077
|
+
CLI: "CLI",
|
|
27078
|
+
BACKGROUND_JOBS: "Background jobs"
|
|
27079
|
+
};
|
|
27080
|
+
function normalizePentestCustomerIntakeAnswers(answers) {
|
|
27081
|
+
const next = { ...answers };
|
|
27082
|
+
if (next.issueClasses !== void 0) {
|
|
27083
|
+
next.issueClasses = Array.from(new Set(next.issueClasses)).sort();
|
|
27084
|
+
}
|
|
27085
|
+
if (next.surfaces !== void 0) {
|
|
27086
|
+
next.surfaces = Array.from(new Set(next.surfaces)).sort();
|
|
27087
|
+
}
|
|
27088
|
+
return next;
|
|
27089
|
+
}
|
|
27090
|
+
|
|
26528
27091
|
// ../../packages/api-contracts/src/schemas/api/v1/pentest.api.ts
|
|
26529
27092
|
var PentestIdParamsSchema = OrgIdParamsSchema.extend({
|
|
26530
27093
|
pentestId: external_exports.string().min(1)
|
|
26531
27094
|
});
|
|
27095
|
+
var PentestApplicationParamsSchema = PentestIdParamsSchema.extend({
|
|
27096
|
+
applicationId: external_exports.uuid()
|
|
27097
|
+
});
|
|
26532
27098
|
var CustomerPentestIdParamsSchema = OrgIdParamsSchema.extend({
|
|
26533
27099
|
pentestId: PentestIdOrDisplayIdSchema
|
|
26534
27100
|
});
|
|
@@ -26541,6 +27107,21 @@ var CustomerPentestStatusValues = [
|
|
|
26541
27107
|
"PAUSED"
|
|
26542
27108
|
];
|
|
26543
27109
|
var CustomerPentestStatus = external_exports.enum(CustomerPentestStatusValues);
|
|
27110
|
+
var BoundPentestApplicationSchema = external_exports.object({
|
|
27111
|
+
applicationId: external_exports.uuid(),
|
|
27112
|
+
name: external_exports.string(),
|
|
27113
|
+
type: external_exports.enum(ApplicationTypeValues),
|
|
27114
|
+
// `z.string()`, not `z.url()` — every other URL field on this surface's RESPONSE
|
|
27115
|
+
// side is a plain string. Writes already validate with `z.url()`
|
|
27116
|
+
// (`application.api.ts`), so re-validating stored data here buys nothing and would
|
|
27117
|
+
// let one legacy row 404 an entire staff page through `safeParse`.
|
|
27118
|
+
applicationUrl: external_exports.string().nullable(),
|
|
27119
|
+
/**
|
|
27120
|
+
* Bind order. Never renumbered on unbind, so gaps are normal and only the
|
|
27121
|
+
* relative order carries meaning — the lowest ordinal is the compat mirror.
|
|
27122
|
+
*/
|
|
27123
|
+
ordinal: external_exports.number().int()
|
|
27124
|
+
});
|
|
26544
27125
|
var PentestResponseSchema = external_exports.object({
|
|
26545
27126
|
pentestId: external_exports.uuid(),
|
|
26546
27127
|
organizationId: external_exports.uuid(),
|
|
@@ -26557,8 +27138,21 @@ var PentestResponseSchema = external_exports.object({
|
|
|
26557
27138
|
scope: external_exports.string().nullable(),
|
|
26558
27139
|
/** Granular stage state. Wizard surfaces this; worker transitions write it. */
|
|
26559
27140
|
currentStage: PentestStage,
|
|
26560
|
-
/**
|
|
27141
|
+
/**
|
|
27142
|
+
* The LOWEST-ORDINAL bound application — a compat mirror of the authoritative
|
|
27143
|
+
* `PentestApplication` join, not a distinct concept. Read `applications` when you
|
|
27144
|
+
* need the engagement's real scope; a multi-application engagement reports its
|
|
27145
|
+
* first binding here and would otherwise understate what it covers.
|
|
27146
|
+
*/
|
|
26561
27147
|
primaryApplicationId: external_exports.uuid().nullable(),
|
|
27148
|
+
/**
|
|
27149
|
+
* Every bound application, ordinal-ascending. `.optional()` for rolling-deploy
|
|
27150
|
+
* safety: `apps/web` (Vercel) deploys ahead of `apps/api` (ECS), so a new web
|
|
27151
|
+
* build briefly reads responses from an API that does not send this yet — the
|
|
27152
|
+
* precedent is `PentestDetailResponseSchema` below. Absent means "this API is
|
|
27153
|
+
* older", NOT "no applications bound"; fall back to `primaryApplicationId`.
|
|
27154
|
+
*/
|
|
27155
|
+
applications: external_exports.array(BoundPentestApplicationSchema).optional(),
|
|
26562
27156
|
/** Customer threat-model context — free text. Used by hypothesis-gen prompt. */
|
|
26563
27157
|
customerConcernsContext: external_exports.string().nullable(),
|
|
26564
27158
|
customerPriorityCategories: external_exports.array(CustomerPriorityCategory),
|
|
@@ -26587,7 +27181,44 @@ var PentestDetailResponseSchema = PentestResponseSchema.extend({
|
|
|
26587
27181
|
systemUnderTest: external_exports.string().optional(),
|
|
26588
27182
|
testingWindowStart: external_exports.coerce.date().nullable().optional(),
|
|
26589
27183
|
testingWindowEnd: external_exports.coerce.date().nullable().optional(),
|
|
26590
|
-
engagementMetadataOverrides: EngagementMetadataOverridesSchema.optional()
|
|
27184
|
+
engagementMetadataOverrides: EngagementMetadataOverridesSchema.optional(),
|
|
27185
|
+
/**
|
|
27186
|
+
* True once the engagement's repository scope has been snapshotted, which
|
|
27187
|
+
* PERMANENTLY refuses bind and unbind (`repositoryScopes > 0` in
|
|
27188
|
+
* `requireBindableInLock`).
|
|
27189
|
+
*
|
|
27190
|
+
* This one refusal only — that guard also refuses on `PENTEST_CLOSED` and on a
|
|
27191
|
+
* non-scoping stage, both of which the client can already read off `status` and
|
|
27192
|
+
* `currentStage` on this same response. So `false` means "not frozen by the
|
|
27193
|
+
* snapshot", NOT "a bind will succeed"; a consumer that gates a control must check
|
|
27194
|
+
* the stage and closed state too.
|
|
27195
|
+
*
|
|
27196
|
+
* Needed as its OWN field because nothing else on the wire answers it: the scope
|
|
27197
|
+
* freezes at the first scope-consuming session create, and only VALIDATION moves
|
|
27198
|
+
* the stage, so RECON / CODE_REVIEW / PRODUCT_RECON leave the engagement in
|
|
27199
|
+
* `DRAFT` with permanently frozen bindings. `getRepositoryScope` reports
|
|
27200
|
+
* `source: 'PENTEST_SCOPE'` only PAST the scoping stages, so a frozen `DRAFT`
|
|
27201
|
+
* engagement still returns live application links there.
|
|
27202
|
+
*
|
|
27203
|
+
* Scoped to BINDINGS, not to the whole target: environment add/remove is gated on
|
|
27204
|
+
* stage alone (`PentestEnvironmentService`, `NON_SCOPING_PENTEST_STAGES`), and
|
|
27205
|
+
* `DRAFT` is a scoping stage — so a consumer must not disable environment editing
|
|
27206
|
+
* on this flag. Doing so would remove the one provisioning action a frozen
|
|
27207
|
+
* multi-application engagement still legitimately needs.
|
|
27208
|
+
*
|
|
27209
|
+
* Detail-only (the list schema deliberately carries no per-pentest aggregates) and
|
|
27210
|
+
* `.optional()` for the same rolling-deploy reason as the fields above.
|
|
27211
|
+
*/
|
|
27212
|
+
applicationBindingFrozen: external_exports.boolean().optional(),
|
|
27213
|
+
/**
|
|
27214
|
+
* Optional customer intake questionnaire answers. Staff detail only.
|
|
27215
|
+
* `.optional()` for rolling-deploy safety (Vercel ahead of ECS).
|
|
27216
|
+
*
|
|
27217
|
+
* Read with the lenient schema for the same reason: an API that hasn't
|
|
27218
|
+
* deployed yet still answers with keys from a retired question, and a strict
|
|
27219
|
+
* parse here would fail the whole response instead of ignoring them.
|
|
27220
|
+
*/
|
|
27221
|
+
customerIntakeAnswers: PentestCustomerIntakeStoredAnswersSchema.nullable().optional()
|
|
26591
27222
|
});
|
|
26592
27223
|
var CustomerPentestShellResponseSchema = external_exports.object({
|
|
26593
27224
|
pentestId: external_exports.uuid(),
|
|
@@ -26596,6 +27227,24 @@ var CustomerPentestShellResponseSchema = external_exports.object({
|
|
|
26596
27227
|
title: external_exports.string(),
|
|
26597
27228
|
description: external_exports.string().nullable(),
|
|
26598
27229
|
customerStatus: CustomerPentestStatus,
|
|
27230
|
+
/** The LOWEST-ORDINAL application under test — a compat mirror of the join. Null =
|
|
27231
|
+
* engagement not bound to an application. `.optional()` for rolling-deploy
|
|
27232
|
+
* safety — apps/web (Vercel) deploys ahead of apps/api (ECS).
|
|
27233
|
+
*
|
|
27234
|
+
* Read `applicationIds` for the homepage "In scope" chips: this field names one
|
|
27235
|
+
* application, so using it there marked the other bindings of a multi-application
|
|
27236
|
+
* engagement "Not in current scope" — a false statement on a customer surface. */
|
|
27237
|
+
primaryApplicationId: external_exports.uuid().nullable().optional(),
|
|
27238
|
+
/**
|
|
27239
|
+
* EVERY application this engagement covers, in bind order. Ids only — the customer
|
|
27240
|
+
* homepage already has the org's applications and resolves names locally, and this
|
|
27241
|
+
* surface deliberately shows no more application detail than it did.
|
|
27242
|
+
*
|
|
27243
|
+
* `.optional()` for the same rolling-deploy reason: absent means "this API is
|
|
27244
|
+
* older", NOT "nothing bound", so a consumer must fall back to
|
|
27245
|
+
* `primaryApplicationId` rather than claim the engagement covers nothing.
|
|
27246
|
+
*/
|
|
27247
|
+
applicationIds: external_exports.array(external_exports.uuid()).optional(),
|
|
26599
27248
|
startedAt: external_exports.coerce.date().nullable(),
|
|
26600
27249
|
endedAt: external_exports.coerce.date().nullable(),
|
|
26601
27250
|
createdAt: external_exports.coerce.date(),
|
|
@@ -26614,8 +27263,35 @@ var ListCustomerPentestsResponseSchema = external_exports.array(CustomerPentestR
|
|
|
26614
27263
|
var CustomerPentestDetailResponseSchema = CustomerPentestResponseSchema.extend({
|
|
26615
27264
|
systemUnderTest: external_exports.string().optional(),
|
|
26616
27265
|
testingWindowStart: external_exports.coerce.date().nullable().optional(),
|
|
26617
|
-
testingWindowEnd: external_exports.coerce.date().nullable().optional()
|
|
27266
|
+
testingWindowEnd: external_exports.coerce.date().nullable().optional(),
|
|
27267
|
+
/**
|
|
27268
|
+
* Discovery flags for the questionnaire header CTA. Answer bodies live on
|
|
27269
|
+
* GET …/questionnaire. `.optional()` for rolling-deploy safety.
|
|
27270
|
+
*/
|
|
27271
|
+
questionnaireEditable: external_exports.boolean().optional(),
|
|
27272
|
+
hasQuestionnaireAnswers: external_exports.boolean().optional()
|
|
26618
27273
|
});
|
|
27274
|
+
var CustomerPentestQuestionnaireResponseSchema = external_exports.object({
|
|
27275
|
+
pentestId: external_exports.uuid(),
|
|
27276
|
+
/** True iff currentStage ∈ SCOPING_PENTEST_STAGES (DRAFT | READY_TO_START). */
|
|
27277
|
+
editable: external_exports.boolean(),
|
|
27278
|
+
/**
|
|
27279
|
+
* Lenient on unknown keys: during a rolling deploy the dashboard runs against
|
|
27280
|
+
* an API that still answers with a retired question's key, and a strict parse
|
|
27281
|
+
* would turn that into a broken page instead of an ignored field. Writes stay
|
|
27282
|
+
* strict — see the upsert request below.
|
|
27283
|
+
*/
|
|
27284
|
+
answers: PentestCustomerIntakeStoredAnswersSchema.nullable(),
|
|
27285
|
+
updatedAt: external_exports.coerce.date()
|
|
27286
|
+
});
|
|
27287
|
+
var UpsertCustomerPentestQuestionnaireRequestSchema = external_exports.object({
|
|
27288
|
+
/**
|
|
27289
|
+
* Full answers object, or null to clear. Keys of retired questions are
|
|
27290
|
+
* accepted and dropped so a tab opened before the deploy can still save;
|
|
27291
|
+
* keys that were never questions are still rejected.
|
|
27292
|
+
*/
|
|
27293
|
+
answers: PentestCustomerIntakeWriteAnswersSchema.nullable()
|
|
27294
|
+
}).strict();
|
|
26619
27295
|
var ReadPentestResponseSchema = external_exports.union([
|
|
26620
27296
|
PentestDetailResponseSchema,
|
|
26621
27297
|
CustomerPentestShellResponseSchema
|
|
@@ -26675,6 +27351,14 @@ var UpdatePentestRequestSchema = external_exports.object({
|
|
|
26675
27351
|
scope: external_exports.string().max(5e4).nullable().optional(),
|
|
26676
27352
|
startedAt: external_exports.coerce.date().nullable().optional(),
|
|
26677
27353
|
endedAt: external_exports.coerce.date().nullable().optional(),
|
|
27354
|
+
/**
|
|
27355
|
+
* SINGLE-APPLICATION COMPAT PATH ONLY: means "replace the bound set with exactly
|
|
27356
|
+
* this application", or clear it on `null`. Rejected with 409
|
|
27357
|
+
* `PENTEST_MULTI_APPLICATION_USE_BIND_ENDPOINT` when 2+ applications are already
|
|
27358
|
+
* bound — otherwise one PATCH would silently unbind N−1 of them and bypass the
|
|
27359
|
+
* per-application unbind guard. Use `bindApplication` / `unbindApplication` for
|
|
27360
|
+
* anything multi-application.
|
|
27361
|
+
*/
|
|
26678
27362
|
primaryApplicationId: external_exports.uuid().nullable().optional(),
|
|
26679
27363
|
customerConcernsContext: external_exports.string().max(2e4).nullable().optional(),
|
|
26680
27364
|
customerPriorityCategories: external_exports.array(CustomerPriorityCategory).max(20).optional(),
|
|
@@ -26688,6 +27372,9 @@ var UpdatePentestRequestSchema = external_exports.object({
|
|
|
26688
27372
|
perHypothesisBudgetCapUsd: external_exports.number().min(0).max(1e5).optional(),
|
|
26689
27373
|
lifecycleReason: external_exports.string().trim().min(1).max(2e3).optional()
|
|
26690
27374
|
});
|
|
27375
|
+
var BindPentestApplicationRequestSchema = external_exports.object({
|
|
27376
|
+
applicationId: external_exports.uuid()
|
|
27377
|
+
}).strict();
|
|
26691
27378
|
|
|
26692
27379
|
// ../../packages/api-contracts/src/schemas/api/v1/pentest-stage-transition.api.ts
|
|
26693
27380
|
var StageTransitionResponseSchema = external_exports.object({
|
|
@@ -26793,6 +27480,33 @@ var pentestContract = c21.router({
|
|
|
26793
27480
|
500: ErrorResponseSchema
|
|
26794
27481
|
}
|
|
26795
27482
|
},
|
|
27483
|
+
getCustomerPentestQuestionnaire: {
|
|
27484
|
+
method: "GET",
|
|
27485
|
+
path: "/organizations/:organizationId/customer-pentests/:pentestId/questionnaire",
|
|
27486
|
+
pathParams: CustomerPentestIdParamsSchema,
|
|
27487
|
+
responses: {
|
|
27488
|
+
200: CustomerPentestQuestionnaireResponseSchema,
|
|
27489
|
+
401: ErrorResponseSchema,
|
|
27490
|
+
403: ErrorResponseSchema,
|
|
27491
|
+
404: ErrorResponseSchema,
|
|
27492
|
+
500: ErrorResponseSchema
|
|
27493
|
+
}
|
|
27494
|
+
},
|
|
27495
|
+
upsertCustomerPentestQuestionnaire: {
|
|
27496
|
+
method: "PUT",
|
|
27497
|
+
path: "/organizations/:organizationId/customer-pentests/:pentestId/questionnaire",
|
|
27498
|
+
pathParams: CustomerPentestIdParamsSchema,
|
|
27499
|
+
body: UpsertCustomerPentestQuestionnaireRequestSchema,
|
|
27500
|
+
responses: {
|
|
27501
|
+
200: CustomerPentestQuestionnaireResponseSchema,
|
|
27502
|
+
400: ErrorResponseSchema,
|
|
27503
|
+
401: ErrorResponseSchema,
|
|
27504
|
+
403: ErrorResponseSchema,
|
|
27505
|
+
404: ErrorResponseSchema,
|
|
27506
|
+
409: ErrorResponseSchema,
|
|
27507
|
+
500: ErrorResponseSchema
|
|
27508
|
+
}
|
|
27509
|
+
},
|
|
26796
27510
|
createPentest: {
|
|
26797
27511
|
method: "POST",
|
|
26798
27512
|
path: "/organizations/:organizationId/pentests",
|
|
@@ -26849,6 +27563,49 @@ var pentestContract = c21.router({
|
|
|
26849
27563
|
500: ErrorResponseSchema
|
|
26850
27564
|
}
|
|
26851
27565
|
},
|
|
27566
|
+
// POST/DELETE-per-row rather than a batch set on PATCH, mirroring
|
|
27567
|
+
// `pentest-environment.ts`: every rejection stays attributable to ONE
|
|
27568
|
+
// application, where a set-diff would fail an entire save on one blocked
|
|
27569
|
+
// removal with no way to say which.
|
|
27570
|
+
bindApplication: {
|
|
27571
|
+
method: "POST",
|
|
27572
|
+
path: "/organizations/:organizationId/pentests/:pentestId/applications",
|
|
27573
|
+
pathParams: PentestIdParamsSchema,
|
|
27574
|
+
body: BindPentestApplicationRequestSchema,
|
|
27575
|
+
responses: {
|
|
27576
|
+
// The resulting bound set, NOT the detail shape. The 201 body is assembled purely
|
|
27577
|
+
// inside the bind transaction, so it cannot describe a state the write did not
|
|
27578
|
+
// produce; deriving the engagement cover here would mean a fallible read AFTER the
|
|
27579
|
+
// commit. Callers that need the cover GET the pentest.
|
|
27580
|
+
201: PentestResponseSchema,
|
|
27581
|
+
400: ErrorResponseSchema,
|
|
27582
|
+
401: ErrorResponseSchema,
|
|
27583
|
+
403: ErrorResponseSchema,
|
|
27584
|
+
404: ErrorResponseSchema,
|
|
27585
|
+
// 409 — PENTEST_APPLICATION_ALREADY_BOUND (unique violation),
|
|
27586
|
+
// PENTEST_APPLICATION_FROZEN_AT_STAGE (past scoping), or
|
|
27587
|
+
// PENTEST_APPLICATION_SCOPE_FROZEN (repository scope already snapshotted,
|
|
27588
|
+
// so a new binding could never enter it).
|
|
27589
|
+
409: ErrorResponseSchema,
|
|
27590
|
+
500: ErrorResponseSchema
|
|
27591
|
+
}
|
|
27592
|
+
},
|
|
27593
|
+
unbindApplication: {
|
|
27594
|
+
method: "DELETE",
|
|
27595
|
+
path: "/organizations/:organizationId/pentests/:pentestId/applications/:applicationId",
|
|
27596
|
+
pathParams: PentestApplicationParamsSchema,
|
|
27597
|
+
responses: {
|
|
27598
|
+
204: DeleteResponseSchema,
|
|
27599
|
+
400: ErrorResponseSchema,
|
|
27600
|
+
401: ErrorResponseSchema,
|
|
27601
|
+
403: ErrorResponseSchema,
|
|
27602
|
+
404: ErrorResponseSchema,
|
|
27603
|
+
// 409 — PENTEST_APPLICATION_UNBIND_BLOCKED (this application still has
|
|
27604
|
+
// linked environments), or either frozen guard as on bind.
|
|
27605
|
+
409: ErrorResponseSchema,
|
|
27606
|
+
500: ErrorResponseSchema
|
|
27607
|
+
}
|
|
27608
|
+
},
|
|
26852
27609
|
getScanReuseSuggestions: {
|
|
26853
27610
|
method: "GET",
|
|
26854
27611
|
path: "/organizations/:organizationId/pentests/:pentestId/scan-reuse-suggestions",
|
|
@@ -27427,7 +28184,22 @@ var ScopeRowSchema = external_exports.object({
|
|
|
27427
28184
|
type: ScopeRowType,
|
|
27428
28185
|
label: external_exports.string().min(1).max(200),
|
|
27429
28186
|
description: external_exports.string().max(500),
|
|
27430
|
-
inScope: external_exports.boolean()
|
|
28187
|
+
inScope: external_exports.boolean(),
|
|
28188
|
+
/**
|
|
28189
|
+
* Which bound applications this asset belongs to — DISPLAY NAMES in bind order
|
|
28190
|
+
* (multi-application PR 7).
|
|
28191
|
+
*
|
|
28192
|
+
* A SNAPSHOT, like `PentestRepositoryScope.purposeSnapshot`, not a reference: the
|
|
28193
|
+
* report row is a frozen customer-facing document, and resolving application ids at
|
|
28194
|
+
* render time would let a regenerate after an unbind silently shrink a published
|
|
28195
|
+
* scope column. A name that no longer matches a bound application is therefore
|
|
28196
|
+
* legitimate history, not an error.
|
|
28197
|
+
*
|
|
28198
|
+
* Absent or empty means "provenance unknown" — the renderer omits the cell rather
|
|
28199
|
+
* than printing "none" (the PR 1b hand-off rule, shared with the session briefs).
|
|
28200
|
+
* Capped at the row cap so it can never be the binding constraint below it.
|
|
28201
|
+
*/
|
|
28202
|
+
applications: external_exports.array(external_exports.string().min(1).max(200)).max(100).optional()
|
|
27431
28203
|
});
|
|
27432
28204
|
var ScopeRowsJsonSchema = external_exports.object({
|
|
27433
28205
|
version: external_exports.literal(1),
|
|
@@ -27650,7 +28422,13 @@ var ReportCoverBlockSchema = external_exports.object({
|
|
|
27650
28422
|
testingWindowStart: NullableCoverFieldSchema,
|
|
27651
28423
|
testingWindowEnd: NullableCoverFieldSchema,
|
|
27652
28424
|
classification: CoverFieldSchema,
|
|
27653
|
-
documentId: CoverFieldSchema
|
|
28425
|
+
documentId: CoverFieldSchema,
|
|
28426
|
+
/** Report attribution (derive-with-override like the rest; the derived
|
|
28427
|
+
* value is a firm-default constant, so `value` is always present).
|
|
28428
|
+
* testerName renders as "<name> · <firm>" in the cover's Tested-by row;
|
|
28429
|
+
* approverName is the "Approved by" row (conventionally "Name, Title"). */
|
|
28430
|
+
testerName: CoverFieldSchema,
|
|
28431
|
+
approverName: CoverFieldSchema
|
|
27654
28432
|
});
|
|
27655
28433
|
var ReportCoverFieldNameValues = [
|
|
27656
28434
|
"customerOrgName",
|
|
@@ -27660,7 +28438,9 @@ var ReportCoverFieldNameValues = [
|
|
|
27660
28438
|
"testingWindowStart",
|
|
27661
28439
|
"testingWindowEnd",
|
|
27662
28440
|
"classification",
|
|
27663
|
-
"documentId"
|
|
28441
|
+
"documentId",
|
|
28442
|
+
"testerName",
|
|
28443
|
+
"approverName"
|
|
27664
28444
|
];
|
|
27665
28445
|
var ReportCoverFieldName = external_exports.enum(ReportCoverFieldNameValues);
|
|
27666
28446
|
var ApplyReportCoverRequestSchema = external_exports.object({
|
|
@@ -27719,6 +28499,20 @@ var ReportCanvasResponseSchema = external_exports.object({
|
|
|
27719
28499
|
/** Per-field override provenance for the cover grid (RS2). */
|
|
27720
28500
|
cover: ReportCoverBlockSchema,
|
|
27721
28501
|
scopeRows: external_exports.array(ScopeRowSchema),
|
|
28502
|
+
/**
|
|
28503
|
+
* Every bound application's name, in bind order — what the scope editor offers as
|
|
28504
|
+
* per-row application toggles (multi-application PR 7). Empty for an unbound
|
|
28505
|
+
* engagement; a single entry means the editor stays hidden, matching the report's
|
|
28506
|
+
* own rule that one application needs no attribution column.
|
|
28507
|
+
*
|
|
28508
|
+
* OPTIONAL for the wire, not because the server ever omits it: `apps/web` deploys on
|
|
28509
|
+
* merge while the API deploys after it, and the ts-rest client does not validate
|
|
28510
|
+
* response bodies (`apps/web/lib/api-client.ts` sets no `validateResponse`), so a new
|
|
28511
|
+
* bundle briefly reads an old API's response. A required field would be typed as
|
|
28512
|
+
* present while arriving `undefined` — the same reason
|
|
28513
|
+
* `AgentSessionSpawnContextSchema.applications` is optional. Consumers default it.
|
|
28514
|
+
*/
|
|
28515
|
+
boundApplications: external_exports.array(external_exports.string()).optional(),
|
|
27722
28516
|
/** null = undrafted, or stored JSON was unparseable (degraded — never 500). */
|
|
27723
28517
|
narrative: StoredNarrativeJsonSchema.nullable(),
|
|
27724
28518
|
/** Render Section 05 (Remediation Timeline) in the PDF. Lazy/no-row previews
|
|
@@ -27862,6 +28656,11 @@ var IssuedReportSnapshotSchema = external_exports.object({
|
|
|
27862
28656
|
* pre-feature `input_json` still parses (absent → undefined → standard
|
|
27863
28657
|
* branding). */
|
|
27864
28658
|
coBrandName: external_exports.string().nullable().optional(),
|
|
28659
|
+
/** Report attribution frozen at issuance. Optional so every pre-feature
|
|
28660
|
+
* `input_json` still parses (absent → legacy rendering: firm-only
|
|
28661
|
+
* Tested-by row, no Approved-by row). */
|
|
28662
|
+
testerName: external_exports.string().optional(),
|
|
28663
|
+
approverName: external_exports.string().optional(),
|
|
27865
28664
|
engagementTitle: external_exports.string(),
|
|
27866
28665
|
engagementSubtitle: external_exports.string(),
|
|
27867
28666
|
systemUnderTest: external_exports.string(),
|
|
@@ -28189,7 +28988,18 @@ var PentestFindingResponseSchema = external_exports.object({
|
|
|
28189
28988
|
pentestFindingId: external_exports.uuid(),
|
|
28190
28989
|
organizationId: external_exports.uuid(),
|
|
28191
28990
|
pentestId: external_exports.uuid(),
|
|
28192
|
-
|
|
28991
|
+
/**
|
|
28992
|
+
* Customer-facing finding number (the N in `PTF-N`). NULL until the finding is
|
|
28993
|
+
* published: a finding never shown to a customer has no customer-facing number yet.
|
|
28994
|
+
* Staff and agents identify an unpublished finding by `pentestFindingId` + `title`.
|
|
28995
|
+
*
|
|
28996
|
+
* Nullable here so it cascades to the staff and AGENT derivations below — every
|
|
28997
|
+
* agent-session type except REPORT reads findings with no visibility filter
|
|
28998
|
+
* (agent-session.service.ts operatorListFindings/operatorGetFinding), so a draft
|
|
28999
|
+
* reaches them and a non-null schema would be a Zod 500. The customer derivations
|
|
29000
|
+
* re-narrow it to non-null, because customer visibility implies published.
|
|
29001
|
+
*/
|
|
29002
|
+
displayId: external_exports.number().int().positive().nullable(),
|
|
28193
29003
|
title: external_exports.string(),
|
|
28194
29004
|
description: external_exports.string(),
|
|
28195
29005
|
severity: PentestFindingSeverity,
|
|
@@ -28263,9 +29073,11 @@ var OperatorFindingReadSchema = PentestFindingResponseSchema.omit({
|
|
|
28263
29073
|
externalTicket: true
|
|
28264
29074
|
});
|
|
28265
29075
|
var OperatorFindingRetestSchema = external_exports.object({
|
|
29076
|
+
retestId: external_exports.uuid(),
|
|
28266
29077
|
outcome: RetestOutcome,
|
|
28267
29078
|
notes: external_exports.string().nullable(),
|
|
28268
29079
|
testedAt: external_exports.coerce.date(),
|
|
29080
|
+
editedAt: external_exports.coerce.date().nullable(),
|
|
28269
29081
|
source: PentestFindingRetestSource
|
|
28270
29082
|
});
|
|
28271
29083
|
var OperatorFindingDetailSchema = OperatorFindingReadSchema.extend({
|
|
@@ -28295,10 +29107,20 @@ var CustomerPentestFindingResponseSchema = PentestFindingResponseSchema.omit({
|
|
|
28295
29107
|
reportProseAt: true,
|
|
28296
29108
|
reportProseStatus: true
|
|
28297
29109
|
}).extend({
|
|
29110
|
+
// Customer findings are published-only (customerVisiblePentestFindingWhere), and
|
|
29111
|
+
// publishing is what assigns the number, so it always exists here. Re-narrowed from
|
|
29112
|
+
// the nullable root so the customer dashboard never needs a draft affordance; the
|
|
29113
|
+
// handler mapper throws if the invariant is ever violated rather than coercing.
|
|
29114
|
+
displayId: external_exports.number().int().positive(),
|
|
28298
29115
|
// Customer-safe prose/rendering status. This preserves report/PDF heading
|
|
28299
29116
|
// semantics without exposing the staff-only provenance marker pair.
|
|
28300
29117
|
renderedStatus: PentestFindingStatus,
|
|
28301
|
-
repositories: external_exports.array(CustomerPentestFindingRepositorySchema)
|
|
29118
|
+
repositories: external_exports.array(CustomerPentestFindingRepositorySchema),
|
|
29119
|
+
// True when the customer has an unresolved dispute on this finding. Drives the
|
|
29120
|
+
// customer "dispute under review" hint + suppresses the re-dispute affordance,
|
|
29121
|
+
// even after a retest moved the finding off CONTESTED. Only this derived
|
|
29122
|
+
// boolean crosses the trust boundary — never the staff contest list.
|
|
29123
|
+
hasOpenContest: external_exports.boolean()
|
|
28302
29124
|
});
|
|
28303
29125
|
var CustomerPentestFindingListItemSchema = PentestFindingListItemSchema.omit({
|
|
28304
29126
|
organizationId: true,
|
|
@@ -28310,6 +29132,9 @@ var CustomerPentestFindingListItemSchema = PentestFindingListItemSchema.omit({
|
|
|
28310
29132
|
reportProseAt: true,
|
|
28311
29133
|
reportProseStatus: true
|
|
28312
29134
|
}).extend({
|
|
29135
|
+
// Published-only, same as the customer detail schema above — re-narrowed from the
|
|
29136
|
+
// nullable root.
|
|
29137
|
+
displayId: external_exports.number().int().positive(),
|
|
28313
29138
|
repositories: external_exports.array(CustomerPentestFindingRepositorySchema)
|
|
28314
29139
|
});
|
|
28315
29140
|
var ListCustomerPentestFindingsResponseSchema = external_exports.array(
|
|
@@ -28455,7 +29280,12 @@ var RecoveredFindingResultSchema = external_exports.object({
|
|
|
28455
29280
|
status: external_exports.enum(["recovered", "skipped"]),
|
|
28456
29281
|
reason: external_exports.string().optional(),
|
|
28457
29282
|
pentestFindingId: external_exports.uuid().optional(),
|
|
28458
|
-
|
|
29283
|
+
/**
|
|
29284
|
+
* NULL when the recovered finding has no number yet. Recovered findings land
|
|
29285
|
+
* UNPUBLISHED (see the docstring above), and publishing is what assigns the number,
|
|
29286
|
+
* so `.optional()` alone would reject the `null` the service returns.
|
|
29287
|
+
*/
|
|
29288
|
+
findingDisplayId: external_exports.int().positive().nullish(),
|
|
28459
29289
|
/** Preview-only (dryRun): the title + severity the finding WOULD get. */
|
|
28460
29290
|
findingTitle: external_exports.string().optional(),
|
|
28461
29291
|
severity: PentestFindingSeverity.nullable().optional(),
|
|
@@ -28552,8 +29382,9 @@ var PentestFindingContestResponseSchema = external_exports.object({
|
|
|
28552
29382
|
resolvedById: external_exports.uuid().nullable(),
|
|
28553
29383
|
resolvedByName: external_exports.string().nullable(),
|
|
28554
29384
|
resolvedAt: external_exports.coerce.date().nullable(),
|
|
28555
|
-
// The finding status
|
|
28556
|
-
//
|
|
29385
|
+
// The finding's ACTUAL status at resolution time (any active status for a
|
|
29386
|
+
// status-neutral reject). DISMISSED / ACCEPTED_WITH_CONTROLS ⇔ the dispute
|
|
29387
|
+
// was accepted; anything else ⇔ rejected. NULL while open.
|
|
28557
29388
|
resultStatus: PentestFindingStatus.nullable()
|
|
28558
29389
|
});
|
|
28559
29390
|
var ListPentestFindingContestsResponseSchema = external_exports.array(
|
|
@@ -28578,6 +29409,9 @@ var PentestFindingRetestResponseSchema = external_exports.object({
|
|
|
28578
29409
|
testedById: external_exports.uuid(),
|
|
28579
29410
|
testedByName: external_exports.string(),
|
|
28580
29411
|
testedAt: external_exports.coerce.date(),
|
|
29412
|
+
// Null = never corrected. Staff-only: the customer schema below is an explicit
|
|
29413
|
+
// allowlist, so this cannot reach a customer by omission.
|
|
29414
|
+
editedAt: external_exports.coerce.date().nullable(),
|
|
28581
29415
|
source: PentestFindingRetestSource,
|
|
28582
29416
|
retestRunId: external_exports.uuid().nullable(),
|
|
28583
29417
|
performedByActorType: PentestAuditActorType,
|
|
@@ -29024,7 +29858,8 @@ var pentestFindingContract = c26.router({
|
|
|
29024
29858
|
401: ErrorResponseSchema,
|
|
29025
29859
|
403: ErrorResponseSchema,
|
|
29026
29860
|
404: ErrorResponseSchema,
|
|
29027
|
-
// CONTEST_ALREADY_RESOLVED,
|
|
29861
|
+
// CONTEST_ALREADY_RESOLVED, CONTEST_REJECT_NOT_ALLOWED (reject on a
|
|
29862
|
+
// dismissed/accepted finding), or PENTEST_CLOSED.
|
|
29028
29863
|
409: ErrorResponseSchema,
|
|
29029
29864
|
500: ErrorResponseSchema
|
|
29030
29865
|
}
|
|
@@ -30000,28 +30835,6 @@ var repositoryContract = c31.router({
|
|
|
30000
30835
|
409: ErrorResponseSchema,
|
|
30001
30836
|
500: ErrorResponseSchema
|
|
30002
30837
|
}
|
|
30003
|
-
},
|
|
30004
|
-
/**
|
|
30005
|
-
* Set / clear the per-repo AI coding-agent override (PR 5).
|
|
30006
|
-
* Body `{overrideTool}`: 'claude-code'|'codex' sets, `null` clears.
|
|
30007
|
-
* Response `{aiToolingProfile}` is nullable: clearing on an undetected
|
|
30008
|
-
* repo writes NULL to the column and returns `{aiToolingProfile: null}`.
|
|
30009
|
-
* 422 = `PLATFORM_VALIDATION_UNSUPPORTED` for non-GITHUB platforms.
|
|
30010
|
-
*/
|
|
30011
|
-
setAiToolingProfileOverride: {
|
|
30012
|
-
method: "PATCH",
|
|
30013
|
-
path: "/organizations/:organizationId/repositories/:repositoryId/ai-tooling-profile",
|
|
30014
|
-
pathParams: RepositoryIdParamsSchema,
|
|
30015
|
-
body: SetAiToolingProfileOverrideRequestSchema,
|
|
30016
|
-
responses: {
|
|
30017
|
-
200: SetAiToolingProfileOverrideResponseSchema,
|
|
30018
|
-
400: ErrorResponseSchema,
|
|
30019
|
-
401: ErrorResponseSchema,
|
|
30020
|
-
403: ErrorResponseSchema,
|
|
30021
|
-
404: ErrorResponseSchema,
|
|
30022
|
-
422: ErrorResponseSchema,
|
|
30023
|
-
500: ErrorResponseSchema
|
|
30024
|
-
}
|
|
30025
30838
|
}
|
|
30026
30839
|
});
|
|
30027
30840
|
|
|
@@ -31051,122 +31864,6 @@ var vulnerabilityContract = c36.router({
|
|
|
31051
31864
|
}
|
|
31052
31865
|
});
|
|
31053
31866
|
|
|
31054
|
-
// ../../packages/api-contracts/src/schemas/api/v1/vulnerability-fix-run.api.ts
|
|
31055
|
-
var AGENT_FLAVORS = ["claude-code", "codex"];
|
|
31056
|
-
var VULNERABILITY_FIX_RUN_STATUSES = [
|
|
31057
|
-
"QUEUED",
|
|
31058
|
-
"RUNNING",
|
|
31059
|
-
"ARTIFACTS_READY",
|
|
31060
|
-
"NO_SAFE_FIX",
|
|
31061
|
-
"PATCH_TOO_LARGE",
|
|
31062
|
-
"TESTS_FAILED",
|
|
31063
|
-
"PR_OPENED",
|
|
31064
|
-
"INFRA_FAILED",
|
|
31065
|
-
"STALE_VULN",
|
|
31066
|
-
"TIMED_OUT",
|
|
31067
|
-
"CANCELLED"
|
|
31068
|
-
];
|
|
31069
|
-
var VulnerabilityFixRunPathParamsSchema = VulnerabilityLookupIdParamsSchema.extend({
|
|
31070
|
-
runId: external_exports.uuid()
|
|
31071
|
-
});
|
|
31072
|
-
var TriggerFixRunRequestSchema = external_exports.object({
|
|
31073
|
-
agentFlavor: external_exports.enum(AGENT_FLAVORS).optional()
|
|
31074
|
-
});
|
|
31075
|
-
var VulnerabilityFixRunResponseSchema = external_exports.object({
|
|
31076
|
-
runId: external_exports.uuid(),
|
|
31077
|
-
organizationId: external_exports.uuid(),
|
|
31078
|
-
vulnerabilityId: external_exports.uuid(),
|
|
31079
|
-
repositoryId: external_exports.uuid(),
|
|
31080
|
-
status: external_exports.enum(VULNERABILITY_FIX_RUN_STATUSES),
|
|
31081
|
-
agentFlavor: external_exports.enum(AGENT_FLAVORS),
|
|
31082
|
-
triggeredByUserId: external_exports.uuid().nullable(),
|
|
31083
|
-
triggeredByApiKeyId: external_exports.uuid().nullable(),
|
|
31084
|
-
/**
|
|
31085
|
-
* Display name + avatar of the triggering staff user, resolved
|
|
31086
|
-
* server-side (mirrors `ScanResponseSchema.initiatedByName`). Populated by
|
|
31087
|
-
* every endpoint (list, trigger, get, cancel) so the polled active row in
|
|
31088
|
-
* the runs table keeps the resolved name. `null` only when the run has no
|
|
31089
|
-
* triggering user (api-key path) or the user no longer exists.
|
|
31090
|
-
*/
|
|
31091
|
-
triggeredByName: external_exports.string().nullable(),
|
|
31092
|
-
triggeredByProfilePictureUrl: external_exports.string().nullable(),
|
|
31093
|
-
prUrl: external_exports.string().nullable(),
|
|
31094
|
-
summaryStatus: external_exports.string().nullable(),
|
|
31095
|
-
modelUsed: external_exports.string().nullable(),
|
|
31096
|
-
addedLines: external_exports.number().int().nullable(),
|
|
31097
|
-
removedLines: external_exports.number().int().nullable(),
|
|
31098
|
-
filesChanged: external_exports.number().int().nullable(),
|
|
31099
|
-
statusDetails: external_exports.string().nullable(),
|
|
31100
|
-
queuedAt: external_exports.iso.datetime(),
|
|
31101
|
-
claimedAt: external_exports.iso.datetime().nullable(),
|
|
31102
|
-
deadlineAt: external_exports.iso.datetime().nullable(),
|
|
31103
|
-
completedAt: external_exports.iso.datetime().nullable(),
|
|
31104
|
-
updatedAt: external_exports.iso.datetime()
|
|
31105
|
-
});
|
|
31106
|
-
var ListVulnerabilityFixRunsResponseSchema = external_exports.array(VulnerabilityFixRunResponseSchema);
|
|
31107
|
-
|
|
31108
|
-
// ../../packages/api-contracts/src/contracts/v1/vulnerability-fix-run.ts
|
|
31109
|
-
var c37 = initContract();
|
|
31110
|
-
var vulnerabilityFixRunContract = c37.router({
|
|
31111
|
-
triggerRun: {
|
|
31112
|
-
method: "POST",
|
|
31113
|
-
path: "/organizations/:organizationId/vulnerabilities/:vulnerabilityId/fix-pr-runs",
|
|
31114
|
-
pathParams: VulnerabilityLookupIdParamsSchema,
|
|
31115
|
-
body: TriggerFixRunRequestSchema,
|
|
31116
|
-
responses: {
|
|
31117
|
-
201: VulnerabilityFixRunResponseSchema,
|
|
31118
|
-
400: ErrorResponseSchema,
|
|
31119
|
-
401: ErrorResponseSchema,
|
|
31120
|
-
403: ErrorResponseSchema,
|
|
31121
|
-
404: ErrorResponseSchema,
|
|
31122
|
-
409: ErrorResponseSchema,
|
|
31123
|
-
429: ErrorResponseSchema,
|
|
31124
|
-
500: ErrorResponseSchema
|
|
31125
|
-
}
|
|
31126
|
-
},
|
|
31127
|
-
getRun: {
|
|
31128
|
-
method: "GET",
|
|
31129
|
-
path: "/organizations/:organizationId/vulnerabilities/:vulnerabilityId/fix-pr-runs/:runId",
|
|
31130
|
-
pathParams: VulnerabilityFixRunPathParamsSchema,
|
|
31131
|
-
responses: {
|
|
31132
|
-
200: VulnerabilityFixRunResponseSchema,
|
|
31133
|
-
400: ErrorResponseSchema,
|
|
31134
|
-
401: ErrorResponseSchema,
|
|
31135
|
-
403: ErrorResponseSchema,
|
|
31136
|
-
404: ErrorResponseSchema,
|
|
31137
|
-
500: ErrorResponseSchema
|
|
31138
|
-
}
|
|
31139
|
-
},
|
|
31140
|
-
cancelRun: {
|
|
31141
|
-
method: "POST",
|
|
31142
|
-
path: "/organizations/:organizationId/vulnerabilities/:vulnerabilityId/fix-pr-runs/:runId/cancel",
|
|
31143
|
-
pathParams: VulnerabilityFixRunPathParamsSchema,
|
|
31144
|
-
body: null,
|
|
31145
|
-
responses: {
|
|
31146
|
-
200: VulnerabilityFixRunResponseSchema,
|
|
31147
|
-
400: ErrorResponseSchema,
|
|
31148
|
-
401: ErrorResponseSchema,
|
|
31149
|
-
403: ErrorResponseSchema,
|
|
31150
|
-
404: ErrorResponseSchema,
|
|
31151
|
-
409: ErrorResponseSchema,
|
|
31152
|
-
500: ErrorResponseSchema
|
|
31153
|
-
}
|
|
31154
|
-
},
|
|
31155
|
-
listRuns: {
|
|
31156
|
-
method: "GET",
|
|
31157
|
-
path: "/organizations/:organizationId/vulnerabilities/:vulnerabilityId/fix-pr-runs",
|
|
31158
|
-
pathParams: VulnerabilityLookupIdParamsSchema,
|
|
31159
|
-
responses: {
|
|
31160
|
-
200: ListVulnerabilityFixRunsResponseSchema,
|
|
31161
|
-
400: ErrorResponseSchema,
|
|
31162
|
-
401: ErrorResponseSchema,
|
|
31163
|
-
403: ErrorResponseSchema,
|
|
31164
|
-
404: ErrorResponseSchema,
|
|
31165
|
-
500: ErrorResponseSchema
|
|
31166
|
-
}
|
|
31167
|
-
}
|
|
31168
|
-
});
|
|
31169
|
-
|
|
31170
31867
|
// ../../packages/api-contracts/src/schemas/api/v1/vulnerability-note.api.ts
|
|
31171
31868
|
var VulnerabilityLookupNoteParamsSchema = OrgIdParamsSchema.extend({
|
|
31172
31869
|
vulnerabilityId: VulnerabilityLookupIdSchema
|
|
@@ -31194,8 +31891,8 @@ var UpdateVulnerabilityNoteRequestSchema = external_exports.object({
|
|
|
31194
31891
|
});
|
|
31195
31892
|
|
|
31196
31893
|
// ../../packages/api-contracts/src/contracts/v1/vulnerability-note.ts
|
|
31197
|
-
var
|
|
31198
|
-
var vulnerabilityNoteContract =
|
|
31894
|
+
var c37 = initContract();
|
|
31895
|
+
var vulnerabilityNoteContract = c37.router({
|
|
31199
31896
|
listNotes: {
|
|
31200
31897
|
method: "GET",
|
|
31201
31898
|
path: "/organizations/:organizationId/vulnerabilities/:vulnerabilityId/notes",
|
|
@@ -31376,8 +32073,8 @@ var ListWebhookDeliveriesResponseSchema = external_exports.object({
|
|
|
31376
32073
|
});
|
|
31377
32074
|
|
|
31378
32075
|
// ../../packages/api-contracts/src/contracts/v1/webhook-settings.ts
|
|
31379
|
-
var
|
|
31380
|
-
var webhookSettingsContract =
|
|
32076
|
+
var c38 = initContract();
|
|
32077
|
+
var webhookSettingsContract = c38.router({
|
|
31381
32078
|
listWebhookEndpoints: {
|
|
31382
32079
|
method: "GET",
|
|
31383
32080
|
path: "/organizations/:organizationId/webhook-settings/endpoints",
|
|
@@ -31515,8 +32212,8 @@ var webhookSettingsContract = c39.router({
|
|
|
31515
32212
|
});
|
|
31516
32213
|
|
|
31517
32214
|
// ../../packages/api-contracts/src/contracts/v1/index.ts
|
|
31518
|
-
var
|
|
31519
|
-
var v1Contract =
|
|
32215
|
+
var c39 = initContract();
|
|
32216
|
+
var v1Contract = c39.router(
|
|
31520
32217
|
{
|
|
31521
32218
|
admin: adminContract,
|
|
31522
32219
|
cloudIntegration: cloudIntegrationContract,
|
|
@@ -31536,7 +32233,6 @@ var v1Contract = c40.router(
|
|
|
31536
32233
|
knowledgeDocument: knowledgeDocumentContract,
|
|
31537
32234
|
vulnerability: vulnerabilityContract,
|
|
31538
32235
|
vulnerabilityNote: vulnerabilityNoteContract,
|
|
31539
|
-
vulnerabilityFixRun: vulnerabilityFixRunContract,
|
|
31540
32236
|
webhookSettings: webhookSettingsContract,
|
|
31541
32237
|
application: applicationContract,
|
|
31542
32238
|
chatSession: chatSessionContract,
|
|
@@ -31565,8 +32261,8 @@ var v1Contract = c40.router(
|
|
|
31565
32261
|
);
|
|
31566
32262
|
|
|
31567
32263
|
// ../../packages/api-contracts/src/contracts/index.ts
|
|
31568
|
-
var
|
|
31569
|
-
var contract =
|
|
32264
|
+
var c40 = initContract();
|
|
32265
|
+
var contract = c40.router({
|
|
31570
32266
|
v1: v1Contract
|
|
31571
32267
|
});
|
|
31572
32268
|
|
|
@@ -31615,7 +32311,7 @@ var ComplianceRegimeValues = [
|
|
|
31615
32311
|
var ComplianceRegime = external_exports.enum(ComplianceRegimeValues);
|
|
31616
32312
|
|
|
31617
32313
|
// ../../packages/api-contracts/src/contracts/v1/agent-session-internal.ts
|
|
31618
|
-
var
|
|
32314
|
+
var c41 = initContract();
|
|
31619
32315
|
var AgentSessionInternalParamsSchema = external_exports.object({
|
|
31620
32316
|
agentSessionId: external_exports.uuid()
|
|
31621
32317
|
});
|
|
@@ -31729,8 +32425,13 @@ var RecordCandidateVulnRequestSchema = external_exports.object({
|
|
|
31729
32425
|
/** Idempotency key, stable across POST retries of one tool invocation. */
|
|
31730
32426
|
sourceKey: external_exports.string().min(1).max(256),
|
|
31731
32427
|
candidate: external_exports.object({
|
|
31732
|
-
|
|
31733
|
-
|
|
32428
|
+
// Kept in lockstep with the record_candidate_vuln tool schema in
|
|
32429
|
+
// apps/agent-session-host/src/recording.ts — a tool cap looser than this
|
|
32430
|
+
// one turns a model-visible limit into an opaque API rejection. title 250 /
|
|
32431
|
+
// description 6000 were raised from 200/5000, which observed usage had
|
|
32432
|
+
// saturated (median description 4154 of 5000).
|
|
32433
|
+
title: external_exports.string().min(1).max(250),
|
|
32434
|
+
description: external_exports.string().min(1).max(6e3),
|
|
31734
32435
|
attackChain: external_exports.string().min(1).max(5e3),
|
|
31735
32436
|
exploitTechnique: external_exports.string().min(1).max(5e3),
|
|
31736
32437
|
prerequisiteAccess: external_exports.string().min(1).max(5e3).optional(),
|
|
@@ -31773,7 +32474,7 @@ var RecordProductContextResponseSchema = external_exports.object({
|
|
|
31773
32474
|
disputed: external_exports.number().int().nonnegative(),
|
|
31774
32475
|
rejected: external_exports.number().int().nonnegative()
|
|
31775
32476
|
});
|
|
31776
|
-
var ThreatModelStatement = external_exports.string().min(1).max(
|
|
32477
|
+
var ThreatModelStatement = external_exports.string().min(1).max(2e3);
|
|
31777
32478
|
var RepoScopedThreatItem = external_exports.object({
|
|
31778
32479
|
repoAlias: external_exports.string().min(1).max(200),
|
|
31779
32480
|
statement: ThreatModelStatement
|
|
@@ -31924,17 +32625,71 @@ var RecordValidationResultRequestSchema = external_exports.object({
|
|
|
31924
32625
|
* customerFacing labels. The api stores them on the `PentestExploitArtifact` row (caption →
|
|
31925
32626
|
* `description`) and links them to the promoted finding.
|
|
31926
32627
|
*/
|
|
31927
|
-
evidence: external_exports.array(RecordValidationEvidenceItemSchema).max(32).optional()
|
|
32628
|
+
evidence: external_exports.array(RecordValidationEvidenceItemSchema).max(32).optional(),
|
|
32629
|
+
/**
|
|
32630
|
+
* PROVEN-only. The EXISTING finding this proof belongs to — the same root-cause
|
|
32631
|
+
* weakness, already reported by an earlier session. Set it INSTEAD of promoting:
|
|
32632
|
+
* the covered candidate(s) attach to that finding and no second finding is created.
|
|
32633
|
+
*
|
|
32634
|
+
* When set, `prose` is that finding's COMPLETE prose with this investigation's
|
|
32635
|
+
* addition folded in (read it with get_finding first), not a fragment — the api
|
|
32636
|
+
* writes the prose columns verbatim. Scoring fields (cvssVector / cweIds / category /
|
|
32637
|
+
* owaspCategory / severity) are REJECTED on a bind rather than silently dropped; a
|
|
32638
|
+
* second proof of a known weakness must not re-score a finding staff already
|
|
32639
|
+
* triaged. `repositories` IS applied, additively.
|
|
32640
|
+
*/
|
|
32641
|
+
bindToPentestFindingId: external_exports.uuid().optional(),
|
|
32642
|
+
/**
|
|
32643
|
+
* The bound finding's `updatedAt` as returned by get_finding. Optimistic lock: a
|
|
32644
|
+
* staff edit landing between the read and this call returns BIND_STALE_FINDING
|
|
32645
|
+
* instead of silently clobbering their text. Required whenever
|
|
32646
|
+
* `bindToPentestFindingId` is set AND `prose` is supplied.
|
|
32647
|
+
*/
|
|
32648
|
+
bindExpectedUpdatedAt: external_exports.coerce.date().optional()
|
|
31928
32649
|
}).refine((body) => (body.hypothesisIds?.length ?? 0) > 0 || body.hypothesisId !== void 0, {
|
|
31929
32650
|
message: "record_validation_result requires hypothesisIds (or the legacy hypothesisId)",
|
|
31930
32651
|
path: ["hypothesisIds"]
|
|
31931
|
-
})
|
|
32652
|
+
}).refine(
|
|
32653
|
+
(body) => body.bindToPentestFindingId === void 0 || body.prose == null || body.bindExpectedUpdatedAt !== void 0,
|
|
32654
|
+
{
|
|
32655
|
+
message: "bindExpectedUpdatedAt is required when binding with prose (pass the finding updatedAt from get_finding)",
|
|
32656
|
+
path: ["bindExpectedUpdatedAt"]
|
|
32657
|
+
}
|
|
32658
|
+
);
|
|
31932
32659
|
var RecordValidationResultResponseSchema = external_exports.object({
|
|
31933
32660
|
attemptId: external_exports.uuid(),
|
|
31934
32661
|
verdict: ValidationVerdict,
|
|
31935
32662
|
/** True when a PentestFinding was created from this PROVEN result. */
|
|
31936
32663
|
promoted: external_exports.boolean(),
|
|
31937
|
-
|
|
32664
|
+
/**
|
|
32665
|
+
* The promoted finding's customer-facing number, or NULL when it has none yet — a
|
|
32666
|
+
* freshly promoted finding is UNPUBLISHED, and publishing is what assigns the number.
|
|
32667
|
+
* `promoted: true` with `findingDisplayId: null` means "finding created, not yet
|
|
32668
|
+
* numbered".
|
|
32669
|
+
*/
|
|
32670
|
+
findingDisplayId: external_exports.number().int().positive().nullish(),
|
|
32671
|
+
/**
|
|
32672
|
+
* The promoted finding's durable id, present whenever `promoted` is true. This is the
|
|
32673
|
+
* handle the agent acts on — and once numbering moves to publish it is the ONLY handle
|
|
32674
|
+
* a freshly promoted finding has, since `findingDisplayId` is null until then.
|
|
32675
|
+
*/
|
|
32676
|
+
pentestFindingId: external_exports.uuid().optional(),
|
|
32677
|
+
/**
|
|
32678
|
+
* True when the verdict attached to an EXISTING finding (`bindToPentestFindingId`)
|
|
32679
|
+
* instead of promoting a new one. `promoted` stays false in that case, while
|
|
32680
|
+
* `pentestFindingId` carries the bound finding — so the agent still holds the handle
|
|
32681
|
+
* for the finding it just acted on.
|
|
32682
|
+
*/
|
|
32683
|
+
bound: external_exports.boolean().optional(),
|
|
32684
|
+
/**
|
|
32685
|
+
* How the bind's addition landed. REPORT_PROSE = merged into the finding's report prose
|
|
32686
|
+
* and its repository links (it was unpublished). FINDING_NOTE = filed as a staff note
|
|
32687
|
+
* instead, because the finding is PUBLISHED: nothing customer-facing on it is
|
|
32688
|
+
* agent-editable, which covers the prose AND any cited repository locations. NONE =
|
|
32689
|
+
* there was nothing to apply — no prose and no citations, or a replay, whose original
|
|
32690
|
+
* call already applied whatever it carried. Present whenever `bound`.
|
|
32691
|
+
*/
|
|
32692
|
+
deltaApplied: external_exports.enum(["REPORT_PROSE", "FINDING_NOTE", "NONE"]).optional(),
|
|
31938
32693
|
/**
|
|
31939
32694
|
* The candidate(s) the verdict was bound to (PR A) — each as {displayId, title} so the
|
|
31940
32695
|
* agent can notice a mis-tag by comparing the echoed TITLE against what it actually
|
|
@@ -31999,6 +32754,55 @@ var AgentSessionLoginCodeResponseSchema = external_exports.object({
|
|
|
31999
32754
|
value: external_exports.string().optional(),
|
|
32000
32755
|
receivedAt: external_exports.coerce.date().optional()
|
|
32001
32756
|
});
|
|
32757
|
+
var AgentSessionListInboxMessagesRequestSchema = external_exports.object({
|
|
32758
|
+
runVersion: external_exports.number().int().nonnegative(),
|
|
32759
|
+
/** Which account's inbox (by `Credential.label`); omit if exactly one is readable. */
|
|
32760
|
+
credentialLabel: external_exports.string().min(1).max(200).optional(),
|
|
32761
|
+
/** Max messages, newest first. Clamped server-side. */
|
|
32762
|
+
limit: external_exports.number().int().positive().max(50).optional()
|
|
32763
|
+
});
|
|
32764
|
+
var InboxMessageSummarySchema = external_exports.object({
|
|
32765
|
+
messageId: external_exports.string().min(1).max(500),
|
|
32766
|
+
from: external_exports.string().max(500),
|
|
32767
|
+
subject: external_exports.string().max(1e3).nullable(),
|
|
32768
|
+
/** Provider-generated short body preview. */
|
|
32769
|
+
preview: external_exports.string().max(2e3).nullable(),
|
|
32770
|
+
receivedAt: external_exports.coerce.date(),
|
|
32771
|
+
unread: external_exports.boolean()
|
|
32772
|
+
});
|
|
32773
|
+
var AgentSessionListInboxMessagesResponseSchema = external_exports.object({
|
|
32774
|
+
/** The account whose inbox was read, echoed so the agent can pass it to get_email. */
|
|
32775
|
+
credentialLabel: external_exports.string().max(200),
|
|
32776
|
+
messages: external_exports.array(InboxMessageSummarySchema)
|
|
32777
|
+
});
|
|
32778
|
+
var AgentSessionGetInboxMessageRequestSchema = external_exports.object({
|
|
32779
|
+
runVersion: external_exports.number().int().nonnegative(),
|
|
32780
|
+
/** Message id from a `list_emails` result. */
|
|
32781
|
+
messageId: external_exports.string().min(1).max(500),
|
|
32782
|
+
credentialLabel: external_exports.string().min(1).max(200).optional()
|
|
32783
|
+
});
|
|
32784
|
+
var AgentSessionGetInboxMessageResponseSchema = external_exports.object({
|
|
32785
|
+
credentialLabel: external_exports.string().max(200),
|
|
32786
|
+
message: InboxMessageSummarySchema.extend({
|
|
32787
|
+
/**
|
|
32788
|
+
* The body as plain text, prompt-injection-neutralized and length-capped
|
|
32789
|
+
* ({@link INBOX_MESSAGE_BODY_MAX_CHARS}). Deliberately NOT run through the
|
|
32790
|
+
* credential redactor — that would rewrite the `?token=…` in a magic link,
|
|
32791
|
+
* which is the artifact the agent needs.
|
|
32792
|
+
*/
|
|
32793
|
+
body: external_exports.string(),
|
|
32794
|
+
/** True when the body was truncated at the cap. */
|
|
32795
|
+
truncated: external_exports.boolean()
|
|
32796
|
+
}),
|
|
32797
|
+
/**
|
|
32798
|
+
* http(s) links extracted from the message in priority order (hrefs first,
|
|
32799
|
+
* then inline text URLs), pre-computed so the agent doesn't have to parse the
|
|
32800
|
+
* body. Same extraction and same URL-safety guards the login flow used.
|
|
32801
|
+
*/
|
|
32802
|
+
links: external_exports.array(external_exports.string()),
|
|
32803
|
+
/** Detected one-time code, if the message carried one. */
|
|
32804
|
+
otp: external_exports.string().nullable()
|
|
32805
|
+
});
|
|
32002
32806
|
var RenewCloudCredentialsRequestSchema = external_exports.object({
|
|
32003
32807
|
runVersion: external_exports.number().int().nonnegative()
|
|
32004
32808
|
});
|
|
@@ -32014,6 +32818,42 @@ var RenewCloudCredentialsResponseSchema = external_exports.object({
|
|
|
32014
32818
|
accessToken: external_exports.string().min(1)
|
|
32015
32819
|
}).nullable()
|
|
32016
32820
|
});
|
|
32821
|
+
var ConvexReconRequestSchema = external_exports.object({
|
|
32822
|
+
runVersion: external_exports.number().int().nonnegative()
|
|
32823
|
+
});
|
|
32824
|
+
var ConvexReconInventorySchema = external_exports.discriminatedUnion("status", [
|
|
32825
|
+
/**
|
|
32826
|
+
* Convex's `apiSpec` payload, forwarded verbatim: per function the identifier,
|
|
32827
|
+
* type, visibility (public/internal) and argument validators, plus httpRoutes
|
|
32828
|
+
* and cronSpecs. Deliberately `unknown` — it describes the customer's own
|
|
32829
|
+
* deployment, not a Trace domain object, so pinning its shape would break when
|
|
32830
|
+
* Convex extends it.
|
|
32831
|
+
*/
|
|
32832
|
+
external_exports.object({ status: external_exports.literal("ok"), functions: external_exports.unknown() }),
|
|
32833
|
+
/** Convex answered HTTP 200 with `status: "error"` — a function-level error. */
|
|
32834
|
+
external_exports.object({ status: external_exports.literal("error"), message: external_exports.string() }),
|
|
32835
|
+
/** Convex 401/403 — the grant is gone; the row was flipped ACCESS_DENIED. */
|
|
32836
|
+
external_exports.object({ status: external_exports.literal("access_denied") }),
|
|
32837
|
+
/** Convex 429/5xx/timeout, a decrypt failure, or the response budget spent. */
|
|
32838
|
+
external_exports.object({ status: external_exports.literal("unavailable") }),
|
|
32839
|
+
/** Over the per-deployment byte cap. NEVER truncated — a half inventory read as
|
|
32840
|
+
* complete is worse than an explicit gap. */
|
|
32841
|
+
external_exports.object({ status: external_exports.literal("too_large"), bytes: external_exports.number().int().nonnegative() })
|
|
32842
|
+
]);
|
|
32843
|
+
var ConvexReconDeploymentSchema = external_exports.object({
|
|
32844
|
+
deploymentName: external_exports.string().min(1),
|
|
32845
|
+
/** Convex's DeploymentType verbatim (dev/prod/preview/custom) — never an enum. */
|
|
32846
|
+
deploymentType: external_exports.string().min(1),
|
|
32847
|
+
/** Region-qualified, from the stored row. NEVER synthesised from deploymentName. */
|
|
32848
|
+
convexCloudUrl: external_exports.string().min(1),
|
|
32849
|
+
/** Null when get_canonical_urls failed at connect; the host is not derivable. */
|
|
32850
|
+
convexSiteUrl: external_exports.string().min(1).nullable(),
|
|
32851
|
+
inventory: ConvexReconInventorySchema
|
|
32852
|
+
});
|
|
32853
|
+
var ConvexReconResponseSchema = external_exports.object({
|
|
32854
|
+
/** Empty when the org has no connected, key-bearing Convex deployment. */
|
|
32855
|
+
deployments: external_exports.array(ConvexReconDeploymentSchema)
|
|
32856
|
+
});
|
|
32017
32857
|
var AgentSessionGetSessionStateRequestSchema = external_exports.object({
|
|
32018
32858
|
runVersion: external_exports.number().int().nonnegative(),
|
|
32019
32859
|
/** Which SESSION_STATE credential to fetch (from the non-secret env reference). */
|
|
@@ -32154,6 +32994,32 @@ var OperatorRecordFindingRetestRequestSchema = CreatePentestFindingRetestRequest
|
|
|
32154
32994
|
});
|
|
32155
32995
|
}
|
|
32156
32996
|
});
|
|
32997
|
+
var OperatorRetestAckSchema = OperatorFindingReadSchema.extend({
|
|
32998
|
+
retestId: external_exports.uuid()
|
|
32999
|
+
});
|
|
33000
|
+
var OperatorEditFindingRetestRequestSchema = external_exports.object({
|
|
33001
|
+
runVersion: operatorRunVersion,
|
|
33002
|
+
reason: operatorReason,
|
|
33003
|
+
retestId: external_exports.uuid(),
|
|
33004
|
+
outcome: RetestOutcome.optional(),
|
|
33005
|
+
notes: external_exports.string().trim().min(1).max(1e4).optional(),
|
|
33006
|
+
verification: external_exports.string().min(1).max(8e3).optional()
|
|
33007
|
+
}).superRefine((v2, ctx) => {
|
|
33008
|
+
if (v2.outcome === void 0 && v2.notes === void 0) {
|
|
33009
|
+
ctx.addIssue({
|
|
33010
|
+
code: "custom",
|
|
33011
|
+
message: "provide outcome, notes, or both \u2014 an edit must change something",
|
|
33012
|
+
path: ["notes"]
|
|
33013
|
+
});
|
|
33014
|
+
}
|
|
33015
|
+
if (v2.verification !== void 0 && v2.outcome !== "FIXED") {
|
|
33016
|
+
ctx.addIssue({
|
|
33017
|
+
code: "custom",
|
|
33018
|
+
message: "verification report prose is only allowed when outcome is FIXED",
|
|
33019
|
+
path: ["verification"]
|
|
33020
|
+
});
|
|
33021
|
+
}
|
|
33022
|
+
});
|
|
32157
33023
|
var OperatorMarkRemediationReportedRequestSchema = MarkPentestFindingRemediationReportedRequestSchema.extend({
|
|
32158
33024
|
runVersion: operatorRunVersion,
|
|
32159
33025
|
reason: operatorReason,
|
|
@@ -32300,7 +33166,7 @@ var ReportUpdateScopeRequestSchema = external_exports.object({
|
|
|
32300
33166
|
expectedUpdatedAt: reportExpectedUpdatedAt,
|
|
32301
33167
|
rows: external_exports.array(ScopeRowSchema).max(100)
|
|
32302
33168
|
});
|
|
32303
|
-
var agentSessionInternalContract =
|
|
33169
|
+
var agentSessionInternalContract = c41.router({
|
|
32304
33170
|
postEvents: {
|
|
32305
33171
|
method: "POST",
|
|
32306
33172
|
path: "/internal/v1/agent-sessions/:agentSessionId/events",
|
|
@@ -32457,6 +33323,10 @@ var agentSessionInternalContract = c42.router({
|
|
|
32457
33323
|
200: ReattributeValidationResultResponseSchema,
|
|
32458
33324
|
400: ErrorResponseSchema,
|
|
32459
33325
|
401: ErrorResponseSchema,
|
|
33326
|
+
// The attempt or the target hypothesis does not exist in this pentest — in practice a
|
|
33327
|
+
// mistyped id in the agent's call. Declared because it is the likeliest failure here and
|
|
33328
|
+
// a reader who assumes it cannot 404 mis-diagnoses the retry loop it causes.
|
|
33329
|
+
404: ErrorResponseSchema,
|
|
32460
33330
|
// runVersion/status guard, stage mismatch, R-not-approved, R-already-promoted,
|
|
32461
33331
|
// or attempt-not-in-run.
|
|
32462
33332
|
409: ErrorResponseSchema,
|
|
@@ -32478,7 +33348,53 @@ var agentSessionInternalContract = c42.router({
|
|
|
32478
33348
|
409: ErrorResponseSchema,
|
|
32479
33349
|
// No MAGIC_AUTH credential on the pentest's environments.
|
|
32480
33350
|
404: ErrorResponseSchema,
|
|
32481
|
-
500: ErrorResponseSchema
|
|
33351
|
+
500: ErrorResponseSchema,
|
|
33352
|
+
// Mail provider unavailable — RETRYABLE, and distinct from 500 so the host
|
|
33353
|
+
// can tell "we could not look" from "this will never work".
|
|
33354
|
+
503: ErrorResponseSchema
|
|
33355
|
+
}
|
|
33356
|
+
},
|
|
33357
|
+
// list_emails: newest-first metadata for the pentest's readable Trace-managed
|
|
33358
|
+
// inbox. Same resolution + ownership gate as login-code (org + pentest
|
|
33359
|
+
// environments + provider-side inbox tenancy); no bodies cross the wire here.
|
|
33360
|
+
listInboxMessages: {
|
|
33361
|
+
method: "POST",
|
|
33362
|
+
path: "/internal/v1/agent-sessions/:agentSessionId/inbox-messages",
|
|
33363
|
+
pathParams: AgentSessionInternalParamsSchema,
|
|
33364
|
+
body: AgentSessionListInboxMessagesRequestSchema,
|
|
33365
|
+
responses: {
|
|
33366
|
+
200: AgentSessionListInboxMessagesResponseSchema,
|
|
33367
|
+
// Ambiguous credentialLabel (several readable inboxes, none named).
|
|
33368
|
+
400: ErrorResponseSchema,
|
|
33369
|
+
401: ErrorResponseSchema,
|
|
33370
|
+
409: ErrorResponseSchema,
|
|
33371
|
+
// No readable Trace-managed inbox on the pentest's environments, or the
|
|
33372
|
+
// resolved address is not owned by this run's organization.
|
|
33373
|
+
404: ErrorResponseSchema,
|
|
33374
|
+
500: ErrorResponseSchema,
|
|
33375
|
+
// Mail provider unavailable — RETRYABLE, and distinct from 500 so the host
|
|
33376
|
+
// can tell "we could not look" from "this will never work".
|
|
33377
|
+
503: ErrorResponseSchema
|
|
33378
|
+
}
|
|
33379
|
+
},
|
|
33380
|
+
// get_email: one message from that inbox, body included. The body is
|
|
33381
|
+
// third-party text — the api neutralizes and length-caps it before it can
|
|
33382
|
+
// reach the agent's context.
|
|
33383
|
+
getInboxMessage: {
|
|
33384
|
+
method: "POST",
|
|
33385
|
+
path: "/internal/v1/agent-sessions/:agentSessionId/inbox-message",
|
|
33386
|
+
pathParams: AgentSessionInternalParamsSchema,
|
|
33387
|
+
body: AgentSessionGetInboxMessageRequestSchema,
|
|
33388
|
+
responses: {
|
|
33389
|
+
200: AgentSessionGetInboxMessageResponseSchema,
|
|
33390
|
+
400: ErrorResponseSchema,
|
|
33391
|
+
401: ErrorResponseSchema,
|
|
33392
|
+
409: ErrorResponseSchema,
|
|
33393
|
+
// Unknown inbox (as above) OR the message id is not in that inbox.
|
|
33394
|
+
404: ErrorResponseSchema,
|
|
33395
|
+
500: ErrorResponseSchema,
|
|
33396
|
+
// Mail provider unavailable — RETRYABLE (see listInboxMessages).
|
|
33397
|
+
503: ErrorResponseSchema
|
|
32482
33398
|
}
|
|
32483
33399
|
},
|
|
32484
33400
|
// get_session_state (SESSION_STATE, spec §2/§3): api-mediated JIT fetch — the api
|
|
@@ -32518,6 +33434,26 @@ var agentSessionInternalContract = c42.router({
|
|
|
32518
33434
|
500: ErrorResponseSchema
|
|
32519
33435
|
}
|
|
32520
33436
|
},
|
|
33437
|
+
// get_convex_deployments (Convex integration PR 3): the read-only broker. Every
|
|
33438
|
+
// connected Convex deployment for the run's OWN org, each with its function
|
|
33439
|
+
// inventory. No request identifier at all — see the schema block above. No 404:
|
|
33440
|
+
// there is no agent-supplied id to miss. No 503: a Convex outage is the
|
|
33441
|
+
// per-deployment `unavailable` status, so one bad deployment never fails the rest.
|
|
33442
|
+
convexRecon: {
|
|
33443
|
+
method: "POST",
|
|
33444
|
+
path: "/internal/v1/agent-sessions/:agentSessionId/convex/recon",
|
|
33445
|
+
pathParams: AgentSessionInternalParamsSchema,
|
|
33446
|
+
body: ConvexReconRequestSchema,
|
|
33447
|
+
responses: {
|
|
33448
|
+
200: ConvexReconResponseSchema,
|
|
33449
|
+
400: ErrorResponseSchema,
|
|
33450
|
+
401: ErrorResponseSchema,
|
|
33451
|
+
// Non-credentialed session type — this run may never reach customer clouds.
|
|
33452
|
+
403: ErrorResponseSchema,
|
|
33453
|
+
409: ErrorResponseSchema,
|
|
33454
|
+
500: ErrorResponseSchema
|
|
33455
|
+
}
|
|
33456
|
+
},
|
|
32521
33457
|
// Operator reads (operator-session PR 1 §2b). All run-token authed; org+pentest
|
|
32522
33458
|
// derived from the session row. Detail ops 404 when the id is not in this pentest.
|
|
32523
33459
|
getPentestContext: {
|
|
@@ -32714,7 +33650,21 @@ var agentSessionInternalContract = c42.router({
|
|
|
32714
33650
|
pathParams: AgentSessionInternalParamsSchema,
|
|
32715
33651
|
body: OperatorRecordFindingRetestRequestSchema,
|
|
32716
33652
|
responses: {
|
|
32717
|
-
200:
|
|
33653
|
+
200: OperatorRetestAckSchema,
|
|
33654
|
+
400: ErrorResponseSchema,
|
|
33655
|
+
401: ErrorResponseSchema,
|
|
33656
|
+
404: ErrorResponseSchema,
|
|
33657
|
+
409: ErrorResponseSchema,
|
|
33658
|
+
500: ErrorResponseSchema
|
|
33659
|
+
}
|
|
33660
|
+
},
|
|
33661
|
+
editFindingRetest: {
|
|
33662
|
+
method: "POST",
|
|
33663
|
+
path: "/internal/v1/agent-sessions/:agentSessionId/operator/findings/retest/edit",
|
|
33664
|
+
pathParams: AgentSessionInternalParamsSchema,
|
|
33665
|
+
body: OperatorEditFindingRetestRequestSchema,
|
|
33666
|
+
responses: {
|
|
33667
|
+
200: OperatorRetestAckSchema,
|
|
32718
33668
|
400: ErrorResponseSchema,
|
|
32719
33669
|
401: ErrorResponseSchema,
|
|
32720
33670
|
404: ErrorResponseSchema,
|
|
@@ -32916,8 +33866,8 @@ var GitHubWebhookResponseSchema = external_exports.object({
|
|
|
32916
33866
|
});
|
|
32917
33867
|
|
|
32918
33868
|
// ../../packages/api-contracts/src/contracts/webhooks/github.ts
|
|
32919
|
-
var
|
|
32920
|
-
var githubWebhookContract =
|
|
33869
|
+
var c42 = initContract();
|
|
33870
|
+
var githubWebhookContract = c42.router(
|
|
32921
33871
|
{
|
|
32922
33872
|
handleWebhook: {
|
|
32923
33873
|
method: "POST",
|
|
@@ -32935,7 +33885,7 @@ var githubWebhookContract = c43.router(
|
|
|
32935
33885
|
pathPrefix: "/webhooks"
|
|
32936
33886
|
}
|
|
32937
33887
|
);
|
|
32938
|
-
var githubReadonlyWebhookContract =
|
|
33888
|
+
var githubReadonlyWebhookContract = c42.router(
|
|
32939
33889
|
{
|
|
32940
33890
|
handleWebhook: {
|
|
32941
33891
|
method: "POST",
|
|
@@ -32955,9 +33905,9 @@ var githubReadonlyWebhookContract = c43.router(
|
|
|
32955
33905
|
);
|
|
32956
33906
|
|
|
32957
33907
|
// ../../packages/api-contracts/src/contracts/webhooks/linear.ts
|
|
32958
|
-
var
|
|
33908
|
+
var c43 = initContract();
|
|
32959
33909
|
var LinearWebhookResponseSchema = external_exports.object({ ok: external_exports.boolean() });
|
|
32960
|
-
var linearWebhookContract =
|
|
33910
|
+
var linearWebhookContract = c43.router(
|
|
32961
33911
|
{
|
|
32962
33912
|
handleWebhook: {
|
|
32963
33913
|
method: "POST",
|
|
@@ -32977,7 +33927,7 @@ var linearWebhookContract = c44.router(
|
|
|
32977
33927
|
);
|
|
32978
33928
|
|
|
32979
33929
|
// ../../packages/api-contracts/src/contracts/forge/bitbucket.ts
|
|
32980
|
-
var
|
|
33930
|
+
var c44 = initContract();
|
|
32981
33931
|
var InstallEventSchema = external_exports.object({
|
|
32982
33932
|
eventType: external_exports.enum(["avi:forge:installed:app", "avi:forge:upgraded:app"]),
|
|
32983
33933
|
context: external_exports.object({ cloudId: external_exports.string().min(1) }).loose(),
|
|
@@ -33006,7 +33956,7 @@ var ForgePairingCodeResponseSchema = external_exports.discriminatedUnion("state"
|
|
|
33006
33956
|
expiresInSeconds: external_exports.number().int()
|
|
33007
33957
|
})
|
|
33008
33958
|
]);
|
|
33009
|
-
var forgeBitbucketContract =
|
|
33959
|
+
var forgeBitbucketContract = c44.router(
|
|
33010
33960
|
{
|
|
33011
33961
|
lifecycle: {
|
|
33012
33962
|
method: "POST",
|
|
@@ -33053,8 +34003,8 @@ var HealthResponseSchema = external_exports.object({
|
|
|
33053
34003
|
});
|
|
33054
34004
|
|
|
33055
34005
|
// ../../packages/api-contracts/src/contracts/health.ts
|
|
33056
|
-
var
|
|
33057
|
-
var healthContract =
|
|
34006
|
+
var c45 = initContract();
|
|
34007
|
+
var healthContract = c45.router({
|
|
33058
34008
|
getHealth: {
|
|
33059
34009
|
method: "GET",
|
|
33060
34010
|
path: "/health",
|
|
@@ -33066,8 +34016,8 @@ var healthContract = c46.router({
|
|
|
33066
34016
|
});
|
|
33067
34017
|
|
|
33068
34018
|
// ../../packages/api-contracts/src/contracts/v1/vulnerability-share.ts
|
|
33069
|
-
var
|
|
33070
|
-
var vulnerabilityShareContract =
|
|
34019
|
+
var c46 = initContract();
|
|
34020
|
+
var vulnerabilityShareContract = c46.router(
|
|
33071
34021
|
{
|
|
33072
34022
|
resolveShareLink: {
|
|
33073
34023
|
method: "GET",
|
|
@@ -33154,8 +34104,8 @@ var UpdatePrVulnerabilityRequestSchema = external_exports.object({
|
|
|
33154
34104
|
});
|
|
33155
34105
|
|
|
33156
34106
|
// ../../packages/api-contracts/src/contracts/v1/pr-vulnerability.ts
|
|
33157
|
-
var
|
|
33158
|
-
var prVulnerabilityContract =
|
|
34107
|
+
var c47 = initContract();
|
|
34108
|
+
var prVulnerabilityContract = c47.router(
|
|
33159
34109
|
{
|
|
33160
34110
|
listPrVulnerabilities: {
|
|
33161
34111
|
method: "GET",
|
|
@@ -35541,6 +36491,7 @@ var APPLICATION_TYPE_BY_INPUT = {
|
|
|
35541
36491
|
web: "WEB",
|
|
35542
36492
|
cli: "CLI",
|
|
35543
36493
|
mobile: "MOBILE",
|
|
36494
|
+
desktop: "DESKTOP",
|
|
35544
36495
|
"api-service": "API_SERVICE",
|
|
35545
36496
|
api_service: "API_SERVICE"
|
|
35546
36497
|
};
|
|
@@ -35707,12 +36658,12 @@ function buildApplicationsTable(apps) {
|
|
|
35707
36658
|
repos: String(a.repositories.length),
|
|
35708
36659
|
url: a.applicationUrl ? sanitizeDisplay(a.applicationUrl) : "\u2014"
|
|
35709
36660
|
}));
|
|
35710
|
-
const idWidth = Math.max(2, ...cells.map((
|
|
35711
|
-
const nameWidth = Math.max(4, ...cells.map((
|
|
35712
|
-
const typeWidth = Math.max(4, ...cells.map((
|
|
36661
|
+
const idWidth = Math.max(2, ...cells.map((c49) => c49.id.length));
|
|
36662
|
+
const nameWidth = Math.max(4, ...cells.map((c49) => c49.name.length));
|
|
36663
|
+
const typeWidth = Math.max(4, ...cells.map((c49) => c49.type.length));
|
|
35713
36664
|
const header = `${"ID".padEnd(idWidth)} ${"NAME".padEnd(nameWidth)} ${"TYPE".padEnd(typeWidth)} REPOS URL`;
|
|
35714
36665
|
const rows = cells.map(
|
|
35715
|
-
(
|
|
36666
|
+
(c49) => `${c49.id.padEnd(idWidth)} ${c49.name.padEnd(nameWidth)} ${c49.type.padEnd(typeWidth)} ${c49.repos.padStart(5)} ${c49.url}`
|
|
35716
36667
|
);
|
|
35717
36668
|
return { header, rows };
|
|
35718
36669
|
}
|
|
@@ -35732,12 +36683,12 @@ function buildApplicationRepositoriesTable(links) {
|
|
|
35732
36683
|
path: l.repositoryPath ? sanitizeDisplay(l.repositoryPath) : "\u2014",
|
|
35733
36684
|
status: formatStatus(l.repositoryStatus)
|
|
35734
36685
|
}));
|
|
35735
|
-
const nameWidth = Math.max(10, ...cells.map((
|
|
35736
|
-
const roleWidth = Math.max(4, ...cells.map((
|
|
35737
|
-
const pathWidth = Math.max(4, ...cells.map((
|
|
36686
|
+
const nameWidth = Math.max(10, ...cells.map((c49) => c49.name.length));
|
|
36687
|
+
const roleWidth = Math.max(4, ...cells.map((c49) => c49.role.length));
|
|
36688
|
+
const pathWidth = Math.max(4, ...cells.map((c49) => c49.path.length));
|
|
35738
36689
|
const header = `${"REPOSITORY".padEnd(nameWidth)} SCAN ${"ROLE".padEnd(roleWidth)} ${"PATH".padEnd(pathWidth)} STATUS`;
|
|
35739
36690
|
const rows = cells.map(
|
|
35740
|
-
(
|
|
36691
|
+
(c49) => `${c49.name.padEnd(nameWidth)} ${c49.scan.padEnd(4)} ${c49.role.padEnd(roleWidth)} ${c49.path.padEnd(pathWidth)} ${c49.status}`
|
|
35741
36692
|
);
|
|
35742
36693
|
return { header, rows };
|
|
35743
36694
|
}
|
|
@@ -35999,7 +36950,7 @@ async function runDelete(applicationId, options) {
|
|
|
35999
36950
|
console.log(colorSuccess(`Deleted application ${applicationId}`));
|
|
36000
36951
|
}
|
|
36001
36952
|
function createCreateCommand() {
|
|
36002
|
-
return new Command("create").description("Create a new application").argument("<name>", "Application name").option("--type <type>", "Application type: web, cli, mobile, api-service", "web").option("--url <url>", "Application URL (required for web/api-service)").option("--repo <id-or-url>", "Link a repository at creation (UUID, URL, or owner/repo)").option("--repo-path <path>", "Path within the linked repository").option("--help-center-url <url>", "Help center URL").option("--docs-url <url>", "Documentation URL").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
|
|
36953
|
+
return new Command("create").description("Create a new application").argument("<name>", "Application name").option("--type <type>", "Application type: web, cli, mobile, desktop, api-service", "web").option("--url <url>", "Application URL (required for web/api-service)").option("--repo <id-or-url>", "Link a repository at creation (UUID, URL, or owner/repo)").option("--repo-path <path>", "Path within the linked repository").option("--help-center-url <url>", "Help center URL").option("--docs-url <url>", "Documentation URL").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
|
|
36003
36954
|
"after",
|
|
36004
36955
|
`
|
|
36005
36956
|
Examples:
|
|
@@ -36418,6 +37369,21 @@ function d(r, t, s) {
|
|
|
36418
37369
|
const e2 = r + t, i = Math.max(s.length - 1, 0), n = e2 < 0 ? i : e2 > i ? 0 : e2;
|
|
36419
37370
|
return s[n].disabled ? d(n, t < 0 ? -1 : 1, s) : n;
|
|
36420
37371
|
}
|
|
37372
|
+
function I(r, t, s, e2) {
|
|
37373
|
+
const i = e2.split(`
|
|
37374
|
+
`);
|
|
37375
|
+
let n = 0, o = r;
|
|
37376
|
+
for (const a of i) {
|
|
37377
|
+
if (o <= a.length) break;
|
|
37378
|
+
o -= a.length + 1, n++;
|
|
37379
|
+
}
|
|
37380
|
+
for (n = Math.max(0, Math.min(i.length - 1, n + s)), o = Math.min(o, i[n].length) + t; o < 0 && n > 0; ) n--, o += i[n].length + 1;
|
|
37381
|
+
for (; o > i[n].length && n < i.length - 1; ) o -= i[n].length + 1, n++;
|
|
37382
|
+
o = Math.max(0, Math.min(i[n].length, o));
|
|
37383
|
+
let u = 0;
|
|
37384
|
+
for (let a = 0; a < n; a++) u += i[a].length + 1;
|
|
37385
|
+
return u + o;
|
|
37386
|
+
}
|
|
36421
37387
|
var G = ["up", "down", "left", "right", "space", "enter", "cancel"];
|
|
36422
37388
|
var K = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
36423
37389
|
var h = { actions: new Set(G), aliases: /* @__PURE__ */ new Map([["k", "up"], ["j", "down"], ["h", "left"], ["l", "right"], ["", "cancel"], ["escape", "cancel"]]), messages: { cancel: "Canceled", error: "Something went wrong" }, withGuide: true, date: { monthNames: [...K], messages: { required: "Please enter a valid date", invalidMonth: "There are only 12 months in a year", invalidDay: (r, t) => `There are only ${r} days in ${t}`, afterMin: (r) => `Date must be on or after ${r.toISOString().slice(0, 10)}`, beforeMax: (r) => `Date must be on or before ${r.toISOString().slice(0, 10)}` } } };
|
|
@@ -36579,6 +37545,145 @@ var p = class {
|
|
|
36579
37545
|
}
|
|
36580
37546
|
}
|
|
36581
37547
|
};
|
|
37548
|
+
var X = class extends p {
|
|
37549
|
+
get cursor() {
|
|
37550
|
+
return this.value ? 0 : 1;
|
|
37551
|
+
}
|
|
37552
|
+
get _value() {
|
|
37553
|
+
return this.cursor === 0;
|
|
37554
|
+
}
|
|
37555
|
+
constructor(t) {
|
|
37556
|
+
super(t, false), this.value = !!t.initialValue, this.on("userInput", () => {
|
|
37557
|
+
this.value = this._value;
|
|
37558
|
+
}), this.on("confirm", (s) => {
|
|
37559
|
+
this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = s, this.state = "submit", this.close();
|
|
37560
|
+
}), this.on("cursor", () => {
|
|
37561
|
+
this.value = !this.value;
|
|
37562
|
+
});
|
|
37563
|
+
}
|
|
37564
|
+
};
|
|
37565
|
+
var rt = class extends p {
|
|
37566
|
+
#s = false;
|
|
37567
|
+
#r;
|
|
37568
|
+
focused = "editor";
|
|
37569
|
+
get userInputWithCursor() {
|
|
37570
|
+
if (this.state === "submit") return this.userInput;
|
|
37571
|
+
const t = this.userInput;
|
|
37572
|
+
if (this.cursor >= t.length) return `${t}\u2588`;
|
|
37573
|
+
const s = t.slice(0, this.cursor), e2 = t[this.cursor], i = t.slice(this.cursor + 1);
|
|
37574
|
+
return e2 === `
|
|
37575
|
+
` ? `${s}\u2588
|
|
37576
|
+
${i}` : `${s}${v("inverse", e2)}${i}`;
|
|
37577
|
+
}
|
|
37578
|
+
get cursor() {
|
|
37579
|
+
return this._cursor;
|
|
37580
|
+
}
|
|
37581
|
+
#t(t) {
|
|
37582
|
+
if (this.userInput.length === 0) {
|
|
37583
|
+
this._setUserInput(t);
|
|
37584
|
+
return;
|
|
37585
|
+
}
|
|
37586
|
+
this._setUserInput(this.userInput.slice(0, this.cursor) + t + this.userInput.slice(this.cursor));
|
|
37587
|
+
}
|
|
37588
|
+
#n(t) {
|
|
37589
|
+
const s = this.value ?? "";
|
|
37590
|
+
switch (t) {
|
|
37591
|
+
case "up":
|
|
37592
|
+
this._cursor = I(this._cursor, 0, -1, s);
|
|
37593
|
+
return;
|
|
37594
|
+
case "down":
|
|
37595
|
+
this._cursor = I(this._cursor, 0, 1, s);
|
|
37596
|
+
return;
|
|
37597
|
+
case "left":
|
|
37598
|
+
this._cursor = I(this._cursor, -1, 0, s);
|
|
37599
|
+
return;
|
|
37600
|
+
case "right":
|
|
37601
|
+
this._cursor = I(this._cursor, 1, 0, s);
|
|
37602
|
+
return;
|
|
37603
|
+
}
|
|
37604
|
+
}
|
|
37605
|
+
_shouldSubmit(t, s) {
|
|
37606
|
+
if (this.#r) return this.focused === "submit" ? true : (this.#t(`
|
|
37607
|
+
`), this._cursor++, false);
|
|
37608
|
+
const e2 = this.#s;
|
|
37609
|
+
return this.#s = true, e2 ? (this.userInput[this.cursor - 1] === `
|
|
37610
|
+
` && (this._setUserInput(this.userInput.slice(0, this.cursor - 1) + this.userInput.slice(this.cursor)), this._cursor--), true) : (this.#t(`
|
|
37611
|
+
`), this._cursor++, false);
|
|
37612
|
+
}
|
|
37613
|
+
constructor(t) {
|
|
37614
|
+
super(t, false), this.#r = t.showSubmit ?? false, this.on("key", (s, e2) => {
|
|
37615
|
+
if (e2?.name && h.actions.has(e2.name)) {
|
|
37616
|
+
this.#n(e2.name);
|
|
37617
|
+
return;
|
|
37618
|
+
}
|
|
37619
|
+
if (s === " " && this.#r) {
|
|
37620
|
+
this.focused = this.focused === "editor" ? "submit" : "editor";
|
|
37621
|
+
return;
|
|
37622
|
+
}
|
|
37623
|
+
if (e2?.name !== "return") {
|
|
37624
|
+
if (this.#s = false, e2?.name === "backspace" && this.cursor > 0) {
|
|
37625
|
+
this._setUserInput(this.userInput.slice(0, this.cursor - 1) + this.userInput.slice(this.cursor)), this._cursor--;
|
|
37626
|
+
return;
|
|
37627
|
+
}
|
|
37628
|
+
if (e2?.name === "delete" && this.cursor < this.userInput.length) {
|
|
37629
|
+
this._setUserInput(this.userInput.slice(0, this.cursor) + this.userInput.slice(this.cursor + 1));
|
|
37630
|
+
return;
|
|
37631
|
+
}
|
|
37632
|
+
s && (this.#r && this.focused === "submit" && (this.focused = "editor"), this.#t(s ?? ""), this._cursor++);
|
|
37633
|
+
}
|
|
37634
|
+
}), this.on("userInput", (s) => {
|
|
37635
|
+
this._setValue(s);
|
|
37636
|
+
}), this.on("finalize", () => {
|
|
37637
|
+
this.value || (this.value = t.defaultValue), this.value === void 0 && (this.value = "");
|
|
37638
|
+
});
|
|
37639
|
+
}
|
|
37640
|
+
};
|
|
37641
|
+
var nt = class extends p {
|
|
37642
|
+
options;
|
|
37643
|
+
cursor = 0;
|
|
37644
|
+
get _value() {
|
|
37645
|
+
return this.options[this.cursor].value;
|
|
37646
|
+
}
|
|
37647
|
+
get _enabledOptions() {
|
|
37648
|
+
return this.options.filter((t) => t.disabled !== true);
|
|
37649
|
+
}
|
|
37650
|
+
toggleAll() {
|
|
37651
|
+
const t = this._enabledOptions, s = this.value !== void 0 && this.value.length === t.length;
|
|
37652
|
+
this.value = s ? [] : t.map((e2) => e2.value);
|
|
37653
|
+
}
|
|
37654
|
+
toggleInvert() {
|
|
37655
|
+
const t = this.value;
|
|
37656
|
+
if (!t) return;
|
|
37657
|
+
const s = this._enabledOptions.filter((e2) => !t.includes(e2.value));
|
|
37658
|
+
this.value = s.map((e2) => e2.value);
|
|
37659
|
+
}
|
|
37660
|
+
toggleValue() {
|
|
37661
|
+
this.value === void 0 && (this.value = []);
|
|
37662
|
+
const t = this.value.includes(this._value);
|
|
37663
|
+
this.value = t ? this.value.filter((s) => s !== this._value) : [...this.value, this._value];
|
|
37664
|
+
}
|
|
37665
|
+
constructor(t) {
|
|
37666
|
+
super(t, false), this.options = t.options, this.value = [...t.initialValues ?? []];
|
|
37667
|
+
const s = Math.max(this.options.findIndex(({ value: e2 }) => e2 === t.cursorAt), 0);
|
|
37668
|
+
this.cursor = this.options[s].disabled ? d(s, 1, this.options) : s, this.on("key", (e2) => {
|
|
37669
|
+
e2 === "a" && this.toggleAll(), e2 === "i" && this.toggleInvert();
|
|
37670
|
+
}), this.on("cursor", (e2) => {
|
|
37671
|
+
switch (e2) {
|
|
37672
|
+
case "left":
|
|
37673
|
+
case "up":
|
|
37674
|
+
this.cursor = d(this.cursor, -1, this.options);
|
|
37675
|
+
break;
|
|
37676
|
+
case "down":
|
|
37677
|
+
case "right":
|
|
37678
|
+
this.cursor = d(this.cursor, 1, this.options);
|
|
37679
|
+
break;
|
|
37680
|
+
case "space":
|
|
37681
|
+
this.toggleValue();
|
|
37682
|
+
break;
|
|
37683
|
+
}
|
|
37684
|
+
});
|
|
37685
|
+
}
|
|
37686
|
+
};
|
|
36582
37687
|
var ot = class extends p {
|
|
36583
37688
|
_mask = "\u2022";
|
|
36584
37689
|
get cursor() {
|
|
@@ -36695,14 +37800,14 @@ var yt = (t) => {
|
|
|
36695
37800
|
};
|
|
36696
37801
|
var ee = (t, r, s, i, u) => {
|
|
36697
37802
|
let n = r, o = 0;
|
|
36698
|
-
for (let
|
|
36699
|
-
const a = t[
|
|
37803
|
+
for (let c49 = s; c49 < i; c49++) {
|
|
37804
|
+
const a = t[c49];
|
|
36700
37805
|
if (n = n - a.length, o++, n <= u) break;
|
|
36701
37806
|
}
|
|
36702
37807
|
return { lineCount: n, removals: o };
|
|
36703
37808
|
};
|
|
36704
37809
|
var Y2 = ({ cursor: t, options: r, style: s, output: i = process.stdout, maxItems: u = Number.POSITIVE_INFINITY, columnPadding: n = 0, rowPadding: o = 4 }) => {
|
|
36705
|
-
const
|
|
37810
|
+
const c49 = A(i) - n, a = L(i), l = e("dim", "..."), d2 = Math.max(a - o, 0), y = Math.max(Math.min(u, d2), 5);
|
|
36706
37811
|
let p2 = 0;
|
|
36707
37812
|
t >= y - 3 && (p2 = Math.max(Math.min(t - y + 3, r.length - y), 0));
|
|
36708
37813
|
let m = y < r.length && p2 > 0, g = y < r.length && p2 + y < r.length;
|
|
@@ -36711,7 +37816,7 @@ var Y2 = ({ cursor: t, options: r, style: s, output: i = process.stdout, maxItem
|
|
|
36711
37816
|
m && f++, g && f++;
|
|
36712
37817
|
const v2 = p2 + (m ? 1 : 0), T = S2 - (g ? 1 : 0);
|
|
36713
37818
|
for (let b2 = v2; b2 < T; b2++) {
|
|
36714
|
-
const G2 = wrapAnsi(s(r[b2], b2 === t),
|
|
37819
|
+
const G2 = wrapAnsi(s(r[b2], b2 === t), c49, { hard: true, trim: false }).split(`
|
|
36715
37820
|
`);
|
|
36716
37821
|
h2.push(G2), f += G2.length;
|
|
36717
37822
|
}
|
|
@@ -36725,15 +37830,129 @@ var Y2 = ({ cursor: t, options: r, style: s, output: i = process.stdout, maxItem
|
|
|
36725
37830
|
for (const b2 of h2) for (const G2 of b2) C2.push(G2);
|
|
36726
37831
|
return g && C2.push(l), C2;
|
|
36727
37832
|
};
|
|
37833
|
+
var ue = (t) => {
|
|
37834
|
+
const r = t.active ?? "Yes", s = t.inactive ?? "No";
|
|
37835
|
+
return new X({ active: r, inactive: s, signal: t.signal, input: t.input, output: t.output, initialValue: t.initialValue ?? true, render() {
|
|
37836
|
+
const i = t.withGuide ?? h.withGuide, u = `${M(this.state)} `, n = i ? `${e("gray", $)} ` : "", o = W(t.output, t.message, n, u), c49 = `${i ? `${e("gray", $)}
|
|
37837
|
+
` : ""}${o}
|
|
37838
|
+
`, a = this.value ? r : s;
|
|
37839
|
+
switch (this.state) {
|
|
37840
|
+
case "submit": {
|
|
37841
|
+
const l = i ? `${e("gray", $)} ` : "";
|
|
37842
|
+
return `${c49}${l}${e("dim", a)}`;
|
|
37843
|
+
}
|
|
37844
|
+
case "cancel": {
|
|
37845
|
+
const l = i ? `${e("gray", $)} ` : "";
|
|
37846
|
+
return `${c49}${l}${e(["strikethrough", "dim"], a)}${i ? `
|
|
37847
|
+
${e("gray", $)}` : ""}`;
|
|
37848
|
+
}
|
|
37849
|
+
default: {
|
|
37850
|
+
const l = i ? `${e("cyan", $)} ` : "", d2 = i ? e("cyan", E2) : "";
|
|
37851
|
+
return `${c49}${l}${this.value ? `${e("green", z4)} ${r}` : `${e("dim", H)} ${e("dim", r)}`}${t.vertical ? i ? `
|
|
37852
|
+
${e("cyan", $)} ` : `
|
|
37853
|
+
` : ` ${e("dim", "/")} `}${this.value ? `${e("dim", H)} ${e("dim", s)}` : `${e("green", z4)} ${s}`}
|
|
37854
|
+
${d2}
|
|
37855
|
+
`;
|
|
37856
|
+
}
|
|
37857
|
+
}
|
|
37858
|
+
} }).prompt();
|
|
37859
|
+
};
|
|
37860
|
+
var me = (t = "", r) => {
|
|
37861
|
+
const s = r?.output ?? process.stdout, i = r?.withGuide ?? h.withGuide ? `${e("gray", E2)} ` : "";
|
|
37862
|
+
s.write(`${i}${e("red", t)}
|
|
37863
|
+
|
|
37864
|
+
`);
|
|
37865
|
+
};
|
|
37866
|
+
var fe = (t) => new rt({ validate: t.validate, placeholder: t.placeholder, defaultValue: t.defaultValue, initialValue: t.initialValue, showSubmit: t.showSubmit, output: t.output, signal: t.signal, input: t.input, render() {
|
|
37867
|
+
const r = t?.withGuide ?? h.withGuide, s = `${`${r ? `${e("gray", $)}
|
|
37868
|
+
` : ""}${M(this.state)} `}${t.message}
|
|
37869
|
+
`, i = t.placeholder ? e("inverse", t.placeholder[0]) + e("dim", t.placeholder.slice(1)) : e(["inverse", "hidden"], "_"), u = this.userInput ? this.userInputWithCursor : i, n = this.value ?? "", o = t.showSubmit ? `
|
|
37870
|
+
${e(this.focused === "submit" ? "cyan" : "dim", "[ submit ]")}` : "";
|
|
37871
|
+
switch (this.state) {
|
|
37872
|
+
case "error": {
|
|
37873
|
+
const c49 = `${e("yellow", $)} `, a = r ? W(t.output, u, c49, void 0) : u, l = e("yellow", E2);
|
|
37874
|
+
return `${s}${a}
|
|
37875
|
+
${l} ${e("yellow", this.error)}${o}
|
|
37876
|
+
`;
|
|
37877
|
+
}
|
|
37878
|
+
case "submit": {
|
|
37879
|
+
const c49 = `${e("gray", $)} `, a = r ? W(t.output, n, c49, void 0, (l) => e("dim", l)) : n ? e("dim", n) : "";
|
|
37880
|
+
return `${s}${a}`;
|
|
37881
|
+
}
|
|
37882
|
+
case "cancel": {
|
|
37883
|
+
const c49 = `${e("gray", $)} `, a = r ? W(t.output, n, c49, void 0, (l) => e(["strikethrough", "dim"], l)) : n ? e(["strikethrough", "dim"], n) : "";
|
|
37884
|
+
return `${s}${a}`;
|
|
37885
|
+
}
|
|
37886
|
+
default: {
|
|
37887
|
+
const c49 = r ? `${e("cyan", $)} ` : "", a = r ? e("cyan", E2) : "", l = r ? W(t.output, u, c49) : u;
|
|
37888
|
+
return `${s}${l}
|
|
37889
|
+
${a}${o}
|
|
37890
|
+
`;
|
|
37891
|
+
}
|
|
37892
|
+
}
|
|
37893
|
+
} }).prompt();
|
|
37894
|
+
var Q2 = (t, r) => t.split(`
|
|
37895
|
+
`).map((s) => r(s)).join(`
|
|
37896
|
+
`);
|
|
37897
|
+
var ve = (t) => {
|
|
37898
|
+
const r = (i, u) => {
|
|
37899
|
+
const n = i.label ?? String(i.value);
|
|
37900
|
+
return u === "disabled" ? `${e("gray", J)} ${Q2(n, (o) => e(["strikethrough", "gray"], o))}${i.hint ? ` ${e("dim", `(${i.hint ?? "disabled"})`)}` : ""}` : u === "active" ? `${e("cyan", et2)} ${n}${i.hint ? ` ${e("dim", `(${i.hint})`)}` : ""}` : u === "selected" ? `${e("green", U)} ${Q2(n, (o) => e("dim", o))}${i.hint ? ` ${e("dim", `(${i.hint})`)}` : ""}` : u === "cancelled" ? `${Q2(n, (o) => e(["strikethrough", "dim"], o))}` : u === "active-selected" ? `${e("green", U)} ${n}${i.hint ? ` ${e("dim", `(${i.hint})`)}` : ""}` : u === "submitted" ? `${Q2(n, (o) => e("dim", o))}` : `${e("dim", J)} ${Q2(n, (o) => e("dim", o))}`;
|
|
37901
|
+
}, s = t.required ?? true;
|
|
37902
|
+
return new nt({ options: t.options, signal: t.signal, input: t.input, output: t.output, initialValues: t.initialValues, required: s, cursorAt: t.cursorAt, validate(i) {
|
|
37903
|
+
if (s && (i === void 0 || i.length === 0)) return `Please select at least one option.
|
|
37904
|
+
${e("reset", e("dim", `Press ${e(["gray", "bgWhite", "inverse"], " space ")} to select, ${e("gray", e("bgWhite", e("inverse", " enter ")))} to submit`))}`;
|
|
37905
|
+
}, render() {
|
|
37906
|
+
const i = t.withGuide ?? h.withGuide, u = W(t.output, t.message, i ? `${yt(this.state)} ` : "", `${M(this.state)} `), n = `${i ? `${e("gray", $)}
|
|
37907
|
+
` : ""}${u}
|
|
37908
|
+
`, o = this.value ?? [], c49 = (a, l) => {
|
|
37909
|
+
if (a.disabled) return r(a, "disabled");
|
|
37910
|
+
const d2 = o.includes(a.value);
|
|
37911
|
+
return l && d2 ? r(a, "active-selected") : d2 ? r(a, "selected") : r(a, l ? "active" : "inactive");
|
|
37912
|
+
};
|
|
37913
|
+
switch (this.state) {
|
|
37914
|
+
case "submit": {
|
|
37915
|
+
const a = this.options.filter(({ value: d2 }) => o.includes(d2)).map((d2) => r(d2, "submitted")).join(e("dim", ", ")) || e("dim", "none"), l = W(t.output, a, i ? `${e("gray", $)} ` : "");
|
|
37916
|
+
return `${n}${l}`;
|
|
37917
|
+
}
|
|
37918
|
+
case "cancel": {
|
|
37919
|
+
const a = this.options.filter(({ value: d2 }) => o.includes(d2)).map((d2) => r(d2, "cancelled")).join(e("dim", ", "));
|
|
37920
|
+
if (a.trim() === "") return `${n}${e("gray", $)}`;
|
|
37921
|
+
const l = W(t.output, a, i ? `${e("gray", $)} ` : "");
|
|
37922
|
+
return `${n}${l}${i ? `
|
|
37923
|
+
${e("gray", $)}` : ""}`;
|
|
37924
|
+
}
|
|
37925
|
+
case "error": {
|
|
37926
|
+
const a = i ? `${e("yellow", $)} ` : "", l = this.error.split(`
|
|
37927
|
+
`).map((p2, m) => m === 0 ? `${i ? `${e("yellow", E2)} ` : ""}${e("yellow", p2)}` : ` ${p2}`).join(`
|
|
37928
|
+
`), d2 = n.split(`
|
|
37929
|
+
`).length, y = l.split(`
|
|
37930
|
+
`).length + 1;
|
|
37931
|
+
return `${n}${a}${Y2({ output: t.output, options: this.options, cursor: this.cursor, maxItems: t.maxItems, columnPadding: a.length, rowPadding: d2 + y, style: c49 }).join(`
|
|
37932
|
+
${a}`)}
|
|
37933
|
+
${l}
|
|
37934
|
+
`;
|
|
37935
|
+
}
|
|
37936
|
+
default: {
|
|
37937
|
+
const a = i ? `${e("cyan", $)} ` : "", l = n.split(`
|
|
37938
|
+
`).length, d2 = i ? 2 : 1;
|
|
37939
|
+
return `${n}${a}${Y2({ output: t.output, options: this.options, cursor: this.cursor, maxItems: t.maxItems, columnPadding: a.length, rowPadding: l + d2, style: c49 }).join(`
|
|
37940
|
+
${a}`)}
|
|
37941
|
+
${i ? e("cyan", E2) : ""}
|
|
37942
|
+
`;
|
|
37943
|
+
}
|
|
37944
|
+
}
|
|
37945
|
+
} }).prompt();
|
|
37946
|
+
};
|
|
36728
37947
|
var Ce = (t) => new ot({ validate: t.validate, mask: t.mask ?? Gt, signal: t.signal, input: t.input, output: t.output, render() {
|
|
36729
37948
|
const r = t.withGuide ?? h.withGuide, s = `${r ? `${e("gray", $)}
|
|
36730
37949
|
` : ""}${M(this.state)} ${t.message}
|
|
36731
37950
|
`, i = this.userInputWithCursor, u = this.masked;
|
|
36732
37951
|
switch (this.state) {
|
|
36733
37952
|
case "error": {
|
|
36734
|
-
const n = r ? `${e("yellow", $)} ` : "", o = r ? `${e("yellow", E2)} ` : "",
|
|
37953
|
+
const n = r ? `${e("yellow", $)} ` : "", o = r ? `${e("yellow", E2)} ` : "", c49 = u ?? "";
|
|
36735
37954
|
return t.clearOnError && this.clear(), `${s.trim()}
|
|
36736
|
-
${n}${
|
|
37955
|
+
${n}${c49}
|
|
36737
37956
|
${o}${e("yellow", this.error)}
|
|
36738
37957
|
`;
|
|
36739
37958
|
}
|
|
@@ -36781,19 +38000,19 @@ var Ee = (t) => {
|
|
|
36781
38000
|
`;
|
|
36782
38001
|
switch (this.state) {
|
|
36783
38002
|
case "submit": {
|
|
36784
|
-
const
|
|
38003
|
+
const c49 = s ? `${e("gray", $)} ` : "", a = W(t.output, r(this.options[this.cursor], "selected"), c49);
|
|
36785
38004
|
return `${o}${a}`;
|
|
36786
38005
|
}
|
|
36787
38006
|
case "cancel": {
|
|
36788
|
-
const
|
|
38007
|
+
const c49 = s ? `${e("gray", $)} ` : "", a = W(t.output, r(this.options[this.cursor], "cancelled"), c49);
|
|
36789
38008
|
return `${o}${a}${s ? `
|
|
36790
38009
|
${e("gray", $)}` : ""}`;
|
|
36791
38010
|
}
|
|
36792
38011
|
default: {
|
|
36793
|
-
const
|
|
38012
|
+
const c49 = s ? `${e("cyan", $)} ` : "", a = s ? e("cyan", E2) : "", l = o.split(`
|
|
36794
38013
|
`).length, d2 = s ? 2 : 1;
|
|
36795
|
-
return `${o}${
|
|
36796
|
-
${
|
|
38014
|
+
return `${o}${c49}${Y2({ output: t.output, cursor: this.cursor, options: this.options, maxItems: t.maxItems, columnPadding: c49.length, rowPadding: l + d2, style: (y, p2) => r(y, y.disabled ? "disabled" : p2 ? "active" : "inactive") }).join(`
|
|
38015
|
+
${c49}`)}
|
|
36797
38016
|
${a}
|
|
36798
38017
|
`;
|
|
36799
38018
|
}
|
|
@@ -37551,7 +38770,7 @@ function extractCommandTree(cmd) {
|
|
|
37551
38770
|
description: o.description,
|
|
37552
38771
|
takesValue: o.required || o.optional
|
|
37553
38772
|
}));
|
|
37554
|
-
const subcommands = cmd.commands.filter((
|
|
38773
|
+
const subcommands = cmd.commands.filter((c49) => !c49._hidden).map((c49) => extractCommandTree(c49));
|
|
37555
38774
|
return {
|
|
37556
38775
|
name: cmd.name(),
|
|
37557
38776
|
description: cmd.description(),
|
|
@@ -37617,7 +38836,7 @@ function generateBashCompletion(tree, binName) {
|
|
|
37617
38836
|
}
|
|
37618
38837
|
function collectBashCases(tree, prefix) {
|
|
37619
38838
|
const cases = /* @__PURE__ */ new Map();
|
|
37620
|
-
const subcommandNames = tree.subcommands.map((
|
|
38839
|
+
const subcommandNames = tree.subcommands.map((c49) => c49.name);
|
|
37621
38840
|
const optionNames = tree.options.flatMap((o) => o.short ? [o.long, o.short] : [o.long]);
|
|
37622
38841
|
const extraOptions = prefix === "" ? ["--help", "--version"] : ["--help"];
|
|
37623
38842
|
const allOptions = [.../* @__PURE__ */ new Set([...optionNames, ...extraOptions])];
|
|
@@ -38300,16 +39519,16 @@ function printCredentialsTsv(creds) {
|
|
|
38300
39519
|
}
|
|
38301
39520
|
}
|
|
38302
39521
|
function buildCredentialsTable(creds) {
|
|
38303
|
-
const cells = creds.map((
|
|
38304
|
-
id:
|
|
38305
|
-
label: sanitizeDisplay(
|
|
38306
|
-
type:
|
|
39522
|
+
const cells = creds.map((c49) => ({
|
|
39523
|
+
id: c49.credentialId,
|
|
39524
|
+
label: sanitizeDisplay(c49.label),
|
|
39525
|
+
type: c49.credentialType
|
|
38307
39526
|
}));
|
|
38308
|
-
const idWidth = Math.max(2, ...cells.map((
|
|
38309
|
-
const labelWidth = Math.max(5, ...cells.map((
|
|
39527
|
+
const idWidth = Math.max(2, ...cells.map((c49) => c49.id.length));
|
|
39528
|
+
const labelWidth = Math.max(5, ...cells.map((c49) => c49.label.length));
|
|
38310
39529
|
const header = `${"ID".padEnd(idWidth)} ${"LABEL".padEnd(labelWidth)} TYPE`;
|
|
38311
39530
|
const rows = cells.map(
|
|
38312
|
-
(
|
|
39531
|
+
(c49) => `${c49.id.padEnd(idWidth)} ${c49.label.padEnd(labelWidth)} ${c49.type}`
|
|
38313
39532
|
);
|
|
38314
39533
|
return { header, rows };
|
|
38315
39534
|
}
|
|
@@ -38365,7 +39584,7 @@ async function runCreate2(options) {
|
|
|
38365
39584
|
}
|
|
38366
39585
|
const organizationId = await resolveOrganizationId();
|
|
38367
39586
|
const params = { organizationId, environmentId: options.env };
|
|
38368
|
-
const label = options.label;
|
|
39587
|
+
const label = options.label?.trim() ? options.label.trim() : void 0;
|
|
38369
39588
|
let body;
|
|
38370
39589
|
try {
|
|
38371
39590
|
body = await buildCreateBody(type, label, options);
|
|
@@ -38388,6 +39607,7 @@ async function runCreate2(options) {
|
|
|
38388
39607
|
outputCredential(result.body, output);
|
|
38389
39608
|
}
|
|
38390
39609
|
async function buildCreateBody(type, label, options) {
|
|
39610
|
+
const labelFields = label !== void 0 ? { label } : {};
|
|
38391
39611
|
switch (type) {
|
|
38392
39612
|
case "BEARER_TOKEN": {
|
|
38393
39613
|
const ac = buildBearerAuthConfig(options);
|
|
@@ -38395,7 +39615,7 @@ async function buildCreateBody(type, label, options) {
|
|
|
38395
39615
|
const secretValue = await resolveSecret("secret value", "secret", secretOpts(options));
|
|
38396
39616
|
return {
|
|
38397
39617
|
credentialType: "BEARER_TOKEN",
|
|
38398
|
-
|
|
39618
|
+
...labelFields,
|
|
38399
39619
|
secretValue,
|
|
38400
39620
|
...ac.value ? { authConfig: ac.value } : {}
|
|
38401
39621
|
};
|
|
@@ -38406,7 +39626,7 @@ async function buildCreateBody(type, label, options) {
|
|
|
38406
39626
|
const secretValue = await resolveSecret("secret value", "secret", secretOpts(options));
|
|
38407
39627
|
return {
|
|
38408
39628
|
credentialType: "JWT_TOKEN",
|
|
38409
|
-
|
|
39629
|
+
...labelFields,
|
|
38410
39630
|
secretValue,
|
|
38411
39631
|
...ac.value ? { authConfig: ac.value } : {}
|
|
38412
39632
|
};
|
|
@@ -38417,14 +39637,14 @@ async function buildCreateBody(type, label, options) {
|
|
|
38417
39637
|
const secretValue = await resolveSecret("secret value", "secret", secretOpts(options));
|
|
38418
39638
|
return {
|
|
38419
39639
|
credentialType: "API_KEY",
|
|
38420
|
-
|
|
39640
|
+
...labelFields,
|
|
38421
39641
|
secretValue,
|
|
38422
39642
|
...ac.value ? { authConfig: ac.value } : {}
|
|
38423
39643
|
};
|
|
38424
39644
|
}
|
|
38425
39645
|
case "PASSPHRASE": {
|
|
38426
39646
|
const secretValue = await resolveSecret("secret value", "secret", secretOpts(options));
|
|
38427
|
-
return { credentialType: "PASSPHRASE",
|
|
39647
|
+
return { credentialType: "PASSPHRASE", ...labelFields, secretValue };
|
|
38428
39648
|
}
|
|
38429
39649
|
case "SESSION_STATE": {
|
|
38430
39650
|
const secretValue = await resolveSecret(
|
|
@@ -38432,7 +39652,7 @@ async function buildCreateBody(type, label, options) {
|
|
|
38432
39652
|
"secret",
|
|
38433
39653
|
secretOpts(options)
|
|
38434
39654
|
);
|
|
38435
|
-
return { credentialType: "SESSION_STATE",
|
|
39655
|
+
return { credentialType: "SESSION_STATE", ...labelFields, secretValue };
|
|
38436
39656
|
}
|
|
38437
39657
|
case "COOKIE": {
|
|
38438
39658
|
const ac = buildCookieAuthConfig(options);
|
|
@@ -38440,7 +39660,7 @@ async function buildCreateBody(type, label, options) {
|
|
|
38440
39660
|
const secretValue = await resolveSecret("secret value", "secret", secretOpts(options));
|
|
38441
39661
|
return {
|
|
38442
39662
|
credentialType: "COOKIE",
|
|
38443
|
-
|
|
39663
|
+
...labelFields,
|
|
38444
39664
|
secretValue,
|
|
38445
39665
|
...ac.value ? { authConfig: ac.value } : {}
|
|
38446
39666
|
};
|
|
@@ -38451,7 +39671,7 @@ async function buildCreateBody(type, label, options) {
|
|
|
38451
39671
|
const secretValue = await resolveSecret("test-account email", "secret", secretOpts(options));
|
|
38452
39672
|
return {
|
|
38453
39673
|
credentialType: "MAGIC_AUTH",
|
|
38454
|
-
|
|
39674
|
+
...labelFields,
|
|
38455
39675
|
secretValue,
|
|
38456
39676
|
...ac.value ? { authConfig: ac.value } : {}
|
|
38457
39677
|
};
|
|
@@ -38463,7 +39683,7 @@ async function buildCreateBody(type, label, options) {
|
|
|
38463
39683
|
const password = await resolveSecret("password", "password", passwordOpts(options));
|
|
38464
39684
|
return {
|
|
38465
39685
|
credentialType: "USERNAME_PASSWORD",
|
|
38466
|
-
|
|
39686
|
+
...labelFields,
|
|
38467
39687
|
username,
|
|
38468
39688
|
password,
|
|
38469
39689
|
...ac.value ? { authConfig: ac.value } : {}
|
|
@@ -38616,17 +39836,21 @@ function createCreateCommand2() {
|
|
|
38616
39836
|
const command = new Command("create").description("Create a credential in an environment").requiredOption("--env <environmentId>", "Parent environment UUID").requiredOption(
|
|
38617
39837
|
"--type <type>",
|
|
38618
39838
|
"bearer-token, jwt-token, api-key, passphrase, username-password, cookie, magic-auth"
|
|
38619
|
-
).
|
|
39839
|
+
).option(
|
|
39840
|
+
"--label <label>",
|
|
39841
|
+
"Human-readable label (optional; defaults from type / username + environment)"
|
|
39842
|
+
).option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table");
|
|
38620
39843
|
addSecretInputOptions(command);
|
|
38621
39844
|
addAuthConfigOptions(command).addHelpText(
|
|
38622
39845
|
"after",
|
|
38623
39846
|
`
|
|
38624
39847
|
Secrets are read from stdin/file/env (or a no-echo prompt) \u2014 never an inline flag.
|
|
39848
|
+
--label is optional; when omitted the API picks a unique default.
|
|
38625
39849
|
|
|
38626
39850
|
Examples:
|
|
38627
|
-
vault read -field=token secret/x | tracecli credential create --env <envId> --type bearer-token --
|
|
39851
|
+
vault read -field=token secret/x | tracecli credential create --env <envId> --type bearer-token --secret-stdin
|
|
38628
39852
|
tracecli credential create --env <envId> --type api-key --label "prod key" --secret-env API_KEY --placement header --key-name X-API-Key
|
|
38629
|
-
tracecli credential create --env <envId> --type username-password --
|
|
39853
|
+
tracecli credential create --env <envId> --type username-password --username-env U --password-env P --method form --login-url https://acme.com/login`
|
|
38630
39854
|
);
|
|
38631
39855
|
return command.action(async (options) => {
|
|
38632
39856
|
await runCreate2(options);
|
|
@@ -38856,14 +40080,14 @@ function buildEnvironmentTable(envs, leading) {
|
|
|
38856
40080
|
url: sanitizeDisplay(e2.primaryUrl)
|
|
38857
40081
|
}));
|
|
38858
40082
|
const leadingWidths = leading.map(
|
|
38859
|
-
(column, i) => Math.max(column.header.length, ...cells.map((
|
|
40083
|
+
(column, i) => Math.max(column.header.length, ...cells.map((c49) => c49.leading[i]?.length ?? 0))
|
|
38860
40084
|
);
|
|
38861
|
-
const nameWidth = Math.max(4, ...cells.map((
|
|
40085
|
+
const nameWidth = Math.max(4, ...cells.map((c49) => c49.name.length));
|
|
38862
40086
|
const padLeading = (values) => values.map((v2, i) => v2.padEnd(leadingWidths[i] ?? 0)).join(" ");
|
|
38863
40087
|
return {
|
|
38864
|
-
header: `${padLeading(leading.map((
|
|
40088
|
+
header: `${padLeading(leading.map((c49) => c49.header))} ${"NAME".padEnd(nameWidth)} PROD URL`,
|
|
38865
40089
|
rows: cells.map(
|
|
38866
|
-
(
|
|
40090
|
+
(c49) => `${padLeading(c49.leading)} ${c49.name.padEnd(nameWidth)} ${c49.prod.padEnd(4)} ${c49.url}`
|
|
38867
40091
|
)
|
|
38868
40092
|
};
|
|
38869
40093
|
}
|
|
@@ -39225,6 +40449,120 @@ var packageMetadata = readPackageMetadata();
|
|
|
39225
40449
|
var CLI_PACKAGE_NAME = packageMetadata.name;
|
|
39226
40450
|
var CLI_VERSION = packageMetadata.version;
|
|
39227
40451
|
|
|
40452
|
+
// src/pentest/commands.ts
|
|
40453
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
40454
|
+
|
|
40455
|
+
// src/pentest/questionnaire.ts
|
|
40456
|
+
function buildUpsertQuestionnaireBody(answers) {
|
|
40457
|
+
if (answers === null) {
|
|
40458
|
+
return { answers: null };
|
|
40459
|
+
}
|
|
40460
|
+
return { answers: normalizePentestCustomerIntakeAnswers(answers) };
|
|
40461
|
+
}
|
|
40462
|
+
function parseQuestionnaireAnswersFile(raw, sourceLabel = "file") {
|
|
40463
|
+
let parsed;
|
|
40464
|
+
try {
|
|
40465
|
+
parsed = JSON.parse(raw);
|
|
40466
|
+
} catch {
|
|
40467
|
+
return { error: `Invalid JSON in ${sourceLabel}.` };
|
|
40468
|
+
}
|
|
40469
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
40470
|
+
return {
|
|
40471
|
+
error: `${sourceLabel} must be a JSON object of questionnaire answers (not an array or null).`
|
|
40472
|
+
};
|
|
40473
|
+
}
|
|
40474
|
+
if ("answers" in parsed && Object.keys(parsed).length === 1) {
|
|
40475
|
+
return {
|
|
40476
|
+
error: `${sourceLabel} must contain the answers object directly, not an { answers } wrapper. The CLI wraps it for the API.`
|
|
40477
|
+
};
|
|
40478
|
+
}
|
|
40479
|
+
const result = PentestCustomerIntakeAnswersSchema.safeParse(parsed);
|
|
40480
|
+
if (!result.success) {
|
|
40481
|
+
const issue2 = result.error.issues[0];
|
|
40482
|
+
const path = issue2?.path.length ? issue2.path.join(".") : "answers";
|
|
40483
|
+
const message = issue2?.message ?? "invalid";
|
|
40484
|
+
return { error: `Invalid questionnaire answers in ${sourceLabel}: ${path} \u2014 ${message}` };
|
|
40485
|
+
}
|
|
40486
|
+
return { answers: normalizePentestCustomerIntakeAnswers(result.data) };
|
|
40487
|
+
}
|
|
40488
|
+
function applyTextIntakeAnswer(current, key, input) {
|
|
40489
|
+
const trimmed = input.trim();
|
|
40490
|
+
if (trimmed.length === 0) {
|
|
40491
|
+
return current;
|
|
40492
|
+
}
|
|
40493
|
+
return { ...current, [key]: trimmed };
|
|
40494
|
+
}
|
|
40495
|
+
function applyMultiSelectIntakeAnswer(current, key, selected) {
|
|
40496
|
+
if (selected.length === 0) {
|
|
40497
|
+
return current;
|
|
40498
|
+
}
|
|
40499
|
+
return {
|
|
40500
|
+
...current,
|
|
40501
|
+
[key]: Array.from(new Set(selected)).sort()
|
|
40502
|
+
};
|
|
40503
|
+
}
|
|
40504
|
+
function formatIssueClasses(values) {
|
|
40505
|
+
return values.map((v2) => INTAKE_ISSUE_CLASS_LABELS[v2]).join(", ");
|
|
40506
|
+
}
|
|
40507
|
+
function formatSurfaces(values) {
|
|
40508
|
+
return values.map((v2) => INTAKE_SURFACE_LABELS[v2]).join(", ");
|
|
40509
|
+
}
|
|
40510
|
+
function formatAnswerValue(key, answers) {
|
|
40511
|
+
switch (key) {
|
|
40512
|
+
case "issueClasses": {
|
|
40513
|
+
const values = answers.issueClasses;
|
|
40514
|
+
if (values === void 0 || values.length === 0) {
|
|
40515
|
+
return null;
|
|
40516
|
+
}
|
|
40517
|
+
return formatIssueClasses(values);
|
|
40518
|
+
}
|
|
40519
|
+
case "surfaces": {
|
|
40520
|
+
const values = answers.surfaces;
|
|
40521
|
+
if (values === void 0 || values.length === 0) {
|
|
40522
|
+
return null;
|
|
40523
|
+
}
|
|
40524
|
+
return formatSurfaces(values);
|
|
40525
|
+
}
|
|
40526
|
+
default: {
|
|
40527
|
+
const value = answers[key];
|
|
40528
|
+
if (value === void 0 || value.trim().length === 0) {
|
|
40529
|
+
return null;
|
|
40530
|
+
}
|
|
40531
|
+
return value;
|
|
40532
|
+
}
|
|
40533
|
+
}
|
|
40534
|
+
}
|
|
40535
|
+
function formatQuestionnaireShow(input) {
|
|
40536
|
+
const lines = [
|
|
40537
|
+
`Editable: ${input.editable ? "yes (scoping window open)" : "no (editing closed after scoping)"}`
|
|
40538
|
+
];
|
|
40539
|
+
if (input.answers === null || Object.keys(input.answers).length === 0) {
|
|
40540
|
+
lines.push("Answers: (none)");
|
|
40541
|
+
return lines.join("\n");
|
|
40542
|
+
}
|
|
40543
|
+
lines.push("Answers:");
|
|
40544
|
+
for (const key of PENTEST_CUSTOMER_INTAKE_ANSWER_KEYS) {
|
|
40545
|
+
const value = formatAnswerValue(key, input.answers);
|
|
40546
|
+
if (value === null) {
|
|
40547
|
+
continue;
|
|
40548
|
+
}
|
|
40549
|
+
lines.push(`${PENTEST_CUSTOMER_INTAKE_LABELS[key]}: ${value}`);
|
|
40550
|
+
}
|
|
40551
|
+
return lines.join("\n");
|
|
40552
|
+
}
|
|
40553
|
+
function issueClassSelectOptions() {
|
|
40554
|
+
return CustomerPriorityCategoryValues.map((value) => ({
|
|
40555
|
+
value,
|
|
40556
|
+
label: INTAKE_ISSUE_CLASS_LABELS[value]
|
|
40557
|
+
}));
|
|
40558
|
+
}
|
|
40559
|
+
function surfaceSelectOptions() {
|
|
40560
|
+
return IntakeSurfaceValues.map((value) => ({
|
|
40561
|
+
value,
|
|
40562
|
+
label: INTAKE_SURFACE_LABELS[value]
|
|
40563
|
+
}));
|
|
40564
|
+
}
|
|
40565
|
+
|
|
39228
40566
|
// src/pentest/commands.ts
|
|
39229
40567
|
var DEFAULT_LIMIT2 = 30;
|
|
39230
40568
|
var MAX_LIMIT2 = 100;
|
|
@@ -39474,13 +40812,9 @@ Examples:
|
|
|
39474
40812
|
console.error(`Failed to list findings (status ${result.status}).`);
|
|
39475
40813
|
process.exit(1);
|
|
39476
40814
|
}
|
|
39477
|
-
|
|
39478
|
-
|
|
39479
|
-
|
|
39480
|
-
}
|
|
39481
|
-
if (options.status) {
|
|
39482
|
-
filteredFindings = filteredFindings.filter((f) => f.status === options.status);
|
|
39483
|
-
}
|
|
40815
|
+
const filteredFindings = result.body.filter(
|
|
40816
|
+
(f) => (!options.severity || f.severity === options.severity) && (!options.status || f.status === options.status)
|
|
40817
|
+
);
|
|
39484
40818
|
filteredFindings.sort(
|
|
39485
40819
|
(a, b2) => (SEVERITY_ORDER[a.severity] ?? 99) - (SEVERITY_ORDER[b2.severity] ?? 99)
|
|
39486
40820
|
);
|
|
@@ -39764,16 +41098,248 @@ Examples:
|
|
|
39764
41098
|
await runUpdate4(pentestId, options);
|
|
39765
41099
|
});
|
|
39766
41100
|
}
|
|
41101
|
+
function failQuestionnaire(status, body, action, notFoundLabel) {
|
|
41102
|
+
const { message } = readErrorFields(body);
|
|
41103
|
+
if (status === UNAUTHORIZED_STATUS2) {
|
|
41104
|
+
exitAuthFailed();
|
|
41105
|
+
}
|
|
41106
|
+
if (status === 403) {
|
|
41107
|
+
if (action === "write") {
|
|
41108
|
+
console.error(
|
|
41109
|
+
colorError(
|
|
41110
|
+
"Questionnaire writes require an organization admin (or Trace staff) signed in with a browser session. API keys are rejected."
|
|
41111
|
+
)
|
|
41112
|
+
);
|
|
41113
|
+
} else {
|
|
41114
|
+
console.error(
|
|
41115
|
+
colorError(message ?? "You do not have permission to view this questionnaire.")
|
|
41116
|
+
);
|
|
41117
|
+
}
|
|
41118
|
+
process.exit(1);
|
|
41119
|
+
}
|
|
41120
|
+
if (status === 404) {
|
|
41121
|
+
console.error(
|
|
41122
|
+
colorError(notFoundLabel ? `Pentest not found: ${notFoundLabel}.` : message ?? "Not found.")
|
|
41123
|
+
);
|
|
41124
|
+
process.exit(1);
|
|
41125
|
+
}
|
|
41126
|
+
if (status === 400) {
|
|
41127
|
+
console.error(colorError(message ?? "Invalid questionnaire answers (status 400)."));
|
|
41128
|
+
process.exit(1);
|
|
41129
|
+
}
|
|
41130
|
+
if (status === 409) {
|
|
41131
|
+
console.error(
|
|
41132
|
+
colorError(
|
|
41133
|
+
message ?? "Questionnaire editing is closed after scoping starts (current stage is past DRAFT / READY_TO_START)."
|
|
41134
|
+
)
|
|
41135
|
+
);
|
|
41136
|
+
process.exit(1);
|
|
41137
|
+
}
|
|
41138
|
+
console.error(
|
|
41139
|
+
colorError(
|
|
41140
|
+
`Failed to ${action === "write" ? "save" : "load"} questionnaire (status ${status})${message ? `: ${message}` : "."}`
|
|
41141
|
+
)
|
|
41142
|
+
);
|
|
41143
|
+
process.exit(1);
|
|
41144
|
+
}
|
|
41145
|
+
async function fetchQuestionnaire(organizationId, pentestId, notFoundLabel) {
|
|
41146
|
+
const result = await authenticatedRequest(
|
|
41147
|
+
(client) => client.pentest.getCustomerPentestQuestionnaire({
|
|
41148
|
+
params: { organizationId, pentestId }
|
|
41149
|
+
})
|
|
41150
|
+
);
|
|
41151
|
+
if (result.status !== SUCCESS_STATUS) {
|
|
41152
|
+
failQuestionnaire(result.status, result.body, "read", notFoundLabel);
|
|
41153
|
+
}
|
|
41154
|
+
return result.body;
|
|
41155
|
+
}
|
|
41156
|
+
async function putQuestionnaire(organizationId, pentestId, answers, notFoundLabel) {
|
|
41157
|
+
const body = buildUpsertQuestionnaireBody(answers);
|
|
41158
|
+
const result = await authenticatedRequest(
|
|
41159
|
+
(client) => client.pentest.upsertCustomerPentestQuestionnaire({
|
|
41160
|
+
params: { organizationId, pentestId },
|
|
41161
|
+
body
|
|
41162
|
+
})
|
|
41163
|
+
);
|
|
41164
|
+
if (result.status !== SUCCESS_STATUS) {
|
|
41165
|
+
failQuestionnaire(result.status, result.body, "write", notFoundLabel);
|
|
41166
|
+
}
|
|
41167
|
+
return result.body;
|
|
41168
|
+
}
|
|
41169
|
+
function exitCancelled() {
|
|
41170
|
+
me("Cancelled.");
|
|
41171
|
+
process.exit(1);
|
|
41172
|
+
}
|
|
41173
|
+
async function promptQuestionnaireAnswers(existing) {
|
|
41174
|
+
let working = { ...existing ?? {} };
|
|
41175
|
+
const textPrompt = async (key, question) => {
|
|
41176
|
+
const previous = existing?.[key];
|
|
41177
|
+
const value = await fe({
|
|
41178
|
+
message: `${question} (empty keeps previous)`,
|
|
41179
|
+
initialValue: previous ?? "",
|
|
41180
|
+
...previous ? {} : { placeholder: "Optional, press Enter to skip" }
|
|
41181
|
+
});
|
|
41182
|
+
if (q(value)) {
|
|
41183
|
+
exitCancelled();
|
|
41184
|
+
}
|
|
41185
|
+
working = applyTextIntakeAnswer(working, key, value);
|
|
41186
|
+
};
|
|
41187
|
+
for (const entry of PENTEST_CUSTOMER_INTAKE_QUESTIONS) {
|
|
41188
|
+
if (entry.kind === "text") {
|
|
41189
|
+
await textPrompt(entry.key, entry.question);
|
|
41190
|
+
continue;
|
|
41191
|
+
}
|
|
41192
|
+
const message = `${entry.question} (empty keeps previous)`;
|
|
41193
|
+
if (entry.key === "issueClasses") {
|
|
41194
|
+
const selected = await ve({
|
|
41195
|
+
message,
|
|
41196
|
+
options: issueClassSelectOptions(),
|
|
41197
|
+
required: false,
|
|
41198
|
+
...existing?.issueClasses !== void 0 ? { initialValues: existing.issueClasses } : {}
|
|
41199
|
+
});
|
|
41200
|
+
if (q(selected)) {
|
|
41201
|
+
exitCancelled();
|
|
41202
|
+
}
|
|
41203
|
+
working = applyMultiSelectIntakeAnswer(working, "issueClasses", selected);
|
|
41204
|
+
} else {
|
|
41205
|
+
const selected = await ve({
|
|
41206
|
+
message,
|
|
41207
|
+
options: surfaceSelectOptions(),
|
|
41208
|
+
required: false,
|
|
41209
|
+
...existing?.surfaces !== void 0 ? { initialValues: existing.surfaces } : {}
|
|
41210
|
+
});
|
|
41211
|
+
if (q(selected)) {
|
|
41212
|
+
exitCancelled();
|
|
41213
|
+
}
|
|
41214
|
+
working = applyMultiSelectIntakeAnswer(working, "surfaces", selected);
|
|
41215
|
+
}
|
|
41216
|
+
await textPrompt(entry.notesKey, entry.notesQuestion);
|
|
41217
|
+
}
|
|
41218
|
+
const confirmed = await ue({
|
|
41219
|
+
message: "Save questionnaire answers?",
|
|
41220
|
+
initialValue: true
|
|
41221
|
+
});
|
|
41222
|
+
if (q(confirmed) || !confirmed) {
|
|
41223
|
+
exitCancelled();
|
|
41224
|
+
}
|
|
41225
|
+
if (Object.keys(working).length === 0) {
|
|
41226
|
+
return existing === null ? null : working;
|
|
41227
|
+
}
|
|
41228
|
+
return working;
|
|
41229
|
+
}
|
|
41230
|
+
async function runQuestionnaire(pentestIdentifier, options) {
|
|
41231
|
+
const show = options.show === true;
|
|
41232
|
+
const filePath = options.file;
|
|
41233
|
+
if (show && filePath !== void 0) {
|
|
41234
|
+
console.error(colorError("Pass only one of --show / --file."));
|
|
41235
|
+
process.exit(1);
|
|
41236
|
+
}
|
|
41237
|
+
const isInteractiveTty = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
41238
|
+
if (!show && filePath === void 0 && !isInteractiveTty) {
|
|
41239
|
+
console.error(
|
|
41240
|
+
colorError(
|
|
41241
|
+
"Interactive questionnaire requires a TTY. Use --show to print answers, or --file <path> to upload an answers JSON object."
|
|
41242
|
+
)
|
|
41243
|
+
);
|
|
41244
|
+
process.exit(2);
|
|
41245
|
+
}
|
|
41246
|
+
const organizationId = await resolveOrganizationId();
|
|
41247
|
+
const pentestId = await resolvePentestId(organizationId, pentestIdentifier);
|
|
41248
|
+
if (show) {
|
|
41249
|
+
const current2 = await fetchQuestionnaire(organizationId, pentestId, pentestIdentifier);
|
|
41250
|
+
console.log(
|
|
41251
|
+
formatQuestionnaireShow({
|
|
41252
|
+
answers: current2.answers,
|
|
41253
|
+
editable: current2.editable
|
|
41254
|
+
})
|
|
41255
|
+
);
|
|
41256
|
+
return;
|
|
41257
|
+
}
|
|
41258
|
+
if (filePath !== void 0) {
|
|
41259
|
+
let raw;
|
|
41260
|
+
try {
|
|
41261
|
+
raw = readFileSync4(filePath, "utf8");
|
|
41262
|
+
} catch {
|
|
41263
|
+
console.error(colorError(`Could not read answers file: ${filePath}`));
|
|
41264
|
+
process.exit(1);
|
|
41265
|
+
}
|
|
41266
|
+
const parsed = parseQuestionnaireAnswersFile(raw, filePath);
|
|
41267
|
+
if ("error" in parsed) {
|
|
41268
|
+
console.error(colorError(parsed.error));
|
|
41269
|
+
process.exit(1);
|
|
41270
|
+
}
|
|
41271
|
+
const saved2 = await putQuestionnaire(
|
|
41272
|
+
organizationId,
|
|
41273
|
+
pentestId,
|
|
41274
|
+
parsed.answers,
|
|
41275
|
+
pentestIdentifier
|
|
41276
|
+
);
|
|
41277
|
+
console.log(colorSuccess("Saved questionnaire answers."));
|
|
41278
|
+
console.log(
|
|
41279
|
+
formatQuestionnaireShow({
|
|
41280
|
+
answers: saved2.answers,
|
|
41281
|
+
editable: saved2.editable
|
|
41282
|
+
})
|
|
41283
|
+
);
|
|
41284
|
+
return;
|
|
41285
|
+
}
|
|
41286
|
+
const current = await fetchQuestionnaire(organizationId, pentestId, pentestIdentifier);
|
|
41287
|
+
if (!current.editable) {
|
|
41288
|
+
console.error(
|
|
41289
|
+
colorError(
|
|
41290
|
+
"Questionnaire editing is closed after scoping starts. Use --show to view the saved answers."
|
|
41291
|
+
)
|
|
41292
|
+
);
|
|
41293
|
+
process.exit(1);
|
|
41294
|
+
}
|
|
41295
|
+
const merged = await promptQuestionnaireAnswers(current.answers);
|
|
41296
|
+
const saved = await putQuestionnaire(organizationId, pentestId, merged, pentestIdentifier);
|
|
41297
|
+
console.log(colorSuccess("Saved questionnaire answers."));
|
|
41298
|
+
console.log(
|
|
41299
|
+
formatQuestionnaireShow({
|
|
41300
|
+
answers: saved.answers,
|
|
41301
|
+
editable: saved.editable
|
|
41302
|
+
})
|
|
41303
|
+
);
|
|
41304
|
+
}
|
|
41305
|
+
function createQuestionnaireCommand() {
|
|
41306
|
+
return new Command("questionnaire").description("View or fill the customer pentest intake questionnaire").argument("<pentestId>", "Pentest display ID (e.g. PT-3) or UUID").option("--show", "Print current answers using shared labels (GET)").option(
|
|
41307
|
+
"--file <path>",
|
|
41308
|
+
"Upload answers from a JSON file (answers object only \u2014 not { answers }; whole-object replace)"
|
|
41309
|
+
).addHelpText(
|
|
41310
|
+
"after",
|
|
41311
|
+
`
|
|
41312
|
+
Optional scoping questionnaire for a new pentest (editable while stage is DRAFT
|
|
41313
|
+
or READY_TO_START). Reads accept a browser session or API key; writes require an
|
|
41314
|
+
organization admin (or Trace staff) signed in via \`tracecli auth login\` \u2014 API
|
|
41315
|
+
keys are rejected.
|
|
41316
|
+
|
|
41317
|
+
Modes:
|
|
41318
|
+
--show GET and print key: value with shared customer-facing labels
|
|
41319
|
+
--file <path> PUT the file's answers object (CLI wraps { answers } for the API)
|
|
41320
|
+
(TTY default) load-merge-write: GET, prompt each question, confirm, PUT
|
|
41321
|
+
|
|
41322
|
+
Non-interactive shells must pass --show or --file (exit 2 otherwise).
|
|
41323
|
+
|
|
41324
|
+
Examples:
|
|
41325
|
+
tracecli pentest questionnaire PT-1 --show
|
|
41326
|
+
tracecli pentest questionnaire PT-1 --file answers.json
|
|
41327
|
+
tracecli pentest questionnaire PT-1`
|
|
41328
|
+
).action(async (pentestId, options) => {
|
|
41329
|
+
await runQuestionnaire(pentestId, options);
|
|
41330
|
+
});
|
|
41331
|
+
}
|
|
39767
41332
|
function createPentestCommand() {
|
|
39768
41333
|
const pentest = new Command("pentest").description("Manage pentests");
|
|
39769
41334
|
pentest.addCommand(createListCommand5());
|
|
39770
41335
|
pentest.addCommand(createUpdateCommand4());
|
|
41336
|
+
pentest.addCommand(createQuestionnaireCommand());
|
|
39771
41337
|
pentest.addCommand(createFindingsCommand());
|
|
39772
41338
|
return pentest;
|
|
39773
41339
|
}
|
|
39774
41340
|
|
|
39775
41341
|
// src/update/commands.ts
|
|
39776
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as
|
|
41342
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
39777
41343
|
import { dirname as dirname2, join as join5 } from "path";
|
|
39778
41344
|
import { createInterface as createInterface4 } from "readline/promises";
|
|
39779
41345
|
var UPDATE_CACHE_FILE = "update-check.json";
|
|
@@ -39791,7 +41357,7 @@ function readUpdateCheckCache() {
|
|
|
39791
41357
|
return null;
|
|
39792
41358
|
}
|
|
39793
41359
|
try {
|
|
39794
|
-
const rawCache =
|
|
41360
|
+
const rawCache = readFileSync5(cachePath, "utf-8");
|
|
39795
41361
|
const parsed = JSON.parse(rawCache);
|
|
39796
41362
|
if (typeof parsed !== "object" || parsed === null) {
|
|
39797
41363
|
return null;
|
|
@@ -40521,177 +42087,10 @@ Examples:
|
|
|
40521
42087
|
}
|
|
40522
42088
|
);
|
|
40523
42089
|
}
|
|
40524
|
-
var FIX_PR_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
40525
|
-
"PR_OPENED",
|
|
40526
|
-
"NO_SAFE_FIX",
|
|
40527
|
-
"PATCH_TOO_LARGE",
|
|
40528
|
-
"TESTS_FAILED",
|
|
40529
|
-
"INFRA_FAILED",
|
|
40530
|
-
"STALE_VULN",
|
|
40531
|
-
"TIMED_OUT",
|
|
40532
|
-
"CANCELLED"
|
|
40533
|
-
]);
|
|
40534
|
-
var FIX_PR_AGENT_FLAVORS = ["claude-code", "codex"];
|
|
40535
|
-
var FIX_PR_POLL_MS = 3e3;
|
|
40536
|
-
function isFixPrAgentFlavor(value) {
|
|
40537
|
-
return FIX_PR_AGENT_FLAVORS.includes(value);
|
|
40538
|
-
}
|
|
40539
|
-
function formatFixPrWatchLine(row) {
|
|
40540
|
-
return `[${row.status}] run=${row.runId.slice(0, 8)} agent=${row.agentFlavor}`;
|
|
40541
|
-
}
|
|
40542
|
-
function formatFixPrTerminalLines(row) {
|
|
40543
|
-
const link = row.prUrl ? ` ${row.prUrl}` : "";
|
|
40544
|
-
const lines = [`Run ${row.runId} \u2192 ${row.status}${link}`];
|
|
40545
|
-
if (row.statusDetails) {
|
|
40546
|
-
lines.push(`Details: ${row.statusDetails}`);
|
|
40547
|
-
}
|
|
40548
|
-
return lines;
|
|
40549
|
-
}
|
|
40550
|
-
function createFixCommand() {
|
|
40551
|
-
return new Command("fix").description("Trigger a Trace auto-fix PR for the vulnerability (staff-only dogfood)").argument("<id>", "Vulnerability display ID (e.g. TRACE-123 or 123) or UUID").option(
|
|
40552
|
-
"--agent <flavor>",
|
|
40553
|
-
`Override the agent flavor (one of: ${FIX_PR_AGENT_FLAVORS.join(", ")})`
|
|
40554
|
-
).option("--watch", "Poll the run until it reaches a terminal status", false).option("-o, --output <format>", "Output format: table, json (default: table)", "table").addHelpText(
|
|
40555
|
-
"after",
|
|
40556
|
-
`
|
|
40557
|
-
Examples:
|
|
40558
|
-
# Trigger and exit immediately (scripting):
|
|
40559
|
-
tracecli vulnerabilities fix TRACE-123
|
|
40560
|
-
|
|
40561
|
-
# Trigger and watch until terminal:
|
|
40562
|
-
tracecli vulnerabilities fix TRACE-123 --watch
|
|
40563
|
-
|
|
40564
|
-
# Trigger with codex agent (requires AZURE_OPENAI_ENABLED):
|
|
40565
|
-
tracecli vulnerabilities fix TRACE-123 --agent codex
|
|
40566
|
-
|
|
40567
|
-
# JSON output (final row to stdout; rolling status to stderr under --watch):
|
|
40568
|
-
tracecli vulnerabilities fix TRACE-123 --watch --output json | jq .`
|
|
40569
|
-
).action(
|
|
40570
|
-
async (identifier, options) => {
|
|
40571
|
-
if (options.agent && !isFixPrAgentFlavor(options.agent)) {
|
|
40572
|
-
console.error(
|
|
40573
|
-
`Invalid --agent '${options.agent}'. Expected one of: ${FIX_PR_AGENT_FLAVORS.join(", ")}.`
|
|
40574
|
-
);
|
|
40575
|
-
process.exit(1);
|
|
40576
|
-
}
|
|
40577
|
-
if (options.output !== "table" && options.output !== "json") {
|
|
40578
|
-
console.error(`Invalid --output '${options.output}'. Expected one of: table, json.`);
|
|
40579
|
-
process.exit(1);
|
|
40580
|
-
}
|
|
40581
|
-
const organizationId = await resolveOrganizationId();
|
|
40582
|
-
const triggerResult = await authenticatedRequest(
|
|
40583
|
-
(client) => client.vulnerabilityFixRun.triggerRun({
|
|
40584
|
-
params: { organizationId, vulnerabilityId: identifier },
|
|
40585
|
-
body: options.agent ? { agentFlavor: options.agent } : {}
|
|
40586
|
-
})
|
|
40587
|
-
);
|
|
40588
|
-
if (triggerResult.status === 401) {
|
|
40589
|
-
console.error("Authentication failed. Run `tracecli auth login` to re-authenticate.");
|
|
40590
|
-
process.exit(1);
|
|
40591
|
-
}
|
|
40592
|
-
if (triggerResult.status === 403) {
|
|
40593
|
-
console.error(
|
|
40594
|
-
"Forbidden \u2014 vulnerability fix-PR is a staff-only feature gated by the AUTO_FIX_PR capability."
|
|
40595
|
-
);
|
|
40596
|
-
process.exit(1);
|
|
40597
|
-
}
|
|
40598
|
-
if (triggerResult.status === 404) {
|
|
40599
|
-
console.error(
|
|
40600
|
-
`Vulnerability '${identifier}' not found.
|
|
40601
|
-
Run \`tracecli vulnerabilities list\` to see available vulnerabilities.`
|
|
40602
|
-
);
|
|
40603
|
-
process.exit(1);
|
|
40604
|
-
}
|
|
40605
|
-
if (triggerResult.status === 429) {
|
|
40606
|
-
const body = triggerResult.body;
|
|
40607
|
-
const retry = body.details?.retryAfterSeconds;
|
|
40608
|
-
console.error(
|
|
40609
|
-
`Daily cap exceeded. ${retry ? `Try again in ${retry}s.` : body.message ?? ""}`
|
|
40610
|
-
);
|
|
40611
|
-
process.exit(1);
|
|
40612
|
-
}
|
|
40613
|
-
if (triggerResult.status === 400) {
|
|
40614
|
-
const body = triggerResult.body;
|
|
40615
|
-
console.error(`Bad request: ${body.message ?? "invalid input"}`);
|
|
40616
|
-
process.exit(1);
|
|
40617
|
-
}
|
|
40618
|
-
if (triggerResult.status !== 201) {
|
|
40619
|
-
console.error(`Failed to trigger fix-PR run (status ${triggerResult.status}).`);
|
|
40620
|
-
process.exit(1);
|
|
40621
|
-
}
|
|
40622
|
-
const triggered = triggerResult.body;
|
|
40623
|
-
if (!options.watch) {
|
|
40624
|
-
if (options.output === "json") {
|
|
40625
|
-
console.log(JSON.stringify(triggered, null, 2));
|
|
40626
|
-
} else {
|
|
40627
|
-
console.log(
|
|
40628
|
-
`Triggered fix-PR run ${triggered.runId} (status=${triggered.status}, agent=${triggered.agentFlavor})`
|
|
40629
|
-
);
|
|
40630
|
-
}
|
|
40631
|
-
process.exit(0);
|
|
40632
|
-
}
|
|
40633
|
-
let latest = triggered;
|
|
40634
|
-
const isTTY = process.stderr.isTTY ?? false;
|
|
40635
|
-
const onSigint = () => {
|
|
40636
|
-
const msg = `
|
|
40637
|
-
watch interrupted; run id=${latest.runId}`;
|
|
40638
|
-
process.stderr.write(`${msg}
|
|
40639
|
-
`);
|
|
40640
|
-
process.exit(130);
|
|
40641
|
-
};
|
|
40642
|
-
process.on("SIGINT", onSigint);
|
|
40643
|
-
const writeRolling = (row) => {
|
|
40644
|
-
const line = formatFixPrWatchLine(row);
|
|
40645
|
-
if (isTTY && options.output !== "json") {
|
|
40646
|
-
process.stderr.write(`\r${line} `);
|
|
40647
|
-
} else {
|
|
40648
|
-
process.stderr.write(`${line}
|
|
40649
|
-
`);
|
|
40650
|
-
}
|
|
40651
|
-
};
|
|
40652
|
-
while (!FIX_PR_TERMINAL_STATUSES.has(latest.status)) {
|
|
40653
|
-
writeRolling(latest);
|
|
40654
|
-
await new Promise((resolve) => setTimeout(resolve, FIX_PR_POLL_MS));
|
|
40655
|
-
const pollResult = await authenticatedRequest(
|
|
40656
|
-
(client) => client.vulnerabilityFixRun.getRun({
|
|
40657
|
-
params: {
|
|
40658
|
-
organizationId,
|
|
40659
|
-
vulnerabilityId: identifier,
|
|
40660
|
-
runId: latest.runId
|
|
40661
|
-
}
|
|
40662
|
-
})
|
|
40663
|
-
);
|
|
40664
|
-
if (pollResult.status === 401) {
|
|
40665
|
-
process.stderr.write("\n");
|
|
40666
|
-
console.error("Authentication failed during watch. Run `tracecli auth login`.");
|
|
40667
|
-
process.exit(1);
|
|
40668
|
-
}
|
|
40669
|
-
if (pollResult.status !== 200) {
|
|
40670
|
-
process.stderr.write("\n");
|
|
40671
|
-
console.error(`Failed to read run status (status ${pollResult.status}).`);
|
|
40672
|
-
process.exit(1);
|
|
40673
|
-
}
|
|
40674
|
-
latest = pollResult.body;
|
|
40675
|
-
}
|
|
40676
|
-
if (isTTY && options.output !== "json") {
|
|
40677
|
-
process.stderr.write("\n");
|
|
40678
|
-
}
|
|
40679
|
-
if (options.output === "json") {
|
|
40680
|
-
console.log(JSON.stringify(latest, null, 2));
|
|
40681
|
-
} else {
|
|
40682
|
-
for (const line of formatFixPrTerminalLines(latest)) {
|
|
40683
|
-
console.log(line);
|
|
40684
|
-
}
|
|
40685
|
-
}
|
|
40686
|
-
process.exit(latest.status === "PR_OPENED" ? 0 : 2);
|
|
40687
|
-
}
|
|
40688
|
-
);
|
|
40689
|
-
}
|
|
40690
42090
|
function createVulnerabilitiesCommand() {
|
|
40691
42091
|
const vulnerabilities = new Command("vulnerabilities").description("Manage vulnerabilities");
|
|
40692
42092
|
vulnerabilities.addCommand(createGetCommand4());
|
|
40693
42093
|
vulnerabilities.addCommand(createListCommand6());
|
|
40694
|
-
vulnerabilities.addCommand(createFixCommand());
|
|
40695
42094
|
return vulnerabilities;
|
|
40696
42095
|
}
|
|
40697
42096
|
|