securewithtrace 0.37.0 → 0.39.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/README.md +40 -1
- package/dist/index.js +1618 -381
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6276,7 +6276,7 @@ var $ZodBase64 = /* @__PURE__ */ $constructor("$ZodBase64", (inst, def) => {
|
|
|
6276
6276
|
function isValidBase64URL(data) {
|
|
6277
6277
|
if (!base64url.test(data))
|
|
6278
6278
|
return false;
|
|
6279
|
-
const base643 = data.replace(/[-_]/g, (
|
|
6279
|
+
const base643 = data.replace(/[-_]/g, (c59) => c59 === "-" ? "+" : "/");
|
|
6280
6280
|
const padded = base643.padEnd(Math.ceil(base643.length / 4) * 4, "=");
|
|
6281
6281
|
return isValidBase64(padded);
|
|
6282
6282
|
}
|
|
@@ -16320,9 +16320,9 @@ var ZodDate = /* @__PURE__ */ $constructor("ZodDate", (inst, def) => {
|
|
|
16320
16320
|
inst._zod.processJSONSchema = (ctx, json2, params) => dateProcessor(inst, ctx, json2, params);
|
|
16321
16321
|
inst.min = (value, params) => inst.check(_gte(value, params));
|
|
16322
16322
|
inst.max = (value, params) => inst.check(_lte(value, params));
|
|
16323
|
-
const
|
|
16324
|
-
inst.minDate =
|
|
16325
|
-
inst.maxDate =
|
|
16323
|
+
const c59 = inst._zod.bag;
|
|
16324
|
+
inst.minDate = c59.minimum ? new Date(c59.minimum) : null;
|
|
16325
|
+
inst.maxDate = c59.maximum ? new Date(c59.maximum) : null;
|
|
16326
16326
|
});
|
|
16327
16327
|
function date3(params) {
|
|
16328
16328
|
return _date(ZodDate, params);
|
|
@@ -21998,7 +21998,7 @@ var PentestEditActionValues = [
|
|
|
21998
21998
|
"DELIVER"
|
|
21999
21999
|
];
|
|
22000
22000
|
var PentestEditAction = external_exports.enum(PentestEditActionValues);
|
|
22001
|
-
var PentestAuditActorTypeValues = ["USER", "SYSTEM", "AGENT"];
|
|
22001
|
+
var PentestAuditActorTypeValues = ["USER", "SYSTEM", "AGENT", "API_KEY"];
|
|
22002
22002
|
var PentestAuditActorType = external_exports.enum(PentestAuditActorTypeValues);
|
|
22003
22003
|
var PentestHypothesisStatusValues = [
|
|
22004
22004
|
"DRAFTED",
|
|
@@ -23008,6 +23008,263 @@ var LinearTicketContextResponseSchema = external_exports.object({
|
|
|
23008
23008
|
var AttestationClassificationValues = ["PUBLIC", "CONFIDENTIAL"];
|
|
23009
23009
|
var AttestationClassification = external_exports.enum(AttestationClassificationValues);
|
|
23010
23010
|
|
|
23011
|
+
// ../../packages/api-contracts/src/schemas/api/v1/repository.api.ts
|
|
23012
|
+
var PlatformValues = ["GITHUB", "GITLAB", "BITBUCKET", "UPLOAD"];
|
|
23013
|
+
var RepositoryStatusValues = ["CONNECTED", "DISCONNECTED"];
|
|
23014
|
+
var RepositoryIdParamsSchema = OrgIdParamsSchema.extend({
|
|
23015
|
+
repositoryId: external_exports.uuid()
|
|
23016
|
+
});
|
|
23017
|
+
var CreateRepositoryRequestSchema = external_exports.object({
|
|
23018
|
+
repositoryUrl: external_exports.url(),
|
|
23019
|
+
platform: external_exports.enum(PlatformValues),
|
|
23020
|
+
githubDefaultBranch: external_exports.string().min(1).max(255).optional(),
|
|
23021
|
+
status: external_exports.enum(RepositoryStatusValues).optional()
|
|
23022
|
+
});
|
|
23023
|
+
var UpdateRepositoryRequestSchema = external_exports.object({
|
|
23024
|
+
repositoryUrl: external_exports.url().optional(),
|
|
23025
|
+
platform: external_exports.enum(PlatformValues).optional(),
|
|
23026
|
+
githubDefaultBranch: external_exports.string().min(1).max(255).optional(),
|
|
23027
|
+
status: external_exports.enum(RepositoryStatusValues).optional()
|
|
23028
|
+
});
|
|
23029
|
+
var RepositoryResponseSchema = external_exports.object({
|
|
23030
|
+
repositoryId: external_exports.uuid(),
|
|
23031
|
+
organizationId: external_exports.uuid(),
|
|
23032
|
+
repositoryUrl: external_exports.url(),
|
|
23033
|
+
platform: external_exports.enum(PlatformValues),
|
|
23034
|
+
status: external_exports.enum(RepositoryStatusValues),
|
|
23035
|
+
githubDefaultBranch: external_exports.string(),
|
|
23036
|
+
scanningBranch: external_exports.string().nullable(),
|
|
23037
|
+
primaryLanguage: external_exports.string().nullable().optional(),
|
|
23038
|
+
/** Staff-set opt-in: automated PR scans run on this repo even without a FULL SAST baseline. */
|
|
23039
|
+
prScansEnabled: external_exports.boolean(),
|
|
23040
|
+
createdAt: external_exports.date(),
|
|
23041
|
+
updatedAt: external_exports.date()
|
|
23042
|
+
});
|
|
23043
|
+
var ListRepositoriesResponseSchema = external_exports.array(RepositoryResponseSchema);
|
|
23044
|
+
var SetPrScansEnabledRequestSchema = external_exports.object({
|
|
23045
|
+
enabled: external_exports.boolean()
|
|
23046
|
+
});
|
|
23047
|
+
var StaffRepositoryPrScanSettingSchema = external_exports.object({
|
|
23048
|
+
repositoryId: external_exports.uuid(),
|
|
23049
|
+
/** GitHub owner/name when synced; null for rows created before the sync backfill. */
|
|
23050
|
+
fullName: external_exports.string().nullable(),
|
|
23051
|
+
repositoryUrl: external_exports.url(),
|
|
23052
|
+
/** The staff-set opt-in arm of the gate. */
|
|
23053
|
+
prScansEnabled: external_exports.boolean(),
|
|
23054
|
+
/**
|
|
23055
|
+
* The implicit arm: a completed FULL SAST scan exists for this repo (any
|
|
23056
|
+
* branch). With the org capability granted, either arm open means PR scans run.
|
|
23057
|
+
*/
|
|
23058
|
+
hasSastBaseline: external_exports.boolean()
|
|
23059
|
+
});
|
|
23060
|
+
var StaffPrScanSettingsResponseSchema = external_exports.object({
|
|
23061
|
+
/** Org-level gate: without AUTO_PR_SCANS the per-repo switches are inert. */
|
|
23062
|
+
orgHasAutoPrScans: external_exports.boolean(),
|
|
23063
|
+
repositories: external_exports.array(StaffRepositoryPrScanSettingSchema)
|
|
23064
|
+
});
|
|
23065
|
+
var CloneTokenRequestSchema = external_exports.object({
|
|
23066
|
+
repositoryUrl: external_exports.string().url()
|
|
23067
|
+
});
|
|
23068
|
+
var CloneTokenResponseSchema = external_exports.object({
|
|
23069
|
+
token: external_exports.string(),
|
|
23070
|
+
expiresAt: external_exports.string().datetime(),
|
|
23071
|
+
// Git username scheme to pair with this token. GitHub installation tokens
|
|
23072
|
+
// use `x-access-token`; Bitbucket app tokens use `x-token-auth`. Optional
|
|
23073
|
+
// for back-compat with CLIs that predate Bitbucket support and hardcode
|
|
23074
|
+
// `x-access-token` (the correct value for the GitHub-only flow they gate on).
|
|
23075
|
+
username: external_exports.enum(["x-access-token", "x-token-auth"]).optional()
|
|
23076
|
+
});
|
|
23077
|
+
var ScanningBranchHistoryEntrySchema = external_exports.object({
|
|
23078
|
+
historyId: external_exports.uuid(),
|
|
23079
|
+
branch: external_exports.string(),
|
|
23080
|
+
configuredAt: external_exports.date(),
|
|
23081
|
+
replacedAt: external_exports.date(),
|
|
23082
|
+
configuredByUserId: external_exports.uuid().nullable()
|
|
23083
|
+
});
|
|
23084
|
+
var ScanningBranchStateSchema = external_exports.object({
|
|
23085
|
+
scanningBranch: external_exports.string().nullable(),
|
|
23086
|
+
githubDefaultBranch: external_exports.string(),
|
|
23087
|
+
history: external_exports.array(ScanningBranchHistoryEntrySchema)
|
|
23088
|
+
});
|
|
23089
|
+
var SetScanningBranchRequestSchema = external_exports.object({
|
|
23090
|
+
branch: external_exports.string().min(1).max(255),
|
|
23091
|
+
migrateOpenVulnerabilities: external_exports.boolean(),
|
|
23092
|
+
/**
|
|
23093
|
+
* Optional compare-and-swap guard. When provided, the switch only commits
|
|
23094
|
+
* if the repo's current `scanningBranch` matches. Mismatch → HTTP 409.
|
|
23095
|
+
* `null` means "expect this repo to still be unconfigured."
|
|
23096
|
+
*/
|
|
23097
|
+
expectedCurrentBranch: external_exports.string().nullable().optional()
|
|
23098
|
+
});
|
|
23099
|
+
var SetScanningBranchResponseSchema = external_exports.object({
|
|
23100
|
+
previousBranch: external_exports.string().nullable(),
|
|
23101
|
+
newBranch: external_exports.string(),
|
|
23102
|
+
relabeledVulnerabilityCount: external_exports.number().int().min(0),
|
|
23103
|
+
/** Null when previousBranch was null (initial configuration). */
|
|
23104
|
+
historyId: external_exports.uuid().nullable()
|
|
23105
|
+
});
|
|
23106
|
+
var BulkSetScanningBranchBranchSchema = external_exports.discriminatedUnion("kind", [
|
|
23107
|
+
external_exports.object({ kind: external_exports.literal("literal"), value: external_exports.string().min(1).max(255) }),
|
|
23108
|
+
external_exports.object({ kind: external_exports.literal("github-default") })
|
|
23109
|
+
]);
|
|
23110
|
+
var BulkSetScanningBranchRequestSchema = external_exports.object({
|
|
23111
|
+
branch: BulkSetScanningBranchBranchSchema,
|
|
23112
|
+
repositoryIds: external_exports.array(external_exports.uuid()).min(1).max(100),
|
|
23113
|
+
migrateOpenVulnerabilities: external_exports.boolean()
|
|
23114
|
+
});
|
|
23115
|
+
var BulkSetScanningBranchResultStatusValues = [
|
|
23116
|
+
"switched",
|
|
23117
|
+
"branch-missing-on-github",
|
|
23118
|
+
"forbidden",
|
|
23119
|
+
"already-on-branch",
|
|
23120
|
+
"not-found",
|
|
23121
|
+
"error"
|
|
23122
|
+
];
|
|
23123
|
+
var BulkSetScanningBranchResultSchema = external_exports.object({
|
|
23124
|
+
repositoryId: external_exports.uuid(),
|
|
23125
|
+
status: external_exports.enum(BulkSetScanningBranchResultStatusValues),
|
|
23126
|
+
relabeledVulnerabilityCount: external_exports.number().int().min(0).optional(),
|
|
23127
|
+
historyId: external_exports.uuid().nullable().optional(),
|
|
23128
|
+
errorMessage: external_exports.string().optional()
|
|
23129
|
+
});
|
|
23130
|
+
var BulkSetScanningBranchResponseSchema = external_exports.object({
|
|
23131
|
+
results: external_exports.array(BulkSetScanningBranchResultSchema)
|
|
23132
|
+
});
|
|
23133
|
+
var ScanningBranchPreferenceSchema = external_exports.object({
|
|
23134
|
+
autoConfigureScanningBranch: external_exports.boolean()
|
|
23135
|
+
});
|
|
23136
|
+
var ConfirmScanningBranchDefaultsResponseSchema = external_exports.object({
|
|
23137
|
+
autoConfigureScanningBranch: external_exports.literal(true),
|
|
23138
|
+
/** Repos the sweep configured to their default-branch mirror. */
|
|
23139
|
+
configuredCount: external_exports.number().int().min(0),
|
|
23140
|
+
/**
|
|
23141
|
+
* Rows skipped by the sweep's domain guards (empty or >255-char mirror).
|
|
23142
|
+
* They stay NULL and keep the "waiting on a scanning branch" banner alive.
|
|
23143
|
+
*/
|
|
23144
|
+
skippedCount: external_exports.number().int().min(0)
|
|
23145
|
+
});
|
|
23146
|
+
|
|
23147
|
+
// ../../packages/api-contracts/src/schemas/api/v1/application.api.ts
|
|
23148
|
+
var ApplicationTypeValues = ["WEB", "CLI", "MOBILE", "DESKTOP", "API_SERVICE"];
|
|
23149
|
+
var APPLICATION_NOTES_MAX_CHARS = 2e3;
|
|
23150
|
+
var ApplicationRepositoryRoleValues = [
|
|
23151
|
+
"FRONTEND",
|
|
23152
|
+
"BACKEND_API",
|
|
23153
|
+
"AUTH_SERVICE",
|
|
23154
|
+
"WORKER_JOB_SERVICE",
|
|
23155
|
+
"SHARED_PACKAGE_SDK",
|
|
23156
|
+
"INFRASTRUCTURE_IAC",
|
|
23157
|
+
"MOBILE_CLIENT",
|
|
23158
|
+
"MONOREPO",
|
|
23159
|
+
"OTHER"
|
|
23160
|
+
];
|
|
23161
|
+
var ApplicationIdParamsSchema = OrgIdParamsSchema.extend({
|
|
23162
|
+
applicationId: external_exports.uuid()
|
|
23163
|
+
});
|
|
23164
|
+
var ApplicationRepositoryIdParamsSchema = ApplicationIdParamsSchema.extend({
|
|
23165
|
+
applicationRepositoryId: external_exports.uuid()
|
|
23166
|
+
});
|
|
23167
|
+
var ApplicationRepositorySummarySchema = external_exports.object({
|
|
23168
|
+
applicationRepositoryId: external_exports.uuid().nullable(),
|
|
23169
|
+
applicationId: external_exports.uuid(),
|
|
23170
|
+
organizationId: external_exports.uuid(),
|
|
23171
|
+
repositoryId: external_exports.uuid(),
|
|
23172
|
+
repositoryName: external_exports.string(),
|
|
23173
|
+
repositoryUrl: external_exports.string(),
|
|
23174
|
+
repositoryStatus: external_exports.enum(RepositoryStatusValues),
|
|
23175
|
+
htmlUrl: external_exports.string().nullable(),
|
|
23176
|
+
createdAt: external_exports.date(),
|
|
23177
|
+
updatedAt: external_exports.date()
|
|
23178
|
+
});
|
|
23179
|
+
var ApplicationRepositoryRolesSchema = external_exports.array(external_exports.enum(ApplicationRepositoryRoleValues)).max(ApplicationRepositoryRoleValues.length);
|
|
23180
|
+
var ApplicationRepositoryLinkResponseSchema = ApplicationRepositorySummarySchema.extend({
|
|
23181
|
+
// First of `roles` (enum order), or null when unspecified. Kept so a new
|
|
23182
|
+
// client reading a pre-this-release API during a rolling deploy still parses.
|
|
23183
|
+
role: external_exports.enum(ApplicationRepositoryRoleValues).nullable(),
|
|
23184
|
+
// Source of truth. Defaulted empty so a new client reading a pre-this-release
|
|
23185
|
+
// API that omitted the field doesn't reject the row; the client then falls
|
|
23186
|
+
// back to wrapping `role`.
|
|
23187
|
+
roles: ApplicationRepositoryRolesSchema.default([]),
|
|
23188
|
+
roleLabel: external_exports.string().max(120).nullable(),
|
|
23189
|
+
repositoryPath: external_exports.string().max(500).nullable(),
|
|
23190
|
+
scanEnabled: external_exports.boolean()
|
|
23191
|
+
});
|
|
23192
|
+
var ListApplicationRepositoryLinksResponseSchema = external_exports.array(
|
|
23193
|
+
ApplicationRepositoryLinkResponseSchema
|
|
23194
|
+
);
|
|
23195
|
+
var ApplicationResponseSchema = external_exports.object({
|
|
23196
|
+
applicationId: external_exports.uuid(),
|
|
23197
|
+
organizationId: external_exports.uuid(),
|
|
23198
|
+
name: external_exports.string(),
|
|
23199
|
+
// `.default('WEB')` keeps responses backward-compatible: a pre-P1.3 API that
|
|
23200
|
+
// never emitted `type` parses cleanly (existing apps are semantically WEB),
|
|
23201
|
+
// so a new frontend reading an old API during a mixed-version rollout doesn't
|
|
23202
|
+
// reject application rows.
|
|
23203
|
+
type: external_exports.enum(ApplicationTypeValues).default("WEB"),
|
|
23204
|
+
applicationUrl: external_exports.string().nullable(),
|
|
23205
|
+
// Customer-authored free-text context, any type ("Advanced → Notes").
|
|
23206
|
+
notes: external_exports.string().nullable(),
|
|
23207
|
+
helpCenterUrl: external_exports.string().nullable(),
|
|
23208
|
+
documentationUrl: external_exports.string().nullable(),
|
|
23209
|
+
repositories: external_exports.array(ApplicationRepositorySummarySchema),
|
|
23210
|
+
// Registrable domains RECON is authorized to discover subdomains under. The
|
|
23211
|
+
// Environments-tab panel hydrates from this payload (no client GET). Defaulted
|
|
23212
|
+
// (like `type`) so a new client reading a pre-this-release API during a rolling
|
|
23213
|
+
// deploy doesn't reject application rows that predate the field.
|
|
23214
|
+
// Signed S3 URL for the Overview screenshot. Defaulted null so a new client
|
|
23215
|
+
// reading a pre-this-release API during a rolling deploy doesn't reject rows
|
|
23216
|
+
// that omit the field. The raw S3 key is never on the wire.
|
|
23217
|
+
screenshotUrl: external_exports.url().nullable().default(null),
|
|
23218
|
+
// Defaulted null so a new client reading a pre-this-release API during a
|
|
23219
|
+
// rolling deploy doesn't reject application rows that omit the field.
|
|
23220
|
+
credentialsNudgeDismissedAt: external_exports.date().nullable().default(null),
|
|
23221
|
+
createdAt: external_exports.date(),
|
|
23222
|
+
updatedAt: external_exports.date()
|
|
23223
|
+
});
|
|
23224
|
+
var ListApplicationsResponseSchema = external_exports.array(ApplicationResponseSchema);
|
|
23225
|
+
var CreateApplicationRequestSchema = external_exports.object({
|
|
23226
|
+
name: external_exports.string().min(1).max(200),
|
|
23227
|
+
type: external_exports.enum(ApplicationTypeValues).default("WEB"),
|
|
23228
|
+
applicationUrl: external_exports.url().max(2048).optional(),
|
|
23229
|
+
notes: external_exports.string().max(APPLICATION_NOTES_MAX_CHARS).optional(),
|
|
23230
|
+
repositoryId: external_exports.uuid().optional(),
|
|
23231
|
+
repositoryPath: external_exports.string().max(500).optional(),
|
|
23232
|
+
helpCenterUrl: external_exports.url().max(2048).optional(),
|
|
23233
|
+
documentationUrl: external_exports.url().max(2048).optional()
|
|
23234
|
+
}).strict().refine((data) => !isUrlBearingApplicationType(data.type) || data.applicationUrl != null, {
|
|
23235
|
+
path: ["applicationUrl"],
|
|
23236
|
+
message: "A web or API application requires an application URL."
|
|
23237
|
+
}).refine((data) => isUrlBearingApplicationType(data.type) || data.applicationUrl == null, {
|
|
23238
|
+
path: ["applicationUrl"],
|
|
23239
|
+
message: "Only web or API applications can have an application URL."
|
|
23240
|
+
});
|
|
23241
|
+
var CreateApplicationRepositoryLinkRequestSchema = external_exports.object({
|
|
23242
|
+
repositoryId: external_exports.uuid(),
|
|
23243
|
+
// Legacy single-role write. Ignored when `roles` is also sent.
|
|
23244
|
+
role: external_exports.enum(ApplicationRepositoryRoleValues).nullable().optional(),
|
|
23245
|
+
roles: ApplicationRepositoryRolesSchema.optional(),
|
|
23246
|
+
roleLabel: external_exports.string().max(120).nullable().optional(),
|
|
23247
|
+
repositoryPath: external_exports.string().max(500).nullable().optional(),
|
|
23248
|
+
scanEnabled: external_exports.boolean().optional()
|
|
23249
|
+
}).strict();
|
|
23250
|
+
var UpdateApplicationRepositoryLinkRequestSchema = external_exports.object({
|
|
23251
|
+
// Legacy single-role write. Ignored when `roles` is also sent.
|
|
23252
|
+
role: external_exports.enum(ApplicationRepositoryRoleValues).nullable().optional(),
|
|
23253
|
+
roles: ApplicationRepositoryRolesSchema.optional(),
|
|
23254
|
+
roleLabel: external_exports.string().max(120).nullable().optional(),
|
|
23255
|
+
repositoryPath: external_exports.string().max(500).nullable().optional(),
|
|
23256
|
+
scanEnabled: external_exports.boolean().optional()
|
|
23257
|
+
}).strict();
|
|
23258
|
+
var UpdateApplicationRequestSchema = external_exports.object({
|
|
23259
|
+
name: external_exports.string().min(1).max(200).optional(),
|
|
23260
|
+
applicationUrl: external_exports.url().max(2048).optional(),
|
|
23261
|
+
notes: external_exports.string().max(APPLICATION_NOTES_MAX_CHARS).nullable().optional(),
|
|
23262
|
+
repositoryId: external_exports.uuid().nullable().optional(),
|
|
23263
|
+
repositoryPath: external_exports.string().max(500).nullable().optional(),
|
|
23264
|
+
helpCenterUrl: external_exports.url().max(2048).nullable().optional(),
|
|
23265
|
+
documentationUrl: external_exports.url().max(2048).nullable().optional()
|
|
23266
|
+
}).strict();
|
|
23267
|
+
|
|
23011
23268
|
// ../../packages/api-contracts/src/schemas/api/v1/pentest-report-pdf.api.ts
|
|
23012
23269
|
var ReportPdfPentestParamsSchema = OrgIdParamsSchema.extend({
|
|
23013
23270
|
pentestId: external_exports.uuid()
|
|
@@ -23093,6 +23350,28 @@ var PartnerNarrativeJsonSchema = external_exports.object({
|
|
|
23093
23350
|
notExploitable: external_exports.string().max(4e3).optional()
|
|
23094
23351
|
})
|
|
23095
23352
|
});
|
|
23353
|
+
var BskNarrativeSectionIdValues = [
|
|
23354
|
+
"engagement_context",
|
|
23355
|
+
"platform_and_data",
|
|
23356
|
+
"overall_assessment",
|
|
23357
|
+
"findings_overview",
|
|
23358
|
+
"target",
|
|
23359
|
+
"approach",
|
|
23360
|
+
"limitations",
|
|
23361
|
+
"not_exploitable"
|
|
23362
|
+
];
|
|
23363
|
+
var BskNarrativeSectionId = external_exports.enum(BskNarrativeSectionIdValues);
|
|
23364
|
+
var TraceNarrativeSectionIdValues = [
|
|
23365
|
+
"executive_summary",
|
|
23366
|
+
"scope_summary",
|
|
23367
|
+
"key_themes"
|
|
23368
|
+
];
|
|
23369
|
+
var ReportWriteSectionIdValues = [
|
|
23370
|
+
...TraceNarrativeSectionIdValues,
|
|
23371
|
+
...BskNarrativeSectionIdValues
|
|
23372
|
+
];
|
|
23373
|
+
var ReportWriteSectionId = external_exports.enum(ReportWriteSectionIdValues);
|
|
23374
|
+
var REPORT_SECTION_CONTENT_MAX_CHARS = 4e3;
|
|
23096
23375
|
var SeverityCountsSchema = external_exports.object({
|
|
23097
23376
|
critical: external_exports.int().min(0),
|
|
23098
23377
|
high: external_exports.int().min(0),
|
|
@@ -23415,6 +23694,8 @@ var ApplyReportSettingsRequestSchema = external_exports.object({
|
|
|
23415
23694
|
includeRemediationTimeline: external_exports.boolean(),
|
|
23416
23695
|
expectedUpdatedAt: external_exports.coerce.date().nullable()
|
|
23417
23696
|
});
|
|
23697
|
+
var CustomerReportDownloadFormatValues = ["pdf", "bundle"];
|
|
23698
|
+
var CustomerReportDownloadFormatSchema = external_exports.enum(CustomerReportDownloadFormatValues);
|
|
23418
23699
|
var CustomerReportPdfResponseSchema = ReportPdfResponseSchema.omit({
|
|
23419
23700
|
organizationId: true,
|
|
23420
23701
|
pentestId: true,
|
|
@@ -23446,7 +23727,14 @@ var CustomerReportPdfResponseSchema = ReportPdfResponseSchema.omit({
|
|
|
23446
23727
|
* before the API's, so a new bundle briefly reads an old API's response, where
|
|
23447
23728
|
* this field does not exist. Consumers default it to false.
|
|
23448
23729
|
*/
|
|
23449
|
-
canViewInline: external_exports.boolean().optional()
|
|
23730
|
+
canViewInline: external_exports.boolean().optional(),
|
|
23731
|
+
/**
|
|
23732
|
+
* What the Download action hands the customer: the PDF alone, or one zip
|
|
23733
|
+
* carrying the PDF, the markdown report, and the evidence files (partner
|
|
23734
|
+
* templates whose tooling consumes the markdown). Preview always opens the
|
|
23735
|
+
* PDF. Optional for the deploy-order reason above; consumers default to 'pdf'.
|
|
23736
|
+
*/
|
|
23737
|
+
downloadFormat: CustomerReportDownloadFormatSchema.optional()
|
|
23450
23738
|
});
|
|
23451
23739
|
var GetCustomerReportPdfResponseSchema = external_exports.object({
|
|
23452
23740
|
report: CustomerReportPdfResponseSchema.nullable()
|
|
@@ -23566,6 +23854,12 @@ var IssuedReportSnapshotSchema = external_exports.object({
|
|
|
23566
23854
|
* parses those rows for the changelog diff — a required field would throw
|
|
23567
23855
|
* there and break issuing a new version of any pre-feature report. */
|
|
23568
23856
|
testType: PentestTestType.optional(),
|
|
23857
|
+
/** Types of the applications bound at issuance: the archival record of which
|
|
23858
|
+
* OWASP families the delivered PDF named. Optional for the same reason as
|
|
23859
|
+
* `testType` above: a pre-feature snapshot has no value, and
|
|
23860
|
+
* `latestIssuedSnapshot` parses those rows for the changelog diff. Absent
|
|
23861
|
+
* re-renders as the web family, matching what those reports contain. */
|
|
23862
|
+
applicationTypes: external_exports.array(external_exports.enum(ApplicationTypeValues)).optional(),
|
|
23569
23863
|
versionLabel: external_exports.string(),
|
|
23570
23864
|
revisionCount: external_exports.int().min(1)
|
|
23571
23865
|
}),
|
|
@@ -24390,15 +24684,34 @@ var StartProgressPentestFindingRequestSchema = external_exports.object({});
|
|
|
24390
24684
|
var ReportRemediationPentestFindingRequestSchema = external_exports.object({
|
|
24391
24685
|
note: external_exports.string().trim().min(1).max(1e4).optional()
|
|
24392
24686
|
});
|
|
24687
|
+
var AutomationFindingTransitionSchema = external_exports.enum(["IN_PROGRESS", "REMEDIATED"]);
|
|
24688
|
+
var AutomationStatusUpdateRequestSchema = external_exports.object({
|
|
24689
|
+
status: AutomationFindingTransitionSchema,
|
|
24690
|
+
note: external_exports.string().trim().min(1).max(1e4).optional()
|
|
24691
|
+
}).refine((value) => value.note === void 0 || value.status === "REMEDIATED", {
|
|
24692
|
+
message: "note is only accepted when reporting remediation (status REMEDIATED)",
|
|
24693
|
+
path: ["note"]
|
|
24694
|
+
});
|
|
24393
24695
|
var ReopenPentestFindingTargetStatusSchema = external_exports.enum(["OPEN", "IN_PROGRESS"]);
|
|
24394
24696
|
var ReopenPentestFindingRequestSchema = external_exports.object({
|
|
24395
24697
|
targetStatus: ReopenPentestFindingTargetStatusSchema,
|
|
24396
24698
|
noteContent: external_exports.string().trim().min(1).max(1e4)
|
|
24397
24699
|
});
|
|
24700
|
+
var retestVerificationOnlyOnFixed = (value, ctx) => {
|
|
24701
|
+
if (value.outcome !== "FIXED" && value.verification !== void 0) {
|
|
24702
|
+
ctx.addIssue({
|
|
24703
|
+
code: "custom",
|
|
24704
|
+
message: "verification report prose is only allowed when outcome is FIXED",
|
|
24705
|
+
path: ["verification"]
|
|
24706
|
+
});
|
|
24707
|
+
}
|
|
24708
|
+
};
|
|
24398
24709
|
var CreatePentestFindingRetestRequestSchema = external_exports.object({
|
|
24399
24710
|
outcome: ManualRetestOutcome,
|
|
24400
|
-
notes: external_exports.string().trim().min(1).max(1e4)
|
|
24711
|
+
notes: external_exports.string().trim().min(1).max(1e4),
|
|
24712
|
+
verification: external_exports.string().trim().min(1).max(8e3).optional()
|
|
24401
24713
|
});
|
|
24714
|
+
var CreatePentestFindingRetestBodySchema = CreatePentestFindingRetestRequestSchema.superRefine(retestVerificationOnlyOnFixed);
|
|
24402
24715
|
var CreatePentestFindingNoteRequestSchema = external_exports.object({
|
|
24403
24716
|
content: external_exports.string().min(1).max(1e4)
|
|
24404
24717
|
});
|
|
@@ -24592,263 +24905,6 @@ var PromotePentestHypothesisRequestSchema = external_exports.object({
|
|
|
24592
24905
|
manualFindingIds: HypothesisSourceIdsSchema.optional()
|
|
24593
24906
|
}).strict().optional();
|
|
24594
24907
|
|
|
24595
|
-
// ../../packages/api-contracts/src/schemas/api/v1/repository.api.ts
|
|
24596
|
-
var PlatformValues = ["GITHUB", "GITLAB", "BITBUCKET", "UPLOAD"];
|
|
24597
|
-
var RepositoryStatusValues = ["CONNECTED", "DISCONNECTED"];
|
|
24598
|
-
var RepositoryIdParamsSchema = OrgIdParamsSchema.extend({
|
|
24599
|
-
repositoryId: external_exports.uuid()
|
|
24600
|
-
});
|
|
24601
|
-
var CreateRepositoryRequestSchema = external_exports.object({
|
|
24602
|
-
repositoryUrl: external_exports.url(),
|
|
24603
|
-
platform: external_exports.enum(PlatformValues),
|
|
24604
|
-
githubDefaultBranch: external_exports.string().min(1).max(255).optional(),
|
|
24605
|
-
status: external_exports.enum(RepositoryStatusValues).optional()
|
|
24606
|
-
});
|
|
24607
|
-
var UpdateRepositoryRequestSchema = external_exports.object({
|
|
24608
|
-
repositoryUrl: external_exports.url().optional(),
|
|
24609
|
-
platform: external_exports.enum(PlatformValues).optional(),
|
|
24610
|
-
githubDefaultBranch: external_exports.string().min(1).max(255).optional(),
|
|
24611
|
-
status: external_exports.enum(RepositoryStatusValues).optional()
|
|
24612
|
-
});
|
|
24613
|
-
var RepositoryResponseSchema = external_exports.object({
|
|
24614
|
-
repositoryId: external_exports.uuid(),
|
|
24615
|
-
organizationId: external_exports.uuid(),
|
|
24616
|
-
repositoryUrl: external_exports.url(),
|
|
24617
|
-
platform: external_exports.enum(PlatformValues),
|
|
24618
|
-
status: external_exports.enum(RepositoryStatusValues),
|
|
24619
|
-
githubDefaultBranch: external_exports.string(),
|
|
24620
|
-
scanningBranch: external_exports.string().nullable(),
|
|
24621
|
-
primaryLanguage: external_exports.string().nullable().optional(),
|
|
24622
|
-
/** Staff-set opt-in: automated PR scans run on this repo even without a FULL SAST baseline. */
|
|
24623
|
-
prScansEnabled: external_exports.boolean(),
|
|
24624
|
-
createdAt: external_exports.date(),
|
|
24625
|
-
updatedAt: external_exports.date()
|
|
24626
|
-
});
|
|
24627
|
-
var ListRepositoriesResponseSchema = external_exports.array(RepositoryResponseSchema);
|
|
24628
|
-
var SetPrScansEnabledRequestSchema = external_exports.object({
|
|
24629
|
-
enabled: external_exports.boolean()
|
|
24630
|
-
});
|
|
24631
|
-
var StaffRepositoryPrScanSettingSchema = external_exports.object({
|
|
24632
|
-
repositoryId: external_exports.uuid(),
|
|
24633
|
-
/** GitHub owner/name when synced; null for rows created before the sync backfill. */
|
|
24634
|
-
fullName: external_exports.string().nullable(),
|
|
24635
|
-
repositoryUrl: external_exports.url(),
|
|
24636
|
-
/** The staff-set opt-in arm of the gate. */
|
|
24637
|
-
prScansEnabled: external_exports.boolean(),
|
|
24638
|
-
/**
|
|
24639
|
-
* The implicit arm: a completed FULL SAST scan exists for this repo (any
|
|
24640
|
-
* branch). With the org capability granted, either arm open means PR scans run.
|
|
24641
|
-
*/
|
|
24642
|
-
hasSastBaseline: external_exports.boolean()
|
|
24643
|
-
});
|
|
24644
|
-
var StaffPrScanSettingsResponseSchema = external_exports.object({
|
|
24645
|
-
/** Org-level gate: without AUTO_PR_SCANS the per-repo switches are inert. */
|
|
24646
|
-
orgHasAutoPrScans: external_exports.boolean(),
|
|
24647
|
-
repositories: external_exports.array(StaffRepositoryPrScanSettingSchema)
|
|
24648
|
-
});
|
|
24649
|
-
var CloneTokenRequestSchema = external_exports.object({
|
|
24650
|
-
repositoryUrl: external_exports.string().url()
|
|
24651
|
-
});
|
|
24652
|
-
var CloneTokenResponseSchema = external_exports.object({
|
|
24653
|
-
token: external_exports.string(),
|
|
24654
|
-
expiresAt: external_exports.string().datetime(),
|
|
24655
|
-
// Git username scheme to pair with this token. GitHub installation tokens
|
|
24656
|
-
// use `x-access-token`; Bitbucket app tokens use `x-token-auth`. Optional
|
|
24657
|
-
// for back-compat with CLIs that predate Bitbucket support and hardcode
|
|
24658
|
-
// `x-access-token` (the correct value for the GitHub-only flow they gate on).
|
|
24659
|
-
username: external_exports.enum(["x-access-token", "x-token-auth"]).optional()
|
|
24660
|
-
});
|
|
24661
|
-
var ScanningBranchHistoryEntrySchema = external_exports.object({
|
|
24662
|
-
historyId: external_exports.uuid(),
|
|
24663
|
-
branch: external_exports.string(),
|
|
24664
|
-
configuredAt: external_exports.date(),
|
|
24665
|
-
replacedAt: external_exports.date(),
|
|
24666
|
-
configuredByUserId: external_exports.uuid().nullable()
|
|
24667
|
-
});
|
|
24668
|
-
var ScanningBranchStateSchema = external_exports.object({
|
|
24669
|
-
scanningBranch: external_exports.string().nullable(),
|
|
24670
|
-
githubDefaultBranch: external_exports.string(),
|
|
24671
|
-
history: external_exports.array(ScanningBranchHistoryEntrySchema)
|
|
24672
|
-
});
|
|
24673
|
-
var SetScanningBranchRequestSchema = external_exports.object({
|
|
24674
|
-
branch: external_exports.string().min(1).max(255),
|
|
24675
|
-
migrateOpenVulnerabilities: external_exports.boolean(),
|
|
24676
|
-
/**
|
|
24677
|
-
* Optional compare-and-swap guard. When provided, the switch only commits
|
|
24678
|
-
* if the repo's current `scanningBranch` matches. Mismatch → HTTP 409.
|
|
24679
|
-
* `null` means "expect this repo to still be unconfigured."
|
|
24680
|
-
*/
|
|
24681
|
-
expectedCurrentBranch: external_exports.string().nullable().optional()
|
|
24682
|
-
});
|
|
24683
|
-
var SetScanningBranchResponseSchema = external_exports.object({
|
|
24684
|
-
previousBranch: external_exports.string().nullable(),
|
|
24685
|
-
newBranch: external_exports.string(),
|
|
24686
|
-
relabeledVulnerabilityCount: external_exports.number().int().min(0),
|
|
24687
|
-
/** Null when previousBranch was null (initial configuration). */
|
|
24688
|
-
historyId: external_exports.uuid().nullable()
|
|
24689
|
-
});
|
|
24690
|
-
var BulkSetScanningBranchBranchSchema = external_exports.discriminatedUnion("kind", [
|
|
24691
|
-
external_exports.object({ kind: external_exports.literal("literal"), value: external_exports.string().min(1).max(255) }),
|
|
24692
|
-
external_exports.object({ kind: external_exports.literal("github-default") })
|
|
24693
|
-
]);
|
|
24694
|
-
var BulkSetScanningBranchRequestSchema = external_exports.object({
|
|
24695
|
-
branch: BulkSetScanningBranchBranchSchema,
|
|
24696
|
-
repositoryIds: external_exports.array(external_exports.uuid()).min(1).max(100),
|
|
24697
|
-
migrateOpenVulnerabilities: external_exports.boolean()
|
|
24698
|
-
});
|
|
24699
|
-
var BulkSetScanningBranchResultStatusValues = [
|
|
24700
|
-
"switched",
|
|
24701
|
-
"branch-missing-on-github",
|
|
24702
|
-
"forbidden",
|
|
24703
|
-
"already-on-branch",
|
|
24704
|
-
"not-found",
|
|
24705
|
-
"error"
|
|
24706
|
-
];
|
|
24707
|
-
var BulkSetScanningBranchResultSchema = external_exports.object({
|
|
24708
|
-
repositoryId: external_exports.uuid(),
|
|
24709
|
-
status: external_exports.enum(BulkSetScanningBranchResultStatusValues),
|
|
24710
|
-
relabeledVulnerabilityCount: external_exports.number().int().min(0).optional(),
|
|
24711
|
-
historyId: external_exports.uuid().nullable().optional(),
|
|
24712
|
-
errorMessage: external_exports.string().optional()
|
|
24713
|
-
});
|
|
24714
|
-
var BulkSetScanningBranchResponseSchema = external_exports.object({
|
|
24715
|
-
results: external_exports.array(BulkSetScanningBranchResultSchema)
|
|
24716
|
-
});
|
|
24717
|
-
var ScanningBranchPreferenceSchema = external_exports.object({
|
|
24718
|
-
autoConfigureScanningBranch: external_exports.boolean()
|
|
24719
|
-
});
|
|
24720
|
-
var ConfirmScanningBranchDefaultsResponseSchema = external_exports.object({
|
|
24721
|
-
autoConfigureScanningBranch: external_exports.literal(true),
|
|
24722
|
-
/** Repos the sweep configured to their default-branch mirror. */
|
|
24723
|
-
configuredCount: external_exports.number().int().min(0),
|
|
24724
|
-
/**
|
|
24725
|
-
* Rows skipped by the sweep's domain guards (empty or >255-char mirror).
|
|
24726
|
-
* They stay NULL and keep the "waiting on a scanning branch" banner alive.
|
|
24727
|
-
*/
|
|
24728
|
-
skippedCount: external_exports.number().int().min(0)
|
|
24729
|
-
});
|
|
24730
|
-
|
|
24731
|
-
// ../../packages/api-contracts/src/schemas/api/v1/application.api.ts
|
|
24732
|
-
var ApplicationTypeValues = ["WEB", "CLI", "MOBILE", "DESKTOP", "API_SERVICE"];
|
|
24733
|
-
var APPLICATION_NOTES_MAX_CHARS = 2e3;
|
|
24734
|
-
var ApplicationRepositoryRoleValues = [
|
|
24735
|
-
"FRONTEND",
|
|
24736
|
-
"BACKEND_API",
|
|
24737
|
-
"AUTH_SERVICE",
|
|
24738
|
-
"WORKER_JOB_SERVICE",
|
|
24739
|
-
"SHARED_PACKAGE_SDK",
|
|
24740
|
-
"INFRASTRUCTURE_IAC",
|
|
24741
|
-
"MOBILE_CLIENT",
|
|
24742
|
-
"MONOREPO",
|
|
24743
|
-
"OTHER"
|
|
24744
|
-
];
|
|
24745
|
-
var ApplicationIdParamsSchema = OrgIdParamsSchema.extend({
|
|
24746
|
-
applicationId: external_exports.uuid()
|
|
24747
|
-
});
|
|
24748
|
-
var ApplicationRepositoryIdParamsSchema = ApplicationIdParamsSchema.extend({
|
|
24749
|
-
applicationRepositoryId: external_exports.uuid()
|
|
24750
|
-
});
|
|
24751
|
-
var ApplicationRepositorySummarySchema = external_exports.object({
|
|
24752
|
-
applicationRepositoryId: external_exports.uuid().nullable(),
|
|
24753
|
-
applicationId: external_exports.uuid(),
|
|
24754
|
-
organizationId: external_exports.uuid(),
|
|
24755
|
-
repositoryId: external_exports.uuid(),
|
|
24756
|
-
repositoryName: external_exports.string(),
|
|
24757
|
-
repositoryUrl: external_exports.string(),
|
|
24758
|
-
repositoryStatus: external_exports.enum(RepositoryStatusValues),
|
|
24759
|
-
htmlUrl: external_exports.string().nullable(),
|
|
24760
|
-
createdAt: external_exports.date(),
|
|
24761
|
-
updatedAt: external_exports.date()
|
|
24762
|
-
});
|
|
24763
|
-
var ApplicationRepositoryRolesSchema = external_exports.array(external_exports.enum(ApplicationRepositoryRoleValues)).max(ApplicationRepositoryRoleValues.length);
|
|
24764
|
-
var ApplicationRepositoryLinkResponseSchema = ApplicationRepositorySummarySchema.extend({
|
|
24765
|
-
// First of `roles` (enum order), or null when unspecified. Kept so a new
|
|
24766
|
-
// client reading a pre-this-release API during a rolling deploy still parses.
|
|
24767
|
-
role: external_exports.enum(ApplicationRepositoryRoleValues).nullable(),
|
|
24768
|
-
// Source of truth. Defaulted empty so a new client reading a pre-this-release
|
|
24769
|
-
// API that omitted the field doesn't reject the row; the client then falls
|
|
24770
|
-
// back to wrapping `role`.
|
|
24771
|
-
roles: ApplicationRepositoryRolesSchema.default([]),
|
|
24772
|
-
roleLabel: external_exports.string().max(120).nullable(),
|
|
24773
|
-
repositoryPath: external_exports.string().max(500).nullable(),
|
|
24774
|
-
scanEnabled: external_exports.boolean()
|
|
24775
|
-
});
|
|
24776
|
-
var ListApplicationRepositoryLinksResponseSchema = external_exports.array(
|
|
24777
|
-
ApplicationRepositoryLinkResponseSchema
|
|
24778
|
-
);
|
|
24779
|
-
var ApplicationResponseSchema = external_exports.object({
|
|
24780
|
-
applicationId: external_exports.uuid(),
|
|
24781
|
-
organizationId: external_exports.uuid(),
|
|
24782
|
-
name: external_exports.string(),
|
|
24783
|
-
// `.default('WEB')` keeps responses backward-compatible: a pre-P1.3 API that
|
|
24784
|
-
// never emitted `type` parses cleanly (existing apps are semantically WEB),
|
|
24785
|
-
// so a new frontend reading an old API during a mixed-version rollout doesn't
|
|
24786
|
-
// reject application rows.
|
|
24787
|
-
type: external_exports.enum(ApplicationTypeValues).default("WEB"),
|
|
24788
|
-
applicationUrl: external_exports.string().nullable(),
|
|
24789
|
-
// Customer-authored free-text context, any type ("Advanced → Notes").
|
|
24790
|
-
notes: external_exports.string().nullable(),
|
|
24791
|
-
helpCenterUrl: external_exports.string().nullable(),
|
|
24792
|
-
documentationUrl: external_exports.string().nullable(),
|
|
24793
|
-
repositories: external_exports.array(ApplicationRepositorySummarySchema),
|
|
24794
|
-
// Registrable domains RECON is authorized to discover subdomains under. The
|
|
24795
|
-
// Environments-tab panel hydrates from this payload (no client GET). Defaulted
|
|
24796
|
-
// (like `type`) so a new client reading a pre-this-release API during a rolling
|
|
24797
|
-
// deploy doesn't reject application rows that predate the field.
|
|
24798
|
-
// Signed S3 URL for the Overview screenshot. Defaulted null so a new client
|
|
24799
|
-
// reading a pre-this-release API during a rolling deploy doesn't reject rows
|
|
24800
|
-
// that omit the field. The raw S3 key is never on the wire.
|
|
24801
|
-
screenshotUrl: external_exports.url().nullable().default(null),
|
|
24802
|
-
// Defaulted null so a new client reading a pre-this-release API during a
|
|
24803
|
-
// rolling deploy doesn't reject application rows that omit the field.
|
|
24804
|
-
credentialsNudgeDismissedAt: external_exports.date().nullable().default(null),
|
|
24805
|
-
createdAt: external_exports.date(),
|
|
24806
|
-
updatedAt: external_exports.date()
|
|
24807
|
-
});
|
|
24808
|
-
var ListApplicationsResponseSchema = external_exports.array(ApplicationResponseSchema);
|
|
24809
|
-
var CreateApplicationRequestSchema = external_exports.object({
|
|
24810
|
-
name: external_exports.string().min(1).max(200),
|
|
24811
|
-
type: external_exports.enum(ApplicationTypeValues).default("WEB"),
|
|
24812
|
-
applicationUrl: external_exports.url().max(2048).optional(),
|
|
24813
|
-
notes: external_exports.string().max(APPLICATION_NOTES_MAX_CHARS).optional(),
|
|
24814
|
-
repositoryId: external_exports.uuid().optional(),
|
|
24815
|
-
repositoryPath: external_exports.string().max(500).optional(),
|
|
24816
|
-
helpCenterUrl: external_exports.url().max(2048).optional(),
|
|
24817
|
-
documentationUrl: external_exports.url().max(2048).optional()
|
|
24818
|
-
}).strict().refine((data) => !isUrlBearingApplicationType(data.type) || data.applicationUrl != null, {
|
|
24819
|
-
path: ["applicationUrl"],
|
|
24820
|
-
message: "A web or API application requires an application URL."
|
|
24821
|
-
}).refine((data) => isUrlBearingApplicationType(data.type) || data.applicationUrl == null, {
|
|
24822
|
-
path: ["applicationUrl"],
|
|
24823
|
-
message: "Only web or API applications can have an application URL."
|
|
24824
|
-
});
|
|
24825
|
-
var CreateApplicationRepositoryLinkRequestSchema = external_exports.object({
|
|
24826
|
-
repositoryId: external_exports.uuid(),
|
|
24827
|
-
// Legacy single-role write. Ignored when `roles` is also sent.
|
|
24828
|
-
role: external_exports.enum(ApplicationRepositoryRoleValues).nullable().optional(),
|
|
24829
|
-
roles: ApplicationRepositoryRolesSchema.optional(),
|
|
24830
|
-
roleLabel: external_exports.string().max(120).nullable().optional(),
|
|
24831
|
-
repositoryPath: external_exports.string().max(500).nullable().optional(),
|
|
24832
|
-
scanEnabled: external_exports.boolean().optional()
|
|
24833
|
-
}).strict();
|
|
24834
|
-
var UpdateApplicationRepositoryLinkRequestSchema = external_exports.object({
|
|
24835
|
-
// Legacy single-role write. Ignored when `roles` is also sent.
|
|
24836
|
-
role: external_exports.enum(ApplicationRepositoryRoleValues).nullable().optional(),
|
|
24837
|
-
roles: ApplicationRepositoryRolesSchema.optional(),
|
|
24838
|
-
roleLabel: external_exports.string().max(120).nullable().optional(),
|
|
24839
|
-
repositoryPath: external_exports.string().max(500).nullable().optional(),
|
|
24840
|
-
scanEnabled: external_exports.boolean().optional()
|
|
24841
|
-
}).strict();
|
|
24842
|
-
var UpdateApplicationRequestSchema = external_exports.object({
|
|
24843
|
-
name: external_exports.string().min(1).max(200).optional(),
|
|
24844
|
-
applicationUrl: external_exports.url().max(2048).optional(),
|
|
24845
|
-
notes: external_exports.string().max(APPLICATION_NOTES_MAX_CHARS).nullable().optional(),
|
|
24846
|
-
repositoryId: external_exports.uuid().nullable().optional(),
|
|
24847
|
-
repositoryPath: external_exports.string().max(500).nullable().optional(),
|
|
24848
|
-
helpCenterUrl: external_exports.url().max(2048).nullable().optional(),
|
|
24849
|
-
documentationUrl: external_exports.url().max(2048).nullable().optional()
|
|
24850
|
-
}).strict();
|
|
24851
|
-
|
|
24852
24908
|
// ../../packages/api-contracts/src/schemas/api/v1/pentest.api.ts
|
|
24853
24909
|
var PentestIdParamsSchema = OrgIdParamsSchema.extend({
|
|
24854
24910
|
pentestId: external_exports.string().min(1)
|
|
@@ -25289,13 +25345,13 @@ var StorageStateSchema = external_exports.object({
|
|
|
25289
25345
|
} catch {
|
|
25290
25346
|
return;
|
|
25291
25347
|
}
|
|
25292
|
-
s.cookies.forEach((
|
|
25293
|
-
const d =
|
|
25348
|
+
s.cookies.forEach((c59, i2) => {
|
|
25349
|
+
const d = c59.domain.replace(/^\./, "").toLowerCase();
|
|
25294
25350
|
if (d !== host && !host.endsWith(`.${d}`)) {
|
|
25295
25351
|
ctx.addIssue({
|
|
25296
25352
|
code: "custom",
|
|
25297
25353
|
path: ["cookies", i2, "domain"],
|
|
25298
|
-
message: `cookie domain "${
|
|
25354
|
+
message: `cookie domain "${c59.domain}" is not the capture origin host "${host}" or a parent domain of it`
|
|
25299
25355
|
});
|
|
25300
25356
|
}
|
|
25301
25357
|
});
|
|
@@ -25993,7 +26049,19 @@ var AgentSessionLoginCodeResponseSchema = external_exports.object({
|
|
|
25993
26049
|
var AgentSessionTotpCodeRequestSchema = external_exports.object({
|
|
25994
26050
|
runVersion: external_exports.number().int().nonnegative(),
|
|
25995
26051
|
/** Which account (by `Credential.label`); omit if exactly one is enrolled. */
|
|
25996
|
-
credentialLabel: external_exports.string().min(1).max(200).optional()
|
|
26052
|
+
credentialLabel: external_exports.string().min(1).max(200).optional(),
|
|
26053
|
+
/**
|
|
26054
|
+
* Which account by ID, which is what a DESKTOP session holds.
|
|
26055
|
+
*
|
|
26056
|
+
* `Credential.label` is unique per ENVIRONMENT, not per pentest, so an
|
|
26057
|
+
* engagement spanning staging and production can carry two accounts labelled
|
|
26058
|
+
* `admin` and the label identifies neither. The desktop credential catalog
|
|
26059
|
+
* hands the agent an unambiguous id, and without this the only way to use an
|
|
26060
|
+
* enrolled desktop account was to ask staff to relabel one mid-engagement.
|
|
26061
|
+
*
|
|
26062
|
+
* Wins over `credentialLabel` when both are given.
|
|
26063
|
+
*/
|
|
26064
|
+
credentialId: external_exports.uuid().optional()
|
|
25997
26065
|
});
|
|
25998
26066
|
var AgentSessionTotpCodeResponseSchema = external_exports.object({
|
|
25999
26067
|
/** The account the code belongs to, echoed so the agent can name it. */
|
|
@@ -26393,17 +26461,9 @@ var OperatorRecordFindingRetestRequestSchema = CreatePentestFindingRetestRequest
|
|
|
26393
26461
|
runVersion: operatorRunVersion,
|
|
26394
26462
|
reason: operatorReason,
|
|
26395
26463
|
pentestFindingId: external_exports.uuid(),
|
|
26396
|
-
|
|
26397
|
-
|
|
26398
|
-
}).superRefine(
|
|
26399
|
-
if (v.outcome !== "FIXED" && v.verification !== void 0) {
|
|
26400
|
-
ctx.addIssue({
|
|
26401
|
-
code: "custom",
|
|
26402
|
-
message: "verification report prose is only allowed when outcome is FIXED",
|
|
26403
|
-
path: ["verification"]
|
|
26404
|
-
});
|
|
26405
|
-
}
|
|
26406
|
-
});
|
|
26464
|
+
// Widened from the dashboard's 3 values; `verification` comes from the base.
|
|
26465
|
+
outcome: RetestOutcome
|
|
26466
|
+
}).superRefine(retestVerificationOnlyOnFixed);
|
|
26407
26467
|
var OperatorRetestAckSchema = OperatorFindingReadSchema.extend({
|
|
26408
26468
|
retestId: external_exports.uuid()
|
|
26409
26469
|
});
|
|
@@ -26564,7 +26624,21 @@ var ReportSessionCoverSchema = external_exports.object({
|
|
|
26564
26624
|
classification: AttestationClassification,
|
|
26565
26625
|
documentId: external_exports.string(),
|
|
26566
26626
|
testingWindowStart: external_exports.string().nullable(),
|
|
26567
|
-
testingWindowEnd: external_exports.string().nullable()
|
|
26627
|
+
testingWindowEnd: external_exports.string().nullable(),
|
|
26628
|
+
/**
|
|
26629
|
+
* The engagement approach in the exact words the rendered document prints
|
|
26630
|
+
* ("white-box" / "authenticated grey-box" / "black-box", from the pentest's
|
|
26631
|
+
* `testType`).
|
|
26632
|
+
*
|
|
26633
|
+
* Here because the agent writing an Approach section otherwise cannot know it,
|
|
26634
|
+
* while the BSK document's methodology appendix prints it three paragraphs
|
|
26635
|
+
* later — one page apart and flatly contradictory in a partner deliverable.
|
|
26636
|
+
*
|
|
26637
|
+
* Optional for the reason the whole view is: the host reads this response with
|
|
26638
|
+
* a raw cast and no validation, so a host running against an older api would
|
|
26639
|
+
* read a required-typed field as `undefined`.
|
|
26640
|
+
*/
|
|
26641
|
+
approachLabel: external_exports.string().optional()
|
|
26568
26642
|
});
|
|
26569
26643
|
var ReportSessionViewSchema = external_exports.object({
|
|
26570
26644
|
rendered: external_exports.boolean(),
|
|
@@ -26575,7 +26649,19 @@ var ReportSessionViewSchema = external_exports.object({
|
|
|
26575
26649
|
keyThemes: external_exports.array(KeyThemeSchema)
|
|
26576
26650
|
}),
|
|
26577
26651
|
scopeRows: external_exports.array(ScopeRowSchema),
|
|
26578
|
-
updatedAt: external_exports.string().nullable()
|
|
26652
|
+
updatedAt: external_exports.string().nullable(),
|
|
26653
|
+
/** Which template this org's report renders with. Absent = TRACE (older api). */
|
|
26654
|
+
reportTemplate: PentestReportTemplateSchema.optional(),
|
|
26655
|
+
/**
|
|
26656
|
+
* The BSK partner narrative as stored; null when nothing is written, absent on
|
|
26657
|
+
* a TRACE org (or an older api).
|
|
26658
|
+
*
|
|
26659
|
+
* A section key ABSENT from `sections` has not been written yet. That is the
|
|
26660
|
+
* BSK agent's only channel for "which of my eight sections already exist", and
|
|
26661
|
+
* every write returns this view, so a follow-up or resumed session reads it
|
|
26662
|
+
* back rather than re-authoring all eight.
|
|
26663
|
+
*/
|
|
26664
|
+
partnerNarrative: PartnerNarrativeJsonSchema.nullable().optional()
|
|
26579
26665
|
});
|
|
26580
26666
|
var reportRunVersion = external_exports.number().int().nonnegative();
|
|
26581
26667
|
var reportReason = external_exports.string().min(1).max(2e3);
|
|
@@ -26587,8 +26673,8 @@ var ReportWriteSectionRequestSchema = external_exports.object({
|
|
|
26587
26673
|
runVersion: reportRunVersion,
|
|
26588
26674
|
reason: reportReason,
|
|
26589
26675
|
expectedUpdatedAt: reportExpectedUpdatedAt,
|
|
26590
|
-
section:
|
|
26591
|
-
content: external_exports.string().min(1).max(
|
|
26676
|
+
section: ReportWriteSectionId,
|
|
26677
|
+
content: external_exports.string().min(1).max(REPORT_SECTION_CONTENT_MAX_CHARS).optional(),
|
|
26592
26678
|
themes: external_exports.array(KeyThemeSchema).max(4).optional()
|
|
26593
26679
|
});
|
|
26594
26680
|
var ReportUpdateScopeRequestSchema = external_exports.object({
|
|
@@ -26602,13 +26688,24 @@ var RequestDesktopTargetRequestSchema = external_exports.object({
|
|
|
26602
26688
|
/** Only Windows exists; a literal keeps the macOS follow-on additive. */
|
|
26603
26689
|
platform: external_exports.literal("WINDOWS")
|
|
26604
26690
|
});
|
|
26691
|
+
var DesktopCredentialRefSchema = external_exports.object({
|
|
26692
|
+
credentialId: external_exports.uuid(),
|
|
26693
|
+
label: external_exports.string(),
|
|
26694
|
+
credentialType: external_exports.enum(CredentialTypeValues),
|
|
26695
|
+
environmentId: external_exports.uuid(),
|
|
26696
|
+
/** Present when the account has a second factor enrolled. `get_totp_code`
|
|
26697
|
+
* resolves by LABEL, which is not unique per pentest, so an enrolled desktop
|
|
26698
|
+
* account would otherwise dead-end. */
|
|
26699
|
+
mfaKind: CredentialMfaKind.nullable()
|
|
26700
|
+
});
|
|
26605
26701
|
var RequestDesktopTargetResponseSchema = external_exports.object({
|
|
26606
26702
|
desktopTargetId: external_exports.uuid(),
|
|
26607
26703
|
status: external_exports.enum(DesktopTargetStatusValues),
|
|
26608
26704
|
/** True when this session already owned a live box, so a second call in one
|
|
26609
26705
|
* assistant turn cannot bill a second instance. */
|
|
26610
26706
|
reused: external_exports.boolean(),
|
|
26611
|
-
screen: external_exports.object({ width: external_exports.number().int().positive(), height: external_exports.number().int().positive() })
|
|
26707
|
+
screen: external_exports.object({ width: external_exports.number().int().positive(), height: external_exports.number().int().positive() }),
|
|
26708
|
+
credentials: external_exports.array(DesktopCredentialRefSchema)
|
|
26612
26709
|
});
|
|
26613
26710
|
var DesktopTargetStatusRequestSchema = external_exports.object({
|
|
26614
26711
|
runVersion: external_exports.number().int().min(0),
|
|
@@ -26654,7 +26751,15 @@ var DesktopActionViewSchema = external_exports.object({
|
|
|
26654
26751
|
* so a caller-chosen name is how an unredacted clip would publish as a
|
|
26655
26752
|
* customer-facing screenshot.
|
|
26656
26753
|
*/
|
|
26657
|
-
artifactName: external_exports.string().max(256).nullable()
|
|
26754
|
+
artifactName: external_exports.string().max(256).nullable(),
|
|
26755
|
+
/**
|
|
26756
|
+
* Shape-only reason a FAILED action carries. Load-bearing for `type_secret`:
|
|
26757
|
+
* claim-time substitution fails the action with one of three codes
|
|
26758
|
+
* (`credential_not_found`, `credential_field_absent`, `decrypt_failed`), and
|
|
26759
|
+
* without this projection the agent could not tell those apart from a box
|
|
26760
|
+
* that crashed.
|
|
26761
|
+
*/
|
|
26762
|
+
failureDetails: external_exports.string().nullable()
|
|
26658
26763
|
});
|
|
26659
26764
|
var ReadDesktopActionRequestSchema = external_exports.object({
|
|
26660
26765
|
runVersion: external_exports.number().int().min(0),
|
|
@@ -31977,7 +32082,8 @@ var OrgCapabilityValues = [
|
|
|
31977
32082
|
"SCAN_SECRETS",
|
|
31978
32083
|
"SCAN_DAST",
|
|
31979
32084
|
"AUTO_PR_SCANS",
|
|
31980
|
-
"AUTO_PUSH_SCANS"
|
|
32085
|
+
"AUTO_PUSH_SCANS",
|
|
32086
|
+
"PENTEST_FINDING_AUTOMATION"
|
|
31981
32087
|
];
|
|
31982
32088
|
var UpdateOrganizationRequestSchema = external_exports.object({
|
|
31983
32089
|
name: external_exports.string().min(1).max(255).optional(),
|
|
@@ -34270,6 +34376,28 @@ var pentestFindingContract = c35.router({
|
|
|
34270
34376
|
500: ErrorResponseSchema
|
|
34271
34377
|
}
|
|
34272
34378
|
},
|
|
34379
|
+
// ─── Automation lifecycle transition (API keys) ───
|
|
34380
|
+
// A separate route rather than a widened `start-progress` / `report-remediation`:
|
|
34381
|
+
// those stay human-only, and everything that makes a machine-driven write
|
|
34382
|
+
// different lives here. API-key principals only, gated on the org owning
|
|
34383
|
+
// PENTEST_FINDING_AUTOMATION, and audited as API_KEY with the key's name.
|
|
34384
|
+
automationStatusUpdate: {
|
|
34385
|
+
method: "POST",
|
|
34386
|
+
path: "/organizations/:organizationId/customer-pentests/:pentestId/findings/:pentestFindingId/automation/status",
|
|
34387
|
+
pathParams: CustomerPentestFindingIdParamsSchema,
|
|
34388
|
+
body: AutomationStatusUpdateRequestSchema,
|
|
34389
|
+
responses: {
|
|
34390
|
+
200: CustomerPentestFindingResponseSchema,
|
|
34391
|
+
400: ErrorResponseSchema,
|
|
34392
|
+
401: ErrorResponseSchema,
|
|
34393
|
+
403: ErrorResponseSchema,
|
|
34394
|
+
404: ErrorResponseSchema,
|
|
34395
|
+
// FINDING_TRANSITION_NOT_ALLOWED (bad source status), FINDING_STALE
|
|
34396
|
+
// (concurrent write), or PENTEST_CLOSED.
|
|
34397
|
+
409: ErrorResponseSchema,
|
|
34398
|
+
500: ErrorResponseSchema
|
|
34399
|
+
}
|
|
34400
|
+
},
|
|
34273
34401
|
// Customer opens a dispute (PR 3) → finding status CONTESTED. Same auth as the
|
|
34274
34402
|
// other customer transitions (VIEW_RESULTS + user principal + customer visibility).
|
|
34275
34403
|
contest: {
|
|
@@ -34362,7 +34490,7 @@ var pentestFindingContract = c35.router({
|
|
|
34362
34490
|
method: "POST",
|
|
34363
34491
|
path: "/organizations/:organizationId/pentests/:pentestId/findings/:pentestFindingId/retests",
|
|
34364
34492
|
pathParams: PentestFindingIdParamsSchema,
|
|
34365
|
-
body:
|
|
34493
|
+
body: CreatePentestFindingRetestBodySchema,
|
|
34366
34494
|
responses: {
|
|
34367
34495
|
201: PentestFindingRetestResponseSchema,
|
|
34368
34496
|
400: ErrorResponseSchema,
|
|
@@ -35466,6 +35594,128 @@ var staffPentestStatsContract = c42.router({
|
|
|
35466
35594
|
}
|
|
35467
35595
|
});
|
|
35468
35596
|
|
|
35597
|
+
// ../../packages/api-contracts/src/schemas/api/v1/staff-queue.api.ts
|
|
35598
|
+
var StaffQueueItemKindValues = [
|
|
35599
|
+
"RETEST_OWED",
|
|
35600
|
+
"CONTESTED",
|
|
35601
|
+
"SESSION_WAITING",
|
|
35602
|
+
"SESSION_FAILED",
|
|
35603
|
+
"REVIEW_GATE",
|
|
35604
|
+
"INTAKE_SUBMITTED"
|
|
35605
|
+
];
|
|
35606
|
+
var StaffQueueItemKind = external_exports.enum(StaffQueueItemKindValues);
|
|
35607
|
+
var STAFF_QUEUE_EXCERPT_MAX = 280;
|
|
35608
|
+
var since = external_exports.iso.datetime();
|
|
35609
|
+
var findingIdentity = {
|
|
35610
|
+
pentestFindingId: external_exports.uuid(),
|
|
35611
|
+
/** Null until published; the finding is then named by title alone. */
|
|
35612
|
+
displayId: external_exports.int().positive().nullable(),
|
|
35613
|
+
title: external_exports.string(),
|
|
35614
|
+
severity: PentestFindingSeverity,
|
|
35615
|
+
/** False for a finding the customer has never seen; they are not the one waiting. */
|
|
35616
|
+
published: external_exports.boolean()
|
|
35617
|
+
};
|
|
35618
|
+
var StaffQueueRetestOwedItemSchema = external_exports.object({
|
|
35619
|
+
kind: external_exports.literal("RETEST_OWED"),
|
|
35620
|
+
since,
|
|
35621
|
+
...findingIdentity,
|
|
35622
|
+
/** The most recent automatic retest, when one ran and did not settle it. */
|
|
35623
|
+
lastAutoRetest: external_exports.object({ outcome: RetestOutcome, testedAt: external_exports.iso.datetime() }).nullable()
|
|
35624
|
+
}).strict();
|
|
35625
|
+
var StaffQueueContestedItemSchema = external_exports.object({
|
|
35626
|
+
kind: external_exports.literal("CONTESTED"),
|
|
35627
|
+
since,
|
|
35628
|
+
...findingIdentity,
|
|
35629
|
+
/** The open contest row. Null only if a finding is CONTESTED with no open row. */
|
|
35630
|
+
contest: external_exports.object({
|
|
35631
|
+
reason: ContestReason,
|
|
35632
|
+
justification: external_exports.string().max(STAFF_QUEUE_EXCERPT_MAX),
|
|
35633
|
+
contestedBy: external_exports.string()
|
|
35634
|
+
}).strict().nullable()
|
|
35635
|
+
}).strict();
|
|
35636
|
+
var StaffQueueSessionWaitingItemSchema = external_exports.object({
|
|
35637
|
+
kind: external_exports.literal("SESSION_WAITING"),
|
|
35638
|
+
since,
|
|
35639
|
+
agentSessionId: external_exports.uuid(),
|
|
35640
|
+
sessionType: AgentSessionType,
|
|
35641
|
+
waitingReason: AgentSessionWaitingReason.nullable(),
|
|
35642
|
+
/** The console's session list names sessions by objective, so the row carries it. */
|
|
35643
|
+
objective: external_exports.string().max(STAFF_QUEUE_EXCERPT_MAX),
|
|
35644
|
+
/** The agent's question when the park carries one. */
|
|
35645
|
+
question: external_exports.string().max(STAFF_QUEUE_EXCERPT_MAX).nullable()
|
|
35646
|
+
}).strict();
|
|
35647
|
+
var StaffQueueSessionFailedItemSchema = external_exports.object({
|
|
35648
|
+
kind: external_exports.literal("SESSION_FAILED"),
|
|
35649
|
+
since,
|
|
35650
|
+
agentSessionId: external_exports.uuid(),
|
|
35651
|
+
sessionType: AgentSessionType,
|
|
35652
|
+
objective: external_exports.string().max(STAFF_QUEUE_EXCERPT_MAX),
|
|
35653
|
+
failureReason: AgentSessionFailureReason.nullable()
|
|
35654
|
+
}).strict();
|
|
35655
|
+
var StaffQueueReviewGateItemSchema = external_exports.object({
|
|
35656
|
+
kind: external_exports.literal("REVIEW_GATE"),
|
|
35657
|
+
since,
|
|
35658
|
+
stage: PentestStage
|
|
35659
|
+
}).strict();
|
|
35660
|
+
var StaffQueueIntakeSubmittedItemSchema = external_exports.object({
|
|
35661
|
+
kind: external_exports.literal("INTAKE_SUBMITTED"),
|
|
35662
|
+
since
|
|
35663
|
+
}).strict();
|
|
35664
|
+
var StaffQueueItemSchema = external_exports.discriminatedUnion("kind", [
|
|
35665
|
+
StaffQueueRetestOwedItemSchema,
|
|
35666
|
+
StaffQueueContestedItemSchema,
|
|
35667
|
+
StaffQueueSessionWaitingItemSchema,
|
|
35668
|
+
StaffQueueSessionFailedItemSchema,
|
|
35669
|
+
StaffQueueReviewGateItemSchema,
|
|
35670
|
+
StaffQueueIntakeSubmittedItemSchema
|
|
35671
|
+
]);
|
|
35672
|
+
var StaffQueueEngagementSchema = external_exports.object({
|
|
35673
|
+
organization: external_exports.object({
|
|
35674
|
+
organizationId: external_exports.uuid(),
|
|
35675
|
+
slug: external_exports.string(),
|
|
35676
|
+
name: external_exports.string(),
|
|
35677
|
+
logoUrl: external_exports.string().nullable(),
|
|
35678
|
+
darkModeLogoUrl: external_exports.string().nullable()
|
|
35679
|
+
}).strict(),
|
|
35680
|
+
pentest: external_exports.object({
|
|
35681
|
+
pentestId: external_exports.uuid(),
|
|
35682
|
+
displayId: external_exports.int().positive(),
|
|
35683
|
+
title: external_exports.string(),
|
|
35684
|
+
status: PentestStatus,
|
|
35685
|
+
currentStage: PentestStage
|
|
35686
|
+
}).strict(),
|
|
35687
|
+
/** Oldest first within the engagement. */
|
|
35688
|
+
items: external_exports.array(StaffQueueItemSchema).min(1),
|
|
35689
|
+
/** The `since` of the oldest item; engagements sort by it ascending. */
|
|
35690
|
+
oldestSince: external_exports.iso.datetime()
|
|
35691
|
+
}).strict();
|
|
35692
|
+
var StaffQueueCountsSchema = external_exports.object(
|
|
35693
|
+
Object.fromEntries(StaffQueueItemKindValues.map((kind) => [kind, external_exports.int().nonnegative()]))
|
|
35694
|
+
).strict();
|
|
35695
|
+
var StaffQueueResponseSchema = external_exports.object({
|
|
35696
|
+
generatedAt: external_exports.iso.datetime(),
|
|
35697
|
+
/** Non-deleted, non-closed pentests considered, so an empty queue can prove the query ran. */
|
|
35698
|
+
liveEngagementCount: external_exports.int().nonnegative(),
|
|
35699
|
+
counts: StaffQueueCountsSchema,
|
|
35700
|
+
engagements: external_exports.array(StaffQueueEngagementSchema)
|
|
35701
|
+
}).strict();
|
|
35702
|
+
|
|
35703
|
+
// ../../packages/api-contracts/src/contracts/v1/staff-queue.ts
|
|
35704
|
+
var c43 = initContract();
|
|
35705
|
+
var staffQueueContract = c43.router({
|
|
35706
|
+
getStaffQueue: {
|
|
35707
|
+
method: "GET",
|
|
35708
|
+
path: "/staff/queue",
|
|
35709
|
+
responses: {
|
|
35710
|
+
200: StaffQueueResponseSchema,
|
|
35711
|
+
401: ErrorResponseSchema,
|
|
35712
|
+
403: ErrorResponseSchema,
|
|
35713
|
+
500: ErrorResponseSchema
|
|
35714
|
+
},
|
|
35715
|
+
summary: "Engagements where the next move is staff\u2019s, grouped by engagement"
|
|
35716
|
+
}
|
|
35717
|
+
});
|
|
35718
|
+
|
|
35469
35719
|
// ../../packages/api-contracts/src/schemas/api/v1/test-integration.api.ts
|
|
35470
35720
|
var NOTES_MAX = 2e3;
|
|
35471
35721
|
var TestIntegrationIdParamsSchema = external_exports.object({
|
|
@@ -35522,8 +35772,8 @@ var AttachTestIntegrationRequestSchema = external_exports.object({
|
|
|
35522
35772
|
}).strict();
|
|
35523
35773
|
|
|
35524
35774
|
// ../../packages/api-contracts/src/contracts/v1/test-integration.ts
|
|
35525
|
-
var
|
|
35526
|
-
var testIntegrationContract =
|
|
35775
|
+
var c44 = initContract();
|
|
35776
|
+
var testIntegrationContract = c44.router({
|
|
35527
35777
|
// -- Fixture CRUD (org-less, staff-only) ----------------------------------
|
|
35528
35778
|
listTestIntegrations: {
|
|
35529
35779
|
method: "GET",
|
|
@@ -35655,8 +35905,8 @@ var MyContextResponseSchema = external_exports.object({
|
|
|
35655
35905
|
});
|
|
35656
35906
|
|
|
35657
35907
|
// ../../packages/api-contracts/src/contracts/v1/user.ts
|
|
35658
|
-
var
|
|
35659
|
-
var userContract =
|
|
35908
|
+
var c45 = initContract();
|
|
35909
|
+
var userContract = c45.router({
|
|
35660
35910
|
getStaffProfile: {
|
|
35661
35911
|
method: "GET",
|
|
35662
35912
|
path: "/staff/profile",
|
|
@@ -35771,8 +36021,8 @@ var VantaIntegrationResponseSchema = external_exports.object({
|
|
|
35771
36021
|
});
|
|
35772
36022
|
|
|
35773
36023
|
// ../../packages/api-contracts/src/contracts/v1/vanta-integration.ts
|
|
35774
|
-
var
|
|
35775
|
-
var vantaIntegrationContract =
|
|
36024
|
+
var c46 = initContract();
|
|
36025
|
+
var vantaIntegrationContract = c46.router({
|
|
35776
36026
|
createVantaIntegration: {
|
|
35777
36027
|
method: "POST",
|
|
35778
36028
|
path: "/organizations/:organizationId/vanta-integration",
|
|
@@ -36104,8 +36354,8 @@ var VerifySharedVulnerabilityEmailCodeResponseSchema = external_exports.object({
|
|
|
36104
36354
|
});
|
|
36105
36355
|
|
|
36106
36356
|
// ../../packages/api-contracts/src/contracts/v1/vulnerability.ts
|
|
36107
|
-
var
|
|
36108
|
-
var vulnerabilityContract =
|
|
36357
|
+
var c47 = initContract();
|
|
36358
|
+
var vulnerabilityContract = c47.router({
|
|
36109
36359
|
filterVulnerabilities: {
|
|
36110
36360
|
method: "POST",
|
|
36111
36361
|
path: "/organizations/:organizationId/vulnerabilities/filter",
|
|
@@ -36313,8 +36563,8 @@ var UpdateVulnerabilityNoteRequestSchema = external_exports.object({
|
|
|
36313
36563
|
});
|
|
36314
36564
|
|
|
36315
36565
|
// ../../packages/api-contracts/src/contracts/v1/vulnerability-note.ts
|
|
36316
|
-
var
|
|
36317
|
-
var vulnerabilityNoteContract =
|
|
36566
|
+
var c48 = initContract();
|
|
36567
|
+
var vulnerabilityNoteContract = c48.router({
|
|
36318
36568
|
listNotes: {
|
|
36319
36569
|
method: "GET",
|
|
36320
36570
|
path: "/organizations/:organizationId/vulnerabilities/:vulnerabilityId/notes",
|
|
@@ -36495,8 +36745,8 @@ var ListWebhookDeliveriesResponseSchema = external_exports.object({
|
|
|
36495
36745
|
});
|
|
36496
36746
|
|
|
36497
36747
|
// ../../packages/api-contracts/src/contracts/v1/webhook-settings.ts
|
|
36498
|
-
var
|
|
36499
|
-
var webhookSettingsContract =
|
|
36748
|
+
var c49 = initContract();
|
|
36749
|
+
var webhookSettingsContract = c49.router({
|
|
36500
36750
|
listWebhookEndpoints: {
|
|
36501
36751
|
method: "GET",
|
|
36502
36752
|
path: "/organizations/:organizationId/webhook-settings/endpoints",
|
|
@@ -36634,8 +36884,8 @@ var webhookSettingsContract = c48.router({
|
|
|
36634
36884
|
});
|
|
36635
36885
|
|
|
36636
36886
|
// ../../packages/api-contracts/src/contracts/v1/index.ts
|
|
36637
|
-
var
|
|
36638
|
-
var v1Contract =
|
|
36887
|
+
var c50 = initContract();
|
|
36888
|
+
var v1Contract = c50.router(
|
|
36639
36889
|
{
|
|
36640
36890
|
admin: adminContract,
|
|
36641
36891
|
cloudIntegration: cloudIntegrationContract,
|
|
@@ -36684,7 +36934,8 @@ var v1Contract = c49.router(
|
|
|
36684
36934
|
engagement: engagementContract,
|
|
36685
36935
|
testIntegration: testIntegrationContract,
|
|
36686
36936
|
pentestEgress: pentestEgressContract,
|
|
36687
|
-
staffPentestStats: staffPentestStatsContract
|
|
36937
|
+
staffPentestStats: staffPentestStatsContract,
|
|
36938
|
+
staffQueue: staffQueueContract
|
|
36688
36939
|
},
|
|
36689
36940
|
{
|
|
36690
36941
|
pathPrefix: "/v1"
|
|
@@ -36692,8 +36943,8 @@ var v1Contract = c49.router(
|
|
|
36692
36943
|
);
|
|
36693
36944
|
|
|
36694
36945
|
// ../../packages/api-contracts/src/contracts/index.ts
|
|
36695
|
-
var
|
|
36696
|
-
var contract =
|
|
36946
|
+
var c51 = initContract();
|
|
36947
|
+
var contract = c51.router({
|
|
36697
36948
|
v1: v1Contract
|
|
36698
36949
|
});
|
|
36699
36950
|
|
|
@@ -36703,8 +36954,8 @@ var GitHubWebhookResponseSchema = external_exports.object({
|
|
|
36703
36954
|
});
|
|
36704
36955
|
|
|
36705
36956
|
// ../../packages/api-contracts/src/contracts/webhooks/github.ts
|
|
36706
|
-
var
|
|
36707
|
-
var githubWebhookContract =
|
|
36957
|
+
var c52 = initContract();
|
|
36958
|
+
var githubWebhookContract = c52.router(
|
|
36708
36959
|
{
|
|
36709
36960
|
handleWebhook: {
|
|
36710
36961
|
method: "POST",
|
|
@@ -36722,7 +36973,7 @@ var githubWebhookContract = c51.router(
|
|
|
36722
36973
|
pathPrefix: "/webhooks"
|
|
36723
36974
|
}
|
|
36724
36975
|
);
|
|
36725
|
-
var githubReadonlyWebhookContract =
|
|
36976
|
+
var githubReadonlyWebhookContract = c52.router(
|
|
36726
36977
|
{
|
|
36727
36978
|
handleWebhook: {
|
|
36728
36979
|
method: "POST",
|
|
@@ -36742,9 +36993,9 @@ var githubReadonlyWebhookContract = c51.router(
|
|
|
36742
36993
|
);
|
|
36743
36994
|
|
|
36744
36995
|
// ../../packages/api-contracts/src/contracts/webhooks/linear.ts
|
|
36745
|
-
var
|
|
36996
|
+
var c53 = initContract();
|
|
36746
36997
|
var LinearWebhookResponseSchema = external_exports.object({ ok: external_exports.boolean() });
|
|
36747
|
-
var linearWebhookContract =
|
|
36998
|
+
var linearWebhookContract = c53.router(
|
|
36748
36999
|
{
|
|
36749
37000
|
handleWebhook: {
|
|
36750
37001
|
method: "POST",
|
|
@@ -36764,7 +37015,7 @@ var linearWebhookContract = c52.router(
|
|
|
36764
37015
|
);
|
|
36765
37016
|
|
|
36766
37017
|
// ../../packages/api-contracts/src/contracts/forge/bitbucket.ts
|
|
36767
|
-
var
|
|
37018
|
+
var c54 = initContract();
|
|
36768
37019
|
var InstallEventSchema = external_exports.object({
|
|
36769
37020
|
eventType: external_exports.enum(["avi:forge:installed:app", "avi:forge:upgraded:app"]),
|
|
36770
37021
|
context: external_exports.object({ cloudId: external_exports.string().min(1) }).loose(),
|
|
@@ -36793,7 +37044,7 @@ var ForgePairingCodeResponseSchema = external_exports.discriminatedUnion("state"
|
|
|
36793
37044
|
expiresInSeconds: external_exports.number().int()
|
|
36794
37045
|
})
|
|
36795
37046
|
]);
|
|
36796
|
-
var forgeBitbucketContract =
|
|
37047
|
+
var forgeBitbucketContract = c54.router(
|
|
36797
37048
|
{
|
|
36798
37049
|
lifecycle: {
|
|
36799
37050
|
method: "POST",
|
|
@@ -36840,8 +37091,8 @@ var HealthResponseSchema = external_exports.object({
|
|
|
36840
37091
|
});
|
|
36841
37092
|
|
|
36842
37093
|
// ../../packages/api-contracts/src/contracts/health.ts
|
|
36843
|
-
var
|
|
36844
|
-
var healthContract =
|
|
37094
|
+
var c55 = initContract();
|
|
37095
|
+
var healthContract = c55.router({
|
|
36845
37096
|
getHealth: {
|
|
36846
37097
|
method: "GET",
|
|
36847
37098
|
path: "/health",
|
|
@@ -36853,8 +37104,8 @@ var healthContract = c54.router({
|
|
|
36853
37104
|
});
|
|
36854
37105
|
|
|
36855
37106
|
// ../../packages/api-contracts/src/contracts/v1/vulnerability-share.ts
|
|
36856
|
-
var
|
|
36857
|
-
var vulnerabilityShareContract =
|
|
37107
|
+
var c56 = initContract();
|
|
37108
|
+
var vulnerabilityShareContract = c56.router(
|
|
36858
37109
|
{
|
|
36859
37110
|
resolveShareLink: {
|
|
36860
37111
|
method: "GET",
|
|
@@ -36941,8 +37192,8 @@ var UpdatePrVulnerabilityRequestSchema = external_exports.object({
|
|
|
36941
37192
|
});
|
|
36942
37193
|
|
|
36943
37194
|
// ../../packages/api-contracts/src/contracts/v1/pr-vulnerability.ts
|
|
36944
|
-
var
|
|
36945
|
-
var prVulnerabilityContract =
|
|
37195
|
+
var c57 = initContract();
|
|
37196
|
+
var prVulnerabilityContract = c57.router(
|
|
36946
37197
|
{
|
|
36947
37198
|
listPrVulnerabilities: {
|
|
36948
37199
|
method: "GET",
|
|
@@ -37678,18 +37929,18 @@ var proto = Object.defineProperties(() => {
|
|
|
37678
37929
|
}
|
|
37679
37930
|
}
|
|
37680
37931
|
});
|
|
37681
|
-
var createStyler = (
|
|
37932
|
+
var createStyler = (open2, close, parent) => {
|
|
37682
37933
|
let openAll;
|
|
37683
37934
|
let closeAll;
|
|
37684
37935
|
if (parent === void 0) {
|
|
37685
|
-
openAll =
|
|
37936
|
+
openAll = open2;
|
|
37686
37937
|
closeAll = close;
|
|
37687
37938
|
} else {
|
|
37688
|
-
openAll = parent.openAll +
|
|
37939
|
+
openAll = parent.openAll + open2;
|
|
37689
37940
|
closeAll = close + parent.closeAll;
|
|
37690
37941
|
}
|
|
37691
37942
|
return {
|
|
37692
|
-
open,
|
|
37943
|
+
open: open2,
|
|
37693
37944
|
close,
|
|
37694
37945
|
openAll,
|
|
37695
37946
|
closeAll,
|
|
@@ -37811,6 +38062,10 @@ function getApiBaseUrl() {
|
|
|
37811
38062
|
}
|
|
37812
38063
|
return raw.replace(/\/+$/, "");
|
|
37813
38064
|
}
|
|
38065
|
+
function requireAuth() {
|
|
38066
|
+
const credential = loadCredentialOrExit();
|
|
38067
|
+
return { token: credential.token, kind: credential.kind };
|
|
38068
|
+
}
|
|
37814
38069
|
function loadCredentialOrExit() {
|
|
37815
38070
|
const credential = resolveCredentialOrExit();
|
|
37816
38071
|
if (!credential) {
|
|
@@ -39404,6 +39659,7 @@ function sanitizeDisplay(value) {
|
|
|
39404
39659
|
}
|
|
39405
39660
|
var SUCCESS_STATUS = 200;
|
|
39406
39661
|
var CREATED_STATUS = 201;
|
|
39662
|
+
var ACCEPTED_STATUS = 202;
|
|
39407
39663
|
var NO_CONTENT_STATUS = 204;
|
|
39408
39664
|
var UNAUTHORIZED_STATUS2 = 401;
|
|
39409
39665
|
function parseOutput(value) {
|
|
@@ -39646,12 +39902,12 @@ function buildApplicationsTable(apps) {
|
|
|
39646
39902
|
repos: String(a2.repositories.length),
|
|
39647
39903
|
url: a2.applicationUrl ? sanitizeDisplay(a2.applicationUrl) : "\u2014"
|
|
39648
39904
|
}));
|
|
39649
|
-
const idWidth = Math.max(2, ...cells.map((
|
|
39650
|
-
const nameWidth = Math.max(4, ...cells.map((
|
|
39651
|
-
const typeWidth = Math.max(4, ...cells.map((
|
|
39905
|
+
const idWidth = Math.max(2, ...cells.map((c59) => c59.id.length));
|
|
39906
|
+
const nameWidth = Math.max(4, ...cells.map((c59) => c59.name.length));
|
|
39907
|
+
const typeWidth = Math.max(4, ...cells.map((c59) => c59.type.length));
|
|
39652
39908
|
const header = `${"ID".padEnd(idWidth)} ${"NAME".padEnd(nameWidth)} ${"TYPE".padEnd(typeWidth)} REPOS URL`;
|
|
39653
39909
|
const rows = cells.map(
|
|
39654
|
-
(
|
|
39910
|
+
(c59) => `${c59.id.padEnd(idWidth)} ${c59.name.padEnd(nameWidth)} ${c59.type.padEnd(typeWidth)} ${c59.repos.padStart(5)} ${c59.url}`
|
|
39655
39911
|
);
|
|
39656
39912
|
return { header, rows };
|
|
39657
39913
|
}
|
|
@@ -39671,12 +39927,12 @@ function buildApplicationRepositoriesTable(links) {
|
|
|
39671
39927
|
path: l2.repositoryPath ? sanitizeDisplay(l2.repositoryPath) : "\u2014",
|
|
39672
39928
|
status: formatStatus(l2.repositoryStatus)
|
|
39673
39929
|
}));
|
|
39674
|
-
const nameWidth = Math.max(10, ...cells.map((
|
|
39675
|
-
const roleWidth = Math.max(4, ...cells.map((
|
|
39676
|
-
const pathWidth = Math.max(4, ...cells.map((
|
|
39930
|
+
const nameWidth = Math.max(10, ...cells.map((c59) => c59.name.length));
|
|
39931
|
+
const roleWidth = Math.max(4, ...cells.map((c59) => c59.role.length));
|
|
39932
|
+
const pathWidth = Math.max(4, ...cells.map((c59) => c59.path.length));
|
|
39677
39933
|
const header = `${"REPOSITORY".padEnd(nameWidth)} SCAN ${"ROLE".padEnd(roleWidth)} ${"PATH".padEnd(pathWidth)} STATUS`;
|
|
39678
39934
|
const rows = cells.map(
|
|
39679
|
-
(
|
|
39935
|
+
(c59) => `${c59.name.padEnd(nameWidth)} ${c59.scan.padEnd(4)} ${c59.role.padEnd(roleWidth)} ${c59.path.padEnd(pathWidth)} ${c59.status}`
|
|
39680
39936
|
);
|
|
39681
39937
|
return { header, rows };
|
|
39682
39938
|
}
|
|
@@ -40461,8 +40717,8 @@ function wrapTextWithPrefix(e, r2, o2, t2 = o2, s = o2, n3) {
|
|
|
40461
40717
|
hard: true,
|
|
40462
40718
|
trim: false
|
|
40463
40719
|
}).split(`
|
|
40464
|
-
`).map((
|
|
40465
|
-
const d = n3 ? n3(
|
|
40720
|
+
`).map((c59, i2, m2) => {
|
|
40721
|
+
const d = n3 ? n3(c59, i2) : c59;
|
|
40466
40722
|
return i2 === 0 ? `${t2}${d}` : i2 === m2.length - 1 ? `${s}${d}` : `${o2}${d}`;
|
|
40467
40723
|
}).join(`
|
|
40468
40724
|
`);
|
|
@@ -40960,14 +41216,14 @@ var limitOptions = ({
|
|
|
40960
41216
|
Math.min(l2 - a2 + 3, e.length - a2),
|
|
40961
41217
|
0
|
|
40962
41218
|
));
|
|
40963
|
-
let d = a2 < e.length && f > 0,
|
|
41219
|
+
let d = a2 < e.length && f > 0, c59 = a2 < e.length && f + a2 < e.length;
|
|
40964
41220
|
const W = Math.min(
|
|
40965
41221
|
f + a2,
|
|
40966
41222
|
e.length
|
|
40967
41223
|
), s = [];
|
|
40968
41224
|
let g = 0;
|
|
40969
|
-
d && g++,
|
|
40970
|
-
const T = f + (d ? 1 : 0), y = W - (
|
|
41225
|
+
d && g++, c59 && g++;
|
|
41226
|
+
const T = f + (d ? 1 : 0), y = W - (c59 ? 1 : 0);
|
|
40971
41227
|
for (let t2 = T; t2 < y; t2++) {
|
|
40972
41228
|
const n3 = e[t2], o2 = n3 ? w(n3, t2 === l2) : "", h2 = wrapAnsi(o2, i2, {
|
|
40973
41229
|
hard: true,
|
|
@@ -40988,14 +41244,14 @@ var limitOptions = ({
|
|
|
40988
41244
|
u4,
|
|
40989
41245
|
true
|
|
40990
41246
|
);
|
|
40991
|
-
d ? ({ lineCount: o2, removals: t2 } = L(), o2 > u4 && (
|
|
41247
|
+
d ? ({ lineCount: o2, removals: t2 } = L(), o2 > u4 && (c59 || (u4 -= 1), { lineCount: o2, removals: n3 } = E())) : (c59 || (u4 -= 1), { lineCount: o2, removals: n3 } = E(), o2 > u4 && (u4 -= 1, { lineCount: o2, removals: t2 } = L())), t2 > 0 && (d = true, s.splice(0, t2)), n3 > 0 && (c59 = true, s.splice(s.length - n3, n3));
|
|
40992
41248
|
}
|
|
40993
41249
|
const x = [];
|
|
40994
41250
|
d && x.push(M);
|
|
40995
41251
|
for (const t2 of s)
|
|
40996
41252
|
for (const n3 of t2)
|
|
40997
41253
|
x.push(n3);
|
|
40998
|
-
return
|
|
41254
|
+
return c59 && x.push(M), x;
|
|
40999
41255
|
};
|
|
41000
41256
|
var confirm = (i2) => {
|
|
41001
41257
|
const a2 = i2.active ?? "Yes", s = i2.inactive ?? "No";
|
|
@@ -41014,15 +41270,15 @@ var confirm = (i2) => {
|
|
|
41014
41270
|
u4
|
|
41015
41271
|
), o2 = `${e ? `${styleText2("gray", S_BAR)}
|
|
41016
41272
|
` : ""}${f}
|
|
41017
|
-
`,
|
|
41273
|
+
`, c59 = this.value ? a2 : s;
|
|
41018
41274
|
switch (this.state) {
|
|
41019
41275
|
case "submit": {
|
|
41020
41276
|
const r2 = e ? `${styleText2("gray", S_BAR)} ` : "";
|
|
41021
|
-
return `${o2}${r2}${styleText2("dim",
|
|
41277
|
+
return `${o2}${r2}${styleText2("dim", c59)}`;
|
|
41022
41278
|
}
|
|
41023
41279
|
case "cancel": {
|
|
41024
41280
|
const r2 = e ? `${styleText2("gray", S_BAR)} ` : "";
|
|
41025
|
-
return `${o2}${r2}${styleText2(["strikethrough", "dim"],
|
|
41281
|
+
return `${o2}${r2}${styleText2(["strikethrough", "dim"], c59)}${e ? `
|
|
41026
41282
|
${styleText2("gray", S_BAR)}` : ""}`;
|
|
41027
41283
|
}
|
|
41028
41284
|
default: {
|
|
@@ -41170,13 +41426,13 @@ var multiline = (e) => new h({
|
|
|
41170
41426
|
`, m2 = e.placeholder && e.placeholder.length > 0 ? (
|
|
41171
41427
|
// biome-ignore lint/style/noNonNullAssertion: guarded by placeholder.length > 0
|
|
41172
41428
|
styleText2("inverse", e.placeholder[0]) + styleText2("dim", e.placeholder.slice(1))
|
|
41173
|
-
) : styleText2(["inverse", "hidden"], "_"), a2 = this.userInput ? this.userInputWithCursor : m2, l2 = this.value ?? "",
|
|
41429
|
+
) : styleText2(["inverse", "hidden"], "_"), a2 = this.userInput ? this.userInputWithCursor : m2, l2 = this.value ?? "", c59 = e.showSubmit ? `
|
|
41174
41430
|
${styleText2(this.focused === "submit" ? "cyan" : "dim", "[ submit ]")}` : "";
|
|
41175
41431
|
switch (this.state) {
|
|
41176
41432
|
case "error": {
|
|
41177
41433
|
const n3 = `${styleText2("yellow", S_BAR)} `, r2 = i2 ? wrapTextWithPrefix(e.output, a2, n3, void 0) : a2, u4 = styleText2("yellow", S_BAR_END);
|
|
41178
41434
|
return `${o2}${r2}
|
|
41179
|
-
${u4} ${styleText2("yellow", this.error)}${
|
|
41435
|
+
${u4} ${styleText2("yellow", this.error)}${c59}
|
|
41180
41436
|
`;
|
|
41181
41437
|
}
|
|
41182
41438
|
case "submit": {
|
|
@@ -41204,7 +41460,7 @@ ${u4} ${styleText2("yellow", this.error)}${c58}
|
|
|
41204
41460
|
default: {
|
|
41205
41461
|
const n3 = i2 ? `${styleText2("cyan", S_BAR)} ` : "", r2 = i2 ? styleText2("cyan", S_BAR_END) : "", u4 = i2 ? wrapTextWithPrefix(e.output, a2, n3) : a2;
|
|
41206
41462
|
return `${o2}${u4}
|
|
41207
|
-
${r2}${
|
|
41463
|
+
${r2}${c59}
|
|
41208
41464
|
`;
|
|
41209
41465
|
}
|
|
41210
41466
|
}
|
|
@@ -41219,7 +41475,7 @@ var password = (r2) => new u$1({
|
|
|
41219
41475
|
render() {
|
|
41220
41476
|
const e = r2.withGuide ?? settings.withGuide, o2 = `${e ? `${styleText2("gray", S_BAR)}
|
|
41221
41477
|
` : ""}${symbol2(this.state)} ${r2.message}
|
|
41222
|
-
`,
|
|
41478
|
+
`, c59 = this.userInputWithCursor, i2 = this.masked;
|
|
41223
41479
|
switch (this.state) {
|
|
41224
41480
|
case "error": {
|
|
41225
41481
|
const s = e ? `${styleText2("yellow", S_BAR)} ` : "", n3 = e ? `${styleText2("yellow", S_BAR_END)} ` : "", l2 = i2 ?? "";
|
|
@@ -41239,7 +41495,7 @@ ${styleText2("gray", S_BAR)}` : ""}`;
|
|
|
41239
41495
|
}
|
|
41240
41496
|
default: {
|
|
41241
41497
|
const s = e ? `${styleText2("cyan", S_BAR)} ` : "", n3 = e ? styleText2("cyan", S_BAR_END) : "";
|
|
41242
|
-
return `${o2}${s}${
|
|
41498
|
+
return `${o2}${s}${c59}
|
|
41243
41499
|
${n3}
|
|
41244
41500
|
`;
|
|
41245
41501
|
}
|
|
@@ -41255,7 +41511,7 @@ var SELECT_INSTRUCTIONS = [
|
|
|
41255
41511
|
`${styleText2("dim", "\u2191/\u2193")} to navigate`,
|
|
41256
41512
|
`${styleText2("dim", "Enter:")} confirm`
|
|
41257
41513
|
];
|
|
41258
|
-
var
|
|
41514
|
+
var c58 = (t2, o2) => t2.includes(`
|
|
41259
41515
|
`) ? t2.split(`
|
|
41260
41516
|
`).map((d) => o2(d)).join(`
|
|
41261
41517
|
`) : o2(t2);
|
|
@@ -41266,15 +41522,15 @@ var select = (t2) => {
|
|
|
41266
41522
|
const s = n3.label ?? String(n3.value);
|
|
41267
41523
|
switch (m2) {
|
|
41268
41524
|
case "disabled":
|
|
41269
|
-
return `${styleText2("gray", S_RADIO_INACTIVE)} ${
|
|
41525
|
+
return `${styleText2("gray", S_RADIO_INACTIVE)} ${c58(s, (i2) => styleText2("gray", i2))}${n3.hint ? ` ${styleText2("dim", `(${n3.hint ?? "disabled"})`)}` : ""}`;
|
|
41270
41526
|
case "selected":
|
|
41271
|
-
return `${
|
|
41527
|
+
return `${c58(s, (i2) => styleText2("dim", i2))}`;
|
|
41272
41528
|
case "active":
|
|
41273
41529
|
return `${styleText2("green", S_RADIO_ACTIVE)} ${s}${n3.hint ? ` ${styleText2("dim", `(${n3.hint})`)}` : ""}`;
|
|
41274
41530
|
case "cancelled":
|
|
41275
|
-
return `${
|
|
41531
|
+
return `${c58(s, (i2) => styleText2(["strikethrough", "dim"], i2))}`;
|
|
41276
41532
|
default:
|
|
41277
|
-
return `${styleText2("dim", S_RADIO_INACTIVE)} ${
|
|
41533
|
+
return `${styleText2("dim", S_RADIO_INACTIVE)} ${c58(s, (i2) => styleText2("dim", i2))}`;
|
|
41278
41534
|
}
|
|
41279
41535
|
}, d = t2.showInstructions ?? true;
|
|
41280
41536
|
return new n$1({
|
|
@@ -42334,7 +42590,7 @@ function extractCommandTree(cmd) {
|
|
|
42334
42590
|
description: o2.description,
|
|
42335
42591
|
takesValue: o2.required || o2.optional
|
|
42336
42592
|
}));
|
|
42337
|
-
const subcommands = cmd.commands.filter((
|
|
42593
|
+
const subcommands = cmd.commands.filter((c59) => !c59._hidden).map((c59) => extractCommandTree(c59));
|
|
42338
42594
|
return {
|
|
42339
42595
|
name: cmd.name(),
|
|
42340
42596
|
description: cmd.description(),
|
|
@@ -42400,7 +42656,7 @@ function generateBashCompletion(tree, binName) {
|
|
|
42400
42656
|
}
|
|
42401
42657
|
function collectBashCases(tree, prefix) {
|
|
42402
42658
|
const cases = /* @__PURE__ */ new Map();
|
|
42403
|
-
const subcommandNames = tree.subcommands.map((
|
|
42659
|
+
const subcommandNames = tree.subcommands.map((c59) => c59.name);
|
|
42404
42660
|
const optionNames = tree.options.flatMap((o2) => o2.short ? [o2.long, o2.short] : [o2.long]);
|
|
42405
42661
|
const extraOptions = prefix === "" ? ["--help", "--version"] : ["--help"];
|
|
42406
42662
|
const allOptions = [.../* @__PURE__ */ new Set([...optionNames, ...extraOptions])];
|
|
@@ -42815,9 +43071,9 @@ function buildInboxesTable(inboxes) {
|
|
|
42815
43071
|
address: sanitizeDisplay(inbox.address),
|
|
42816
43072
|
label: sanitizeDisplay(inbox.label)
|
|
42817
43073
|
}));
|
|
42818
|
-
const addressWidth = Math.max(7, ...cells.map((
|
|
43074
|
+
const addressWidth = Math.max(7, ...cells.map((c59) => c59.address.length));
|
|
42819
43075
|
const header = `${"ADDRESS".padEnd(addressWidth)} LABEL`;
|
|
42820
|
-
const rows = cells.map((
|
|
43076
|
+
const rows = cells.map((c59) => `${c59.address.padEnd(addressWidth)} ${c59.label}`);
|
|
42821
43077
|
return { header, rows };
|
|
42822
43078
|
}
|
|
42823
43079
|
function formatInboxQuota(quota) {
|
|
@@ -42841,14 +43097,14 @@ function buildInboxEmailsTable(messages) {
|
|
|
42841
43097
|
subject: sanitizeDisplay(message.subject ?? ""),
|
|
42842
43098
|
unread: message.unread ? "yes" : "no"
|
|
42843
43099
|
}));
|
|
42844
|
-
const idWidth = Math.max(2, ...cells.map((
|
|
42845
|
-
const receivedWidth = Math.max(8, ...cells.map((
|
|
42846
|
-
const fromWidth = Math.max(4, ...cells.map((
|
|
42847
|
-
const toWidth = Math.max(2, ...cells.map((
|
|
42848
|
-
const subjectWidth = Math.max(7, ...cells.map((
|
|
43100
|
+
const idWidth = Math.max(2, ...cells.map((c59) => c59.id.length));
|
|
43101
|
+
const receivedWidth = Math.max(8, ...cells.map((c59) => c59.received.length));
|
|
43102
|
+
const fromWidth = Math.max(4, ...cells.map((c59) => c59.from.length));
|
|
43103
|
+
const toWidth = Math.max(2, ...cells.map((c59) => c59.to.length));
|
|
43104
|
+
const subjectWidth = Math.max(7, ...cells.map((c59) => c59.subject.length));
|
|
42849
43105
|
const header = `${"ID".padEnd(idWidth)} ${"RECEIVED".padEnd(receivedWidth)} ${"FROM".padEnd(fromWidth)} ${"TO".padEnd(toWidth)} ${"SUBJECT".padEnd(subjectWidth)} UNREAD`;
|
|
42850
43106
|
const rows = cells.map(
|
|
42851
|
-
(
|
|
43107
|
+
(c59) => `${c59.id.padEnd(idWidth)} ${c59.received.padEnd(receivedWidth)} ${c59.from.padEnd(fromWidth)} ${c59.to.padEnd(toWidth)} ${c59.subject.padEnd(subjectWidth)} ${c59.unread}`
|
|
42852
43108
|
);
|
|
42853
43109
|
return { header, rows };
|
|
42854
43110
|
}
|
|
@@ -43076,14 +43332,14 @@ async function runEmails(label, options) {
|
|
|
43076
43332
|
const output = parseOutput(options.output);
|
|
43077
43333
|
requireInboxLabel(label);
|
|
43078
43334
|
const limit = parseEmailLimit(options.limit);
|
|
43079
|
-
const
|
|
43335
|
+
const since2 = parseEmailSince(options.since);
|
|
43080
43336
|
const organizationId = await resolveOrganizationId();
|
|
43081
43337
|
const result = await authenticatedRequest(
|
|
43082
43338
|
(client) => client.inbox.listInboxMessages({
|
|
43083
43339
|
params: { organizationId, label },
|
|
43084
43340
|
query: {
|
|
43085
43341
|
...limit !== void 0 ? { limit } : {},
|
|
43086
|
-
...
|
|
43342
|
+
...since2 !== void 0 ? { since: since2 } : {}
|
|
43087
43343
|
}
|
|
43088
43344
|
})
|
|
43089
43345
|
);
|
|
@@ -43576,16 +43832,16 @@ function printCredentialsTsv(creds) {
|
|
|
43576
43832
|
}
|
|
43577
43833
|
}
|
|
43578
43834
|
function buildCredentialsTable(creds) {
|
|
43579
|
-
const cells = creds.map((
|
|
43580
|
-
id:
|
|
43581
|
-
label: sanitizeDisplay(
|
|
43582
|
-
type:
|
|
43835
|
+
const cells = creds.map((c59) => ({
|
|
43836
|
+
id: c59.credentialId,
|
|
43837
|
+
label: sanitizeDisplay(c59.label),
|
|
43838
|
+
type: c59.credentialType
|
|
43583
43839
|
}));
|
|
43584
|
-
const idWidth = Math.max(2, ...cells.map((
|
|
43585
|
-
const labelWidth = Math.max(5, ...cells.map((
|
|
43840
|
+
const idWidth = Math.max(2, ...cells.map((c59) => c59.id.length));
|
|
43841
|
+
const labelWidth = Math.max(5, ...cells.map((c59) => c59.label.length));
|
|
43586
43842
|
const header = `${"ID".padEnd(idWidth)} ${"LABEL".padEnd(labelWidth)} TYPE`;
|
|
43587
43843
|
const rows = cells.map(
|
|
43588
|
-
(
|
|
43844
|
+
(c59) => `${c59.id.padEnd(idWidth)} ${c59.label.padEnd(labelWidth)} ${c59.type}`
|
|
43589
43845
|
);
|
|
43590
43846
|
return { header, rows };
|
|
43591
43847
|
}
|
|
@@ -44313,14 +44569,14 @@ function buildEnvironmentTable(envs, leading) {
|
|
|
44313
44569
|
url: e.primaryUrl != null ? sanitizeDisplay(e.primaryUrl) : "\u2014"
|
|
44314
44570
|
}));
|
|
44315
44571
|
const leadingWidths = leading.map(
|
|
44316
|
-
(column, i2) => Math.max(column.header.length, ...cells.map((
|
|
44572
|
+
(column, i2) => Math.max(column.header.length, ...cells.map((c59) => c59.leading[i2]?.length ?? 0))
|
|
44317
44573
|
);
|
|
44318
|
-
const nameWidth = Math.max(4, ...cells.map((
|
|
44574
|
+
const nameWidth = Math.max(4, ...cells.map((c59) => c59.name.length));
|
|
44319
44575
|
const padLeading = (values) => values.map((v, i2) => v.padEnd(leadingWidths[i2] ?? 0)).join(" ");
|
|
44320
44576
|
return {
|
|
44321
|
-
header: `${padLeading(leading.map((
|
|
44577
|
+
header: `${padLeading(leading.map((c59) => c59.header))} ${"NAME".padEnd(nameWidth)} PROD URL`,
|
|
44322
44578
|
rows: cells.map(
|
|
44323
|
-
(
|
|
44579
|
+
(c59) => `${padLeading(c59.leading)} ${c59.name.padEnd(nameWidth)} ${c59.prod.padEnd(4)} ${c59.url}`
|
|
44324
44580
|
)
|
|
44325
44581
|
};
|
|
44326
44582
|
}
|
|
@@ -45317,11 +45573,26 @@ function isPentestIdentifier(value) {
|
|
|
45317
45573
|
function isFindingIdentifier(value) {
|
|
45318
45574
|
return FINDING_IDENTIFIER_PATTERN.test(value);
|
|
45319
45575
|
}
|
|
45320
|
-
function failStatusUpdate(status, body) {
|
|
45576
|
+
function failStatusUpdate(status, body, viaApiKey) {
|
|
45321
45577
|
const { message, errorCode } = readErrorFields(body);
|
|
45322
45578
|
if (status === UNAUTHORIZED_STATUS2) {
|
|
45323
45579
|
exitAuthFailed();
|
|
45324
45580
|
}
|
|
45581
|
+
if (status === 403 && viaApiKey) {
|
|
45582
|
+
console.error(
|
|
45583
|
+
colorError(
|
|
45584
|
+
`${message ?? "Request failed (status 403)."}
|
|
45585
|
+
API keys can update finding status once Trace enables finding automation for your organization. Ask Trace to turn it on, or run this with \`tracecli auth login\`.`
|
|
45586
|
+
)
|
|
45587
|
+
);
|
|
45588
|
+
process.exit(1);
|
|
45589
|
+
}
|
|
45590
|
+
if (status === 409 && errorCode === "FINDING_STALE") {
|
|
45591
|
+
console.error(
|
|
45592
|
+
colorError(message ?? "The finding changed while this update was in flight. Retry it.")
|
|
45593
|
+
);
|
|
45594
|
+
process.exit(1);
|
|
45595
|
+
}
|
|
45325
45596
|
if (status === 404) {
|
|
45326
45597
|
console.error(colorError(message ?? "Pentest or finding not found."));
|
|
45327
45598
|
process.exit(1);
|
|
@@ -45398,13 +45669,19 @@ async function runStatusUpdate(options) {
|
|
|
45398
45669
|
);
|
|
45399
45670
|
process.exit(1);
|
|
45400
45671
|
}
|
|
45672
|
+
const viaApiKey = requireAuth().kind === "api_key";
|
|
45401
45673
|
const organizationId = await resolveOrganizationId();
|
|
45402
45674
|
const params = {
|
|
45403
45675
|
organizationId,
|
|
45404
45676
|
pentestId: options.pentest,
|
|
45405
45677
|
pentestFindingId: options.finding
|
|
45406
45678
|
};
|
|
45407
|
-
const result =
|
|
45679
|
+
const result = viaApiKey ? await authenticatedRequest(
|
|
45680
|
+
(client) => client.pentestFinding.automationStatusUpdate({
|
|
45681
|
+
params,
|
|
45682
|
+
body: { status: target, ...note !== void 0 ? { note } : {} }
|
|
45683
|
+
})
|
|
45684
|
+
) : target === "IN_PROGRESS" ? await authenticatedRequest(
|
|
45408
45685
|
(client) => client.pentestFinding.startProgress({ params, body: {} })
|
|
45409
45686
|
) : await authenticatedRequest(
|
|
45410
45687
|
(client) => client.pentestFinding.reportRemediation({
|
|
@@ -45413,7 +45690,7 @@ async function runStatusUpdate(options) {
|
|
|
45413
45690
|
})
|
|
45414
45691
|
);
|
|
45415
45692
|
if (result.status !== 200) {
|
|
45416
|
-
failStatusUpdate(result.status, result.body);
|
|
45693
|
+
failStatusUpdate(result.status, result.body, viaApiKey);
|
|
45417
45694
|
}
|
|
45418
45695
|
if (options.output === "json") {
|
|
45419
45696
|
console.log(JSON.stringify(result.body, null, 2));
|
|
@@ -45436,8 +45713,12 @@ fix is ready for Trace to re-test. Leaving the finding IN_PROGRESS (and not
|
|
|
45436
45713
|
sending REMEDIATED) keeps it out of the retest queue.
|
|
45437
45714
|
|
|
45438
45715
|
IN_PROGRESS is allowed from OPEN or VERIFIED_OPEN. REMEDIATED is allowed from
|
|
45439
|
-
OPEN, IN_PROGRESS, or VERIFIED_OPEN.
|
|
45440
|
-
|
|
45716
|
+
OPEN, IN_PROGRESS, or VERIFIED_OPEN.
|
|
45717
|
+
|
|
45718
|
+
A signed-in session (\`tracecli auth login\`) attributes the change to you. A
|
|
45719
|
+
Trace API key works too, once Trace enables finding automation for your
|
|
45720
|
+
organization: those writes are recorded as \`api-key:<key name>\` and show up as
|
|
45721
|
+
yours in the finding's history.
|
|
45441
45722
|
|
|
45442
45723
|
Examples:
|
|
45443
45724
|
tracecli pentest findings status-update --pentest PT-3 --finding 7 --status IN_PROGRESS
|
|
@@ -46693,6 +46974,961 @@ Examples:
|
|
|
46693
46974
|
});
|
|
46694
46975
|
}
|
|
46695
46976
|
|
|
46977
|
+
// src/upload/prepare.ts
|
|
46978
|
+
import { createHash } from "crypto";
|
|
46979
|
+
import { createReadStream, statSync as statSync3 } from "fs";
|
|
46980
|
+
import { open } from "fs/promises";
|
|
46981
|
+
import { basename as basename2 } from "path";
|
|
46982
|
+
var CodeUploadPrepareError = class extends Error {
|
|
46983
|
+
constructor(message) {
|
|
46984
|
+
super(message);
|
|
46985
|
+
this.name = "CodeUploadPrepareError";
|
|
46986
|
+
}
|
|
46987
|
+
};
|
|
46988
|
+
var KIND_BY_INPUT = {
|
|
46989
|
+
source: "SOURCE_ARCHIVE",
|
|
46990
|
+
code: "SOURCE_ARCHIVE",
|
|
46991
|
+
"source-archive": "SOURCE_ARCHIVE",
|
|
46992
|
+
source_archive: "SOURCE_ARCHIVE",
|
|
46993
|
+
SOURCE_ARCHIVE: "SOURCE_ARCHIVE",
|
|
46994
|
+
apk: "ANDROID_APK",
|
|
46995
|
+
android: "ANDROID_APK",
|
|
46996
|
+
"android-apk": "ANDROID_APK",
|
|
46997
|
+
android_apk: "ANDROID_APK",
|
|
46998
|
+
ANDROID_APK: "ANDROID_APK",
|
|
46999
|
+
ipa: "IOS_IPA",
|
|
47000
|
+
ios: "IOS_IPA",
|
|
47001
|
+
"ios-ipa": "IOS_IPA",
|
|
47002
|
+
ios_ipa: "IOS_IPA",
|
|
47003
|
+
IOS_IPA: "IOS_IPA"
|
|
47004
|
+
};
|
|
47005
|
+
function normalizeArtifactKind(input) {
|
|
47006
|
+
const trimmed = input.trim();
|
|
47007
|
+
return KIND_BY_INPUT[trimmed] ?? KIND_BY_INPUT[trimmed.toLowerCase()] ?? null;
|
|
47008
|
+
}
|
|
47009
|
+
function inferArtifactKindFromFilename(filename) {
|
|
47010
|
+
const lower = filename.toLowerCase();
|
|
47011
|
+
if (lower.endsWith(".zip")) return "SOURCE_ARCHIVE";
|
|
47012
|
+
if (lower.endsWith(".apk")) return "ANDROID_APK";
|
|
47013
|
+
if (lower.endsWith(".ipa")) return "IOS_IPA";
|
|
47014
|
+
return null;
|
|
47015
|
+
}
|
|
47016
|
+
function requiredExtensionForKind(kind) {
|
|
47017
|
+
if (kind === "ANDROID_APK") return ".apk";
|
|
47018
|
+
if (kind === "IOS_IPA") return ".ipa";
|
|
47019
|
+
return ".zip";
|
|
47020
|
+
}
|
|
47021
|
+
function defaultDisplayName(originalFilename) {
|
|
47022
|
+
const base = originalFilename.replace(/\.(zip|apk|ipa)$/i, "").trim();
|
|
47023
|
+
return base.slice(0, 200) || "source";
|
|
47024
|
+
}
|
|
47025
|
+
function formatArchiveBytes(bytes) {
|
|
47026
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
47027
|
+
if (bytes < 1024 * 1024) {
|
|
47028
|
+
const kb = bytes / 1024;
|
|
47029
|
+
return `${kb.toFixed(Number.isInteger(kb) ? 0 : 1)} KB`;
|
|
47030
|
+
}
|
|
47031
|
+
if (bytes < 1024 * 1024 * 1024) {
|
|
47032
|
+
const mb = bytes / (1024 * 1024);
|
|
47033
|
+
return `${mb.toFixed(Number.isInteger(mb) ? 0 : 1)} MB`;
|
|
47034
|
+
}
|
|
47035
|
+
const gb = bytes / (1024 * 1024 * 1024);
|
|
47036
|
+
return `${gb.toFixed(Number.isInteger(gb) ? 0 : 1)} GB`;
|
|
47037
|
+
}
|
|
47038
|
+
function archiveTooLargeMessage() {
|
|
47039
|
+
return `The file must be ${formatArchiveBytes(CODE_UPLOAD_MAX_BYTES)} or smaller.`;
|
|
47040
|
+
}
|
|
47041
|
+
async function hashFileSha256(filePath) {
|
|
47042
|
+
const hash2 = createHash("sha256");
|
|
47043
|
+
const stream = createReadStream(filePath);
|
|
47044
|
+
for await (const chunk of stream) {
|
|
47045
|
+
hash2.update(chunk);
|
|
47046
|
+
}
|
|
47047
|
+
return hash2.digest("hex");
|
|
47048
|
+
}
|
|
47049
|
+
async function readFileSlice(filePath, start, endExclusive) {
|
|
47050
|
+
const length = endExclusive - start;
|
|
47051
|
+
if (!Number.isSafeInteger(start) || !Number.isSafeInteger(length) || start < 0 || length < 1) {
|
|
47052
|
+
throw new Error(
|
|
47053
|
+
`Invalid file slice: start=${String(start)} endExclusive=${String(endExclusive)}.`
|
|
47054
|
+
);
|
|
47055
|
+
}
|
|
47056
|
+
const buffer = Buffer.alloc(length);
|
|
47057
|
+
const handle = await open(filePath, "r");
|
|
47058
|
+
try {
|
|
47059
|
+
const { bytesRead } = await handle.read(buffer, 0, length, start);
|
|
47060
|
+
if (bytesRead !== length) {
|
|
47061
|
+
throw new Error(
|
|
47062
|
+
`Expected to read ${String(length)} bytes at offset ${String(start)}, got ${String(bytesRead)}.`
|
|
47063
|
+
);
|
|
47064
|
+
}
|
|
47065
|
+
return buffer;
|
|
47066
|
+
} finally {
|
|
47067
|
+
await handle.close();
|
|
47068
|
+
}
|
|
47069
|
+
}
|
|
47070
|
+
function assertPreparedMatchesUpload(upload, prepared) {
|
|
47071
|
+
if (upload.sizeBytes !== prepared.sizeBytes || upload.archiveSha256 !== prepared.archiveSha256) {
|
|
47072
|
+
throw new CodeUploadPrepareError(
|
|
47073
|
+
"The file does not match the interrupted upload (size or SHA-256 differs)."
|
|
47074
|
+
);
|
|
47075
|
+
}
|
|
47076
|
+
}
|
|
47077
|
+
async function prepareUploadFile(filePath, options = {}) {
|
|
47078
|
+
let sizeBytes;
|
|
47079
|
+
try {
|
|
47080
|
+
const stats = statSync3(filePath);
|
|
47081
|
+
if (!stats.isFile()) {
|
|
47082
|
+
throw new CodeUploadPrepareError("Path is not a regular file. Pass a .zip, .apk, or .ipa.");
|
|
47083
|
+
}
|
|
47084
|
+
sizeBytes = stats.size;
|
|
47085
|
+
} catch (error48) {
|
|
47086
|
+
if (error48 instanceof CodeUploadPrepareError) throw error48;
|
|
47087
|
+
throw new CodeUploadPrepareError("Cannot read that file.");
|
|
47088
|
+
}
|
|
47089
|
+
if (!Number.isSafeInteger(sizeBytes) || sizeBytes < 1) {
|
|
47090
|
+
throw new CodeUploadPrepareError("The file is empty.");
|
|
47091
|
+
}
|
|
47092
|
+
if (sizeBytes > CODE_UPLOAD_MAX_BYTES) {
|
|
47093
|
+
throw new CodeUploadPrepareError(archiveTooLargeMessage());
|
|
47094
|
+
}
|
|
47095
|
+
const originalFilename = basename2(filePath);
|
|
47096
|
+
const inferred = inferArtifactKindFromFilename(originalFilename);
|
|
47097
|
+
const artifactKind = options.artifactKind ?? inferred;
|
|
47098
|
+
if (artifactKind == null) {
|
|
47099
|
+
throw new CodeUploadPrepareError("Pass a .zip source archive, an .apk, or an .ipa.");
|
|
47100
|
+
}
|
|
47101
|
+
const expected = requiredExtensionForKind(artifactKind);
|
|
47102
|
+
if (!originalFilename.toLowerCase().endsWith(expected)) {
|
|
47103
|
+
const label = isApplicationBuildArtifactKind(artifactKind) ? artifactKind === "ANDROID_APK" ? "Android APK" : "iOS package" : "source archive";
|
|
47104
|
+
throw new CodeUploadPrepareError(`A ${label} must end in ${expected}.`);
|
|
47105
|
+
}
|
|
47106
|
+
const displayName = (options.displayName ?? defaultDisplayName(originalFilename)).trim();
|
|
47107
|
+
if (displayName.length < 1 || displayName.length > 200) {
|
|
47108
|
+
throw new CodeUploadPrepareError("Display name must be 1 to 200 characters.");
|
|
47109
|
+
}
|
|
47110
|
+
return {
|
|
47111
|
+
path: filePath,
|
|
47112
|
+
displayName,
|
|
47113
|
+
originalFilename,
|
|
47114
|
+
sizeBytes,
|
|
47115
|
+
archiveSha256: await hashFileSha256(filePath),
|
|
47116
|
+
artifactKind
|
|
47117
|
+
};
|
|
47118
|
+
}
|
|
47119
|
+
|
|
47120
|
+
// src/upload/multipart.ts
|
|
47121
|
+
var MAX_CONCURRENT_UPLOADS = 3;
|
|
47122
|
+
var MAX_PART_ATTEMPTS = 3;
|
|
47123
|
+
var MAX_URL_REFRESHES = 12;
|
|
47124
|
+
async function uploadCodeArchiveParts(filePath, totalBytes, partSizeBytes, parts, options = {}) {
|
|
47125
|
+
assertUploadPlan(totalBytes, partSizeBytes, parts);
|
|
47126
|
+
const fetchPart = options.fetch ?? globalThis.fetch;
|
|
47127
|
+
const wait = options.wait ?? defaultWait;
|
|
47128
|
+
let uploadedBytes = options.initialUploadedBytes ?? 0;
|
|
47129
|
+
if (!Number.isSafeInteger(uploadedBytes) || uploadedBytes < 0 || uploadedBytes > totalBytes) {
|
|
47130
|
+
throw new Error("Invalid multipart progress: uploaded byte count is outside the archive.");
|
|
47131
|
+
}
|
|
47132
|
+
options.onProgress?.(progress(uploadedBytes, totalBytes));
|
|
47133
|
+
if (parts.length === 0) return;
|
|
47134
|
+
const urls = new Map(parts.map((part) => [part.partNumber, part.uploadUrl]));
|
|
47135
|
+
const refreshUrls = createUrlRefresher(urls, options.refreshParts);
|
|
47136
|
+
let cursor3 = 0;
|
|
47137
|
+
const workerCount = Math.min(MAX_CONCURRENT_UPLOADS, parts.length);
|
|
47138
|
+
await Promise.all(
|
|
47139
|
+
Array.from({ length: workerCount }, async () => {
|
|
47140
|
+
while (cursor3 < parts.length) {
|
|
47141
|
+
const part = parts[cursor3];
|
|
47142
|
+
cursor3 += 1;
|
|
47143
|
+
if (!part) return;
|
|
47144
|
+
const start = (part.partNumber - 1) * partSizeBytes;
|
|
47145
|
+
const end = Math.min(start + partSizeBytes, totalBytes);
|
|
47146
|
+
const body = await readFileSlice(filePath, start, end);
|
|
47147
|
+
await uploadPartWithRetry(part.partNumber, urls, body, fetchPart, wait, refreshUrls);
|
|
47148
|
+
uploadedBytes += body.byteLength;
|
|
47149
|
+
options.onProgress?.(progress(uploadedBytes, totalBytes));
|
|
47150
|
+
}
|
|
47151
|
+
})
|
|
47152
|
+
);
|
|
47153
|
+
}
|
|
47154
|
+
function createUrlRefresher(urls, refreshParts) {
|
|
47155
|
+
if (!refreshParts) return async () => false;
|
|
47156
|
+
let inflight = null;
|
|
47157
|
+
let rounds = 0;
|
|
47158
|
+
return async () => {
|
|
47159
|
+
if (rounds >= MAX_URL_REFRESHES) return false;
|
|
47160
|
+
if (!inflight) {
|
|
47161
|
+
rounds += 1;
|
|
47162
|
+
inflight = (async () => {
|
|
47163
|
+
const fresh = await refreshParts();
|
|
47164
|
+
for (const part of fresh) {
|
|
47165
|
+
assertPresignedUploadUrl(part.uploadUrl);
|
|
47166
|
+
urls.set(part.partNumber, part.uploadUrl);
|
|
47167
|
+
}
|
|
47168
|
+
})().finally(() => {
|
|
47169
|
+
inflight = null;
|
|
47170
|
+
});
|
|
47171
|
+
}
|
|
47172
|
+
await inflight;
|
|
47173
|
+
return true;
|
|
47174
|
+
};
|
|
47175
|
+
}
|
|
47176
|
+
function assertUploadPlan(totalBytes, partSizeBytes, parts) {
|
|
47177
|
+
if (!Number.isSafeInteger(totalBytes) || totalBytes < 1) {
|
|
47178
|
+
throw new Error("Invalid multipart upload: archive size must be a positive integer.");
|
|
47179
|
+
}
|
|
47180
|
+
if (!Number.isSafeInteger(partSizeBytes) || partSizeBytes < 1) {
|
|
47181
|
+
throw new Error("Invalid multipart upload: part size must be a positive integer.");
|
|
47182
|
+
}
|
|
47183
|
+
const totalParts = Math.ceil(totalBytes / partSizeBytes);
|
|
47184
|
+
const seen = /* @__PURE__ */ new Set();
|
|
47185
|
+
for (const part of parts) {
|
|
47186
|
+
if (!Number.isSafeInteger(part.partNumber) || part.partNumber < 1 || part.partNumber > totalParts || seen.has(part.partNumber)) {
|
|
47187
|
+
throw new Error("Invalid multipart upload: part numbers must be unique and in range.");
|
|
47188
|
+
}
|
|
47189
|
+
assertPresignedUploadUrl(part.uploadUrl);
|
|
47190
|
+
seen.add(part.partNumber);
|
|
47191
|
+
}
|
|
47192
|
+
}
|
|
47193
|
+
async function uploadPartWithRetry(partNumber, urls, body, fetchPart, wait, refreshUrls) {
|
|
47194
|
+
let lastStatus = null;
|
|
47195
|
+
for (let attempt = 1; attempt <= MAX_PART_ATTEMPTS; attempt += 1) {
|
|
47196
|
+
const uploadUrl = urls.get(partNumber);
|
|
47197
|
+
if (!uploadUrl) {
|
|
47198
|
+
throw new Error(`Source upload part ${partNumber.toString()} has no upload URL.`);
|
|
47199
|
+
}
|
|
47200
|
+
try {
|
|
47201
|
+
const response = await fetchPart(uploadUrl, {
|
|
47202
|
+
method: "PUT",
|
|
47203
|
+
body: new Uint8Array(body),
|
|
47204
|
+
redirect: "error"
|
|
47205
|
+
});
|
|
47206
|
+
if (response.ok) return;
|
|
47207
|
+
lastStatus = response.status;
|
|
47208
|
+
if (response.status === 403 && await refreshUrls()) {
|
|
47209
|
+
attempt -= 1;
|
|
47210
|
+
continue;
|
|
47211
|
+
}
|
|
47212
|
+
if (response.status >= 400 && response.status < 500 && response.status !== 408) break;
|
|
47213
|
+
} catch {
|
|
47214
|
+
lastStatus = null;
|
|
47215
|
+
}
|
|
47216
|
+
if (attempt < MAX_PART_ATTEMPTS) {
|
|
47217
|
+
await wait(250 * 2 ** (attempt - 1));
|
|
47218
|
+
}
|
|
47219
|
+
}
|
|
47220
|
+
const statusDetail = lastStatus === null ? "network error" : `status ${lastStatus.toString()}`;
|
|
47221
|
+
throw new Error(
|
|
47222
|
+
`Source upload part ${partNumber.toString()} failed after retries (${statusDetail}).`
|
|
47223
|
+
);
|
|
47224
|
+
}
|
|
47225
|
+
function assertPresignedUploadUrl(value) {
|
|
47226
|
+
let url2;
|
|
47227
|
+
try {
|
|
47228
|
+
url2 = new URL(value);
|
|
47229
|
+
} catch {
|
|
47230
|
+
throw new Error("Invalid multipart upload: the API returned an invalid part URL.");
|
|
47231
|
+
}
|
|
47232
|
+
const localHttp = url2.protocol === "http:" && (url2.hostname === "localhost" || url2.hostname === "127.0.0.1" || url2.hostname === "host.docker.internal");
|
|
47233
|
+
if (url2.protocol !== "https:" && !localHttp) {
|
|
47234
|
+
throw new Error("Invalid multipart upload: part URLs must use HTTPS.");
|
|
47235
|
+
}
|
|
47236
|
+
}
|
|
47237
|
+
function progress(uploadedBytes, totalBytes) {
|
|
47238
|
+
return {
|
|
47239
|
+
uploadedBytes,
|
|
47240
|
+
totalBytes,
|
|
47241
|
+
fraction: totalBytes === 0 ? 0 : Math.min(1, uploadedBytes / totalBytes)
|
|
47242
|
+
};
|
|
47243
|
+
}
|
|
47244
|
+
function defaultWait(milliseconds) {
|
|
47245
|
+
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
47246
|
+
}
|
|
47247
|
+
|
|
47248
|
+
// src/upload/commands.ts
|
|
47249
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["READY", "REJECTED", "FAILED", "DELETING"]);
|
|
47250
|
+
var DEFAULT_RUNTIME = {
|
|
47251
|
+
wait: (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)),
|
|
47252
|
+
pollIntervalMs: 3e3,
|
|
47253
|
+
fetch: (input, init) => globalThis.fetch(input, init)
|
|
47254
|
+
};
|
|
47255
|
+
function resolveRuntime(runtime) {
|
|
47256
|
+
return {
|
|
47257
|
+
wait: runtime.wait ?? DEFAULT_RUNTIME.wait,
|
|
47258
|
+
pollIntervalMs: runtime.pollIntervalMs ?? DEFAULT_RUNTIME.pollIntervalMs,
|
|
47259
|
+
fetch: runtime.fetch ?? DEFAULT_RUNTIME.fetch
|
|
47260
|
+
};
|
|
47261
|
+
}
|
|
47262
|
+
function isTerminalCodeUploadStatus(status) {
|
|
47263
|
+
return TERMINAL_STATUSES.has(status);
|
|
47264
|
+
}
|
|
47265
|
+
function requireUuid(value, label) {
|
|
47266
|
+
if (!isUuid(value)) {
|
|
47267
|
+
console.error(colorError(`Invalid ${label} '${sanitizeDisplay(value)}'. Expected a UUID.`));
|
|
47268
|
+
process.exit(1);
|
|
47269
|
+
}
|
|
47270
|
+
return value;
|
|
47271
|
+
}
|
|
47272
|
+
function parseKindOption(value) {
|
|
47273
|
+
if (value === void 0) return void 0;
|
|
47274
|
+
const kind = normalizeArtifactKind(value);
|
|
47275
|
+
if (kind == null) {
|
|
47276
|
+
console.error(
|
|
47277
|
+
colorError(`Invalid --kind '${sanitizeDisplay(value)}'. Use source (code ZIP), apk, or ipa.`)
|
|
47278
|
+
);
|
|
47279
|
+
process.exit(1);
|
|
47280
|
+
}
|
|
47281
|
+
return kind;
|
|
47282
|
+
}
|
|
47283
|
+
function failPrepare(error48) {
|
|
47284
|
+
const message = error48 instanceof CodeUploadPrepareError ? error48.message : error48 instanceof Error ? error48.message : "Failed to prepare the file.";
|
|
47285
|
+
console.error(colorError(message));
|
|
47286
|
+
process.exit(1);
|
|
47287
|
+
}
|
|
47288
|
+
function failWriteOp5(action, status, body) {
|
|
47289
|
+
const { message, errorCode } = readErrorFields(body);
|
|
47290
|
+
if (status === UNAUTHORIZED_STATUS2) {
|
|
47291
|
+
exitAuthFailed();
|
|
47292
|
+
}
|
|
47293
|
+
if (status === 403) {
|
|
47294
|
+
console.error(
|
|
47295
|
+
colorError(
|
|
47296
|
+
`Only an organization admin (or Trace staff) on a pentest-enabled organization can ${action} source uploads.`
|
|
47297
|
+
)
|
|
47298
|
+
);
|
|
47299
|
+
process.exit(1);
|
|
47300
|
+
}
|
|
47301
|
+
if (status === 404) {
|
|
47302
|
+
console.error(colorError(message ?? "No code upload with that id."));
|
|
47303
|
+
process.exit(1);
|
|
47304
|
+
}
|
|
47305
|
+
if (status === 400) {
|
|
47306
|
+
console.error(colorError(message ?? "Invalid request (status 400)."));
|
|
47307
|
+
process.exit(1);
|
|
47308
|
+
}
|
|
47309
|
+
if (status === 409) {
|
|
47310
|
+
if (errorCode === "CODE_UPLOAD_NOT_READY") {
|
|
47311
|
+
console.error(
|
|
47312
|
+
colorError(
|
|
47313
|
+
message ?? "The upload must be ready and pass malware scanning before it can be linked. Run `tracecli upload wait <id>`."
|
|
47314
|
+
)
|
|
47315
|
+
);
|
|
47316
|
+
} else if (errorCode === "CODE_UPLOAD_NOT_SOURCE") {
|
|
47317
|
+
console.error(
|
|
47318
|
+
colorError(message ?? "APK and IPA uploads cannot be linked as source repositories.")
|
|
47319
|
+
);
|
|
47320
|
+
} else {
|
|
47321
|
+
console.error(colorError(message ?? "Conflict (status 409)."));
|
|
47322
|
+
}
|
|
47323
|
+
process.exit(1);
|
|
47324
|
+
}
|
|
47325
|
+
if (status === 503) {
|
|
47326
|
+
console.error(
|
|
47327
|
+
colorError(message ?? "Source archive uploads are not configured on this server.")
|
|
47328
|
+
);
|
|
47329
|
+
process.exit(1);
|
|
47330
|
+
}
|
|
47331
|
+
console.error(
|
|
47332
|
+
colorError(`Failed to ${action} upload (status ${status})${message ? `: ${message}` : "."}`)
|
|
47333
|
+
);
|
|
47334
|
+
process.exit(1);
|
|
47335
|
+
}
|
|
47336
|
+
function failReadOp5(action, status, body) {
|
|
47337
|
+
const { message } = readErrorFields(body);
|
|
47338
|
+
if (status === UNAUTHORIZED_STATUS2) {
|
|
47339
|
+
exitAuthFailed();
|
|
47340
|
+
}
|
|
47341
|
+
if (status === 403) {
|
|
47342
|
+
console.error(
|
|
47343
|
+
colorError(
|
|
47344
|
+
"Only an organization admin (or Trace staff) on a pentest-enabled organization can view source uploads."
|
|
47345
|
+
)
|
|
47346
|
+
);
|
|
47347
|
+
process.exit(1);
|
|
47348
|
+
}
|
|
47349
|
+
if (status === 404) {
|
|
47350
|
+
console.error(colorError(message ?? "No code upload with that id."));
|
|
47351
|
+
process.exit(1);
|
|
47352
|
+
}
|
|
47353
|
+
if (status === 503) {
|
|
47354
|
+
console.error(
|
|
47355
|
+
colorError(message ?? "Source archive uploads are not configured on this server.")
|
|
47356
|
+
);
|
|
47357
|
+
process.exit(1);
|
|
47358
|
+
}
|
|
47359
|
+
console.error(
|
|
47360
|
+
colorError(`Failed to ${action} (status ${status})${message ? `: ${message}` : "."}`)
|
|
47361
|
+
);
|
|
47362
|
+
process.exit(1);
|
|
47363
|
+
}
|
|
47364
|
+
function resumeHint(codeUploadId, filePath) {
|
|
47365
|
+
return `Resume with: tracecli upload resume ${codeUploadId} ${filePath}`;
|
|
47366
|
+
}
|
|
47367
|
+
function buildUploadsTable(uploads) {
|
|
47368
|
+
const cells = uploads.map((upload) => ({
|
|
47369
|
+
name: sanitizeDisplay(upload.displayName),
|
|
47370
|
+
kind: formatStatus(upload.artifactKind),
|
|
47371
|
+
status: formatStatus(upload.status),
|
|
47372
|
+
size: formatArchiveBytes(upload.sizeBytes),
|
|
47373
|
+
id: upload.codeUploadId
|
|
47374
|
+
}));
|
|
47375
|
+
const nameWidth = Math.max(4, ...cells.map((c59) => c59.name.length));
|
|
47376
|
+
const kindWidth = Math.max(4, ...cells.map((c59) => c59.kind.length));
|
|
47377
|
+
const statusWidth = Math.max(6, ...cells.map((c59) => c59.status.length));
|
|
47378
|
+
const sizeWidth = Math.max(4, ...cells.map((c59) => c59.size.length));
|
|
47379
|
+
const header = `${"NAME".padEnd(nameWidth)} ${"KIND".padEnd(kindWidth)} ${"STATUS".padEnd(statusWidth)} ${"SIZE".padEnd(sizeWidth)} ID`;
|
|
47380
|
+
const rows = cells.map(
|
|
47381
|
+
(c59) => `${c59.name.padEnd(nameWidth)} ${c59.kind.padEnd(kindWidth)} ${c59.status.padEnd(statusWidth)} ${c59.size.padEnd(sizeWidth)} ${c59.id}`
|
|
47382
|
+
);
|
|
47383
|
+
return { header, rows };
|
|
47384
|
+
}
|
|
47385
|
+
function renderUploadDetail(upload) {
|
|
47386
|
+
const pad = 18;
|
|
47387
|
+
const linked = upload.linkedApplications.length === 0 ? "\u2014" : upload.linkedApplications.map((app) => `${sanitizeDisplay(app.name)} (${app.applicationId})`).join(", ");
|
|
47388
|
+
return [
|
|
47389
|
+
`${"Name:".padEnd(pad)} ${sanitizeDisplay(upload.displayName)}`,
|
|
47390
|
+
`${"Filename:".padEnd(pad)} ${sanitizeDisplay(upload.originalFilename)}`,
|
|
47391
|
+
`${"Kind:".padEnd(pad)} ${formatStatus(upload.artifactKind)}`,
|
|
47392
|
+
`${"Status:".padEnd(pad)} ${formatStatus(upload.status)}`,
|
|
47393
|
+
`${"Size:".padEnd(pad)} ${formatArchiveBytes(upload.sizeBytes)}`,
|
|
47394
|
+
`${"SHA-256:".padEnd(pad)} ${upload.archiveSha256}`,
|
|
47395
|
+
`${"Upload ID:".padEnd(pad)} ${upload.codeUploadId}`,
|
|
47396
|
+
`${"Repository ID:".padEnd(pad)} ${upload.repositoryId}`,
|
|
47397
|
+
`${"Malware:".padEnd(pad)} ${upload.malwareScanResult ? formatStatus(upload.malwareScanResult) : "\u2014"}`,
|
|
47398
|
+
`${"Rejection:".padEnd(pad)} ${upload.rejectionReason ? formatStatus(upload.rejectionReason) : "\u2014"}`,
|
|
47399
|
+
`${"Linked apps:".padEnd(pad)} ${linked}`,
|
|
47400
|
+
`${"Created:".padEnd(pad)} ${formatDate(upload.createdAt)}`,
|
|
47401
|
+
`${"Ready:".padEnd(pad)} ${formatDate(upload.readyAt)}`
|
|
47402
|
+
].join("\n");
|
|
47403
|
+
}
|
|
47404
|
+
function printUploadsTsv(uploads) {
|
|
47405
|
+
console.log(
|
|
47406
|
+
[
|
|
47407
|
+
"codeUploadId",
|
|
47408
|
+
"repositoryId",
|
|
47409
|
+
"displayName",
|
|
47410
|
+
"originalFilename",
|
|
47411
|
+
"artifactKind",
|
|
47412
|
+
"status",
|
|
47413
|
+
"sizeBytes",
|
|
47414
|
+
"archiveSha256",
|
|
47415
|
+
"malwareScanResult",
|
|
47416
|
+
"rejectionReason",
|
|
47417
|
+
"applicationId",
|
|
47418
|
+
"createdAt",
|
|
47419
|
+
"readyAt"
|
|
47420
|
+
].join(" ")
|
|
47421
|
+
);
|
|
47422
|
+
for (const upload of uploads) {
|
|
47423
|
+
console.log(
|
|
47424
|
+
[
|
|
47425
|
+
tsvSafe(upload.codeUploadId),
|
|
47426
|
+
tsvSafe(upload.repositoryId),
|
|
47427
|
+
tsvSafe(sanitizeDisplay(upload.displayName)),
|
|
47428
|
+
tsvSafe(sanitizeDisplay(upload.originalFilename)),
|
|
47429
|
+
tsvSafe(upload.artifactKind),
|
|
47430
|
+
tsvSafe(upload.status),
|
|
47431
|
+
String(upload.sizeBytes),
|
|
47432
|
+
tsvSafe(upload.archiveSha256),
|
|
47433
|
+
tsvSafe(upload.malwareScanResult ?? ""),
|
|
47434
|
+
tsvSafe(upload.rejectionReason ?? ""),
|
|
47435
|
+
tsvSafe(upload.applicationId ?? ""),
|
|
47436
|
+
tsvSafe(toIso(upload.createdAt)),
|
|
47437
|
+
tsvSafe(upload.readyAt ? toIso(upload.readyAt) : "")
|
|
47438
|
+
].join(" ")
|
|
47439
|
+
);
|
|
47440
|
+
}
|
|
47441
|
+
}
|
|
47442
|
+
function outputUpload(upload, output) {
|
|
47443
|
+
if (output === "json") {
|
|
47444
|
+
console.log(JSON.stringify(upload, null, 2));
|
|
47445
|
+
return;
|
|
47446
|
+
}
|
|
47447
|
+
if (output === "tsv") {
|
|
47448
|
+
printUploadsTsv([upload]);
|
|
47449
|
+
return;
|
|
47450
|
+
}
|
|
47451
|
+
console.log(renderUploadDetail(upload));
|
|
47452
|
+
}
|
|
47453
|
+
function writeProgress(progress2) {
|
|
47454
|
+
if (!process.stderr.isTTY) return;
|
|
47455
|
+
const pct = Math.floor(progress2.fraction * 100);
|
|
47456
|
+
process.stderr.write(
|
|
47457
|
+
`\rUploading ${pct}% (${formatArchiveBytes(progress2.uploadedBytes)} / ${formatArchiveBytes(progress2.totalBytes)})`
|
|
47458
|
+
);
|
|
47459
|
+
}
|
|
47460
|
+
function finishProgress() {
|
|
47461
|
+
if (process.stderr.isTTY) process.stderr.write("\n");
|
|
47462
|
+
}
|
|
47463
|
+
async function listUploads(organizationId, query = {}) {
|
|
47464
|
+
const result = await authenticatedRequest(
|
|
47465
|
+
(client) => client.codeUpload.listCodeUploads({
|
|
47466
|
+
params: { organizationId },
|
|
47467
|
+
query
|
|
47468
|
+
})
|
|
47469
|
+
);
|
|
47470
|
+
if (result.status !== SUCCESS_STATUS) {
|
|
47471
|
+
failReadOp5("list uploads", result.status, result.body);
|
|
47472
|
+
}
|
|
47473
|
+
return result.body.uploads;
|
|
47474
|
+
}
|
|
47475
|
+
async function requireUpload(organizationId, codeUploadId, query = {}) {
|
|
47476
|
+
const uploads = await listUploads(organizationId, query);
|
|
47477
|
+
const match = uploads.find((upload) => upload.codeUploadId === codeUploadId);
|
|
47478
|
+
if (!match) {
|
|
47479
|
+
console.error(colorError(`No code upload '${codeUploadId}'.`));
|
|
47480
|
+
process.exit(1);
|
|
47481
|
+
}
|
|
47482
|
+
return match;
|
|
47483
|
+
}
|
|
47484
|
+
async function refreshRemainingParts(organizationId, codeUploadId) {
|
|
47485
|
+
const result = await authenticatedRequest(
|
|
47486
|
+
(client) => client.codeUpload.resumeCodeUpload({
|
|
47487
|
+
params: { organizationId, codeUploadId },
|
|
47488
|
+
body: {}
|
|
47489
|
+
})
|
|
47490
|
+
);
|
|
47491
|
+
if (result.status !== SUCCESS_STATUS) {
|
|
47492
|
+
failWriteOp5("resume", result.status, result.body);
|
|
47493
|
+
}
|
|
47494
|
+
return result.body.multipart.parts;
|
|
47495
|
+
}
|
|
47496
|
+
async function completeUpload(organizationId, codeUploadId) {
|
|
47497
|
+
const result = await authenticatedRequest(
|
|
47498
|
+
(client) => client.codeUpload.completeCodeUpload({
|
|
47499
|
+
params: { organizationId, codeUploadId },
|
|
47500
|
+
body: {}
|
|
47501
|
+
})
|
|
47502
|
+
);
|
|
47503
|
+
if (result.status !== ACCEPTED_STATUS) {
|
|
47504
|
+
failWriteOp5("complete", result.status, result.body);
|
|
47505
|
+
}
|
|
47506
|
+
return result.body;
|
|
47507
|
+
}
|
|
47508
|
+
async function waitForTerminal(organizationId, codeUploadId, runtime) {
|
|
47509
|
+
for (; ; ) {
|
|
47510
|
+
const upload = await requireUpload(organizationId, codeUploadId);
|
|
47511
|
+
if (isTerminalCodeUploadStatus(upload.status)) {
|
|
47512
|
+
return upload;
|
|
47513
|
+
}
|
|
47514
|
+
if (process.stderr.isTTY) {
|
|
47515
|
+
process.stderr.write(`\rWaiting for malware scan (${formatStatus(upload.status)})...`);
|
|
47516
|
+
}
|
|
47517
|
+
await runtime.wait(runtime.pollIntervalMs);
|
|
47518
|
+
}
|
|
47519
|
+
}
|
|
47520
|
+
function printWaitOutcome(upload, output) {
|
|
47521
|
+
if (output !== "table") {
|
|
47522
|
+
outputUpload(upload, output);
|
|
47523
|
+
if (upload.status !== "READY") process.exit(1);
|
|
47524
|
+
return;
|
|
47525
|
+
}
|
|
47526
|
+
if (upload.status === "READY") {
|
|
47527
|
+
console.log(colorSuccess(`Upload ${upload.codeUploadId} is ready.`));
|
|
47528
|
+
outputUpload(upload, output);
|
|
47529
|
+
if (upload.artifactKind === "SOURCE_ARCHIVE") {
|
|
47530
|
+
console.log(
|
|
47531
|
+
`Link it with: tracecli upload link --app <applicationId> --upload ${upload.codeUploadId}`
|
|
47532
|
+
);
|
|
47533
|
+
}
|
|
47534
|
+
return;
|
|
47535
|
+
}
|
|
47536
|
+
const reason = upload.rejectionReason ? ` (${formatStatus(upload.rejectionReason)})` : "";
|
|
47537
|
+
console.error(
|
|
47538
|
+
colorError(`Upload ${upload.codeUploadId} ended as ${formatStatus(upload.status)}${reason}.`)
|
|
47539
|
+
);
|
|
47540
|
+
outputUpload(upload, output);
|
|
47541
|
+
process.exit(1);
|
|
47542
|
+
}
|
|
47543
|
+
async function runTransfer(filePath, options, runtime) {
|
|
47544
|
+
const output = parseOutput(options.output);
|
|
47545
|
+
let prepared;
|
|
47546
|
+
try {
|
|
47547
|
+
prepared = await prepareUploadFile(filePath, {
|
|
47548
|
+
displayName: options.name,
|
|
47549
|
+
artifactKind: options.artifactKind
|
|
47550
|
+
});
|
|
47551
|
+
} catch (error48) {
|
|
47552
|
+
failPrepare(error48);
|
|
47553
|
+
}
|
|
47554
|
+
const organizationId = await resolveOrganizationId();
|
|
47555
|
+
const initialized = await authenticatedRequest(
|
|
47556
|
+
(client) => client.codeUpload.initializeCodeUpload({
|
|
47557
|
+
params: { organizationId },
|
|
47558
|
+
body: {
|
|
47559
|
+
displayName: prepared.displayName,
|
|
47560
|
+
originalFilename: prepared.originalFilename,
|
|
47561
|
+
sizeBytes: prepared.sizeBytes,
|
|
47562
|
+
archiveSha256: prepared.archiveSha256,
|
|
47563
|
+
artifactKind: prepared.artifactKind,
|
|
47564
|
+
...options.applicationId !== void 0 ? { applicationId: options.applicationId } : {}
|
|
47565
|
+
}
|
|
47566
|
+
})
|
|
47567
|
+
);
|
|
47568
|
+
if (initialized.status !== CREATED_STATUS) {
|
|
47569
|
+
failWriteOp5("create", initialized.status, initialized.body);
|
|
47570
|
+
}
|
|
47571
|
+
const codeUploadId = initialized.body.upload.codeUploadId;
|
|
47572
|
+
if (output === "table") {
|
|
47573
|
+
console.error(
|
|
47574
|
+
`Initialized upload ${codeUploadId} (${formatArchiveBytes(prepared.sizeBytes)}).`
|
|
47575
|
+
);
|
|
47576
|
+
}
|
|
47577
|
+
try {
|
|
47578
|
+
await uploadCodeArchiveParts(
|
|
47579
|
+
prepared.path,
|
|
47580
|
+
prepared.sizeBytes,
|
|
47581
|
+
initialized.body.multipart.partSizeBytes,
|
|
47582
|
+
initialized.body.multipart.parts,
|
|
47583
|
+
{
|
|
47584
|
+
fetch: runtime.fetch,
|
|
47585
|
+
wait: runtime.wait,
|
|
47586
|
+
onProgress: writeProgress,
|
|
47587
|
+
refreshParts: () => refreshRemainingParts(organizationId, codeUploadId)
|
|
47588
|
+
}
|
|
47589
|
+
);
|
|
47590
|
+
finishProgress();
|
|
47591
|
+
} catch (error48) {
|
|
47592
|
+
finishProgress();
|
|
47593
|
+
const detail = error48 instanceof Error ? error48.message : "Upload to storage failed.";
|
|
47594
|
+
console.error(colorError(detail));
|
|
47595
|
+
console.error(resumeHint(codeUploadId, filePath));
|
|
47596
|
+
process.exit(1);
|
|
47597
|
+
}
|
|
47598
|
+
const completed = await completeUpload(organizationId, codeUploadId);
|
|
47599
|
+
const upload = options.wait ? await waitForTerminal(organizationId, codeUploadId, runtime) : completed;
|
|
47600
|
+
if (options.wait) {
|
|
47601
|
+
if (process.stderr.isTTY) process.stderr.write("\n");
|
|
47602
|
+
printWaitOutcome(upload, output);
|
|
47603
|
+
return;
|
|
47604
|
+
}
|
|
47605
|
+
if (output === "table") {
|
|
47606
|
+
console.log(colorSuccess(`Uploaded ${sanitizeDisplay(upload.displayName)}.`));
|
|
47607
|
+
console.log(
|
|
47608
|
+
`Malware scanning is in progress. Check with: tracecli upload wait ${codeUploadId}`
|
|
47609
|
+
);
|
|
47610
|
+
}
|
|
47611
|
+
outputUpload(upload, output);
|
|
47612
|
+
}
|
|
47613
|
+
async function runCreate5(filePath, options, runtime) {
|
|
47614
|
+
const inferred = inferArtifactKindFromFilename(filePath);
|
|
47615
|
+
if (inferred != null && isApplicationBuildArtifactKind(inferred)) {
|
|
47616
|
+
console.error(
|
|
47617
|
+
colorError(
|
|
47618
|
+
"That file is a mobile build, not a source archive. Attach it to an existing application with:"
|
|
47619
|
+
)
|
|
47620
|
+
);
|
|
47621
|
+
console.error(" tracecli upload build <file> --app <applicationId>");
|
|
47622
|
+
process.exit(1);
|
|
47623
|
+
}
|
|
47624
|
+
await runTransfer(
|
|
47625
|
+
filePath,
|
|
47626
|
+
{
|
|
47627
|
+
...options.name !== void 0 ? { name: options.name } : {},
|
|
47628
|
+
...options.wait !== void 0 ? { wait: options.wait } : {},
|
|
47629
|
+
output: options.output,
|
|
47630
|
+
artifactKind: "SOURCE_ARCHIVE"
|
|
47631
|
+
},
|
|
47632
|
+
runtime
|
|
47633
|
+
);
|
|
47634
|
+
}
|
|
47635
|
+
async function runBuild(filePath, options, runtime) {
|
|
47636
|
+
const applicationId = requireUuid(options.app, "--app");
|
|
47637
|
+
const inferred = inferArtifactKindFromFilename(filePath);
|
|
47638
|
+
if (inferred == null || !isApplicationBuildArtifactKind(inferred)) {
|
|
47639
|
+
console.error(
|
|
47640
|
+
colorError(
|
|
47641
|
+
"Build uploads are an APK or IPA attached to an existing application. For a source ZIP, use `tracecli upload create <file>`."
|
|
47642
|
+
)
|
|
47643
|
+
);
|
|
47644
|
+
process.exit(1);
|
|
47645
|
+
}
|
|
47646
|
+
await runTransfer(
|
|
47647
|
+
filePath,
|
|
47648
|
+
{
|
|
47649
|
+
...options.name !== void 0 ? { name: options.name } : {},
|
|
47650
|
+
...options.wait !== void 0 ? { wait: options.wait } : {},
|
|
47651
|
+
output: options.output,
|
|
47652
|
+
applicationId,
|
|
47653
|
+
artifactKind: inferred
|
|
47654
|
+
},
|
|
47655
|
+
runtime
|
|
47656
|
+
);
|
|
47657
|
+
}
|
|
47658
|
+
async function runResume(codeUploadIdArg, filePath, options, runtime) {
|
|
47659
|
+
const output = parseOutput(options.output);
|
|
47660
|
+
const codeUploadId = requireUuid(codeUploadIdArg, "code upload id");
|
|
47661
|
+
let prepared;
|
|
47662
|
+
try {
|
|
47663
|
+
prepared = await prepareUploadFile(filePath);
|
|
47664
|
+
} catch (error48) {
|
|
47665
|
+
failPrepare(error48);
|
|
47666
|
+
}
|
|
47667
|
+
const organizationId = await resolveOrganizationId();
|
|
47668
|
+
const resumed = await authenticatedRequest(
|
|
47669
|
+
(client) => client.codeUpload.resumeCodeUpload({
|
|
47670
|
+
params: { organizationId, codeUploadId },
|
|
47671
|
+
body: {}
|
|
47672
|
+
})
|
|
47673
|
+
);
|
|
47674
|
+
if (resumed.status !== SUCCESS_STATUS) {
|
|
47675
|
+
failWriteOp5("resume", resumed.status, resumed.body);
|
|
47676
|
+
}
|
|
47677
|
+
try {
|
|
47678
|
+
assertPreparedMatchesUpload(resumed.body.upload, prepared);
|
|
47679
|
+
} catch (error48) {
|
|
47680
|
+
failPrepare(error48);
|
|
47681
|
+
}
|
|
47682
|
+
const uploadedBytes = resumed.body.multipart.uploadedParts.reduce(
|
|
47683
|
+
(sum, part) => sum + part.sizeBytes,
|
|
47684
|
+
0
|
|
47685
|
+
);
|
|
47686
|
+
if (output === "table") {
|
|
47687
|
+
console.error(
|
|
47688
|
+
`Resuming upload ${codeUploadId} (${formatArchiveBytes(uploadedBytes)} already stored).`
|
|
47689
|
+
);
|
|
47690
|
+
}
|
|
47691
|
+
try {
|
|
47692
|
+
await uploadCodeArchiveParts(
|
|
47693
|
+
prepared.path,
|
|
47694
|
+
prepared.sizeBytes,
|
|
47695
|
+
resumed.body.multipart.partSizeBytes,
|
|
47696
|
+
resumed.body.multipart.parts,
|
|
47697
|
+
{
|
|
47698
|
+
initialUploadedBytes: uploadedBytes,
|
|
47699
|
+
fetch: runtime.fetch,
|
|
47700
|
+
wait: runtime.wait,
|
|
47701
|
+
onProgress: writeProgress,
|
|
47702
|
+
refreshParts: () => refreshRemainingParts(organizationId, codeUploadId)
|
|
47703
|
+
}
|
|
47704
|
+
);
|
|
47705
|
+
finishProgress();
|
|
47706
|
+
} catch (error48) {
|
|
47707
|
+
finishProgress();
|
|
47708
|
+
const detail = error48 instanceof Error ? error48.message : "Upload to storage failed.";
|
|
47709
|
+
console.error(colorError(detail));
|
|
47710
|
+
console.error(resumeHint(codeUploadId, filePath));
|
|
47711
|
+
process.exit(1);
|
|
47712
|
+
}
|
|
47713
|
+
const completed = await completeUpload(organizationId, codeUploadId);
|
|
47714
|
+
const upload = options.wait ? await waitForTerminal(organizationId, codeUploadId, runtime) : completed;
|
|
47715
|
+
if (options.wait) {
|
|
47716
|
+
if (process.stderr.isTTY) process.stderr.write("\n");
|
|
47717
|
+
printWaitOutcome(upload, output);
|
|
47718
|
+
return;
|
|
47719
|
+
}
|
|
47720
|
+
if (output === "table") {
|
|
47721
|
+
console.log(colorSuccess(`Uploaded ${sanitizeDisplay(upload.displayName)}.`));
|
|
47722
|
+
console.log(
|
|
47723
|
+
`Malware scanning is in progress. Check with: tracecli upload wait ${codeUploadId}`
|
|
47724
|
+
);
|
|
47725
|
+
}
|
|
47726
|
+
outputUpload(upload, output);
|
|
47727
|
+
}
|
|
47728
|
+
async function runList5(options) {
|
|
47729
|
+
const output = parseOutput(options.output);
|
|
47730
|
+
if (options.web) {
|
|
47731
|
+
const slug = await resolveOrganizationSlug();
|
|
47732
|
+
const url2 = `${getAppBaseUrl()}/dashboard/${slug}/settings/integrations/sources`;
|
|
47733
|
+
const opened = await openBrowser(url2);
|
|
47734
|
+
if (!opened) console.log(url2);
|
|
47735
|
+
return;
|
|
47736
|
+
}
|
|
47737
|
+
const kind = parseKindOption(options.kind);
|
|
47738
|
+
const applicationId = options.app !== void 0 ? requireUuid(options.app, "--app") : void 0;
|
|
47739
|
+
const organizationId = await resolveOrganizationId();
|
|
47740
|
+
const uploads = await listUploads(organizationId, {
|
|
47741
|
+
...kind !== void 0 ? { artifactKind: kind } : {},
|
|
47742
|
+
...applicationId !== void 0 ? { applicationId } : {}
|
|
47743
|
+
});
|
|
47744
|
+
if (output === "json") {
|
|
47745
|
+
console.log(JSON.stringify({ uploads }, null, 2));
|
|
47746
|
+
return;
|
|
47747
|
+
}
|
|
47748
|
+
if (output === "tsv") {
|
|
47749
|
+
printUploadsTsv(uploads);
|
|
47750
|
+
return;
|
|
47751
|
+
}
|
|
47752
|
+
if (uploads.length === 0) {
|
|
47753
|
+
console.log("No source uploads found.");
|
|
47754
|
+
return;
|
|
47755
|
+
}
|
|
47756
|
+
const { header, rows } = buildUploadsTable(uploads);
|
|
47757
|
+
await runInteractivePager({
|
|
47758
|
+
items: uploads,
|
|
47759
|
+
header,
|
|
47760
|
+
renderItem: (_upload, i2) => [rows[i2] ?? ""],
|
|
47761
|
+
disabled: options.pager === false
|
|
47762
|
+
});
|
|
47763
|
+
}
|
|
47764
|
+
async function runGet4(codeUploadIdArg, options) {
|
|
47765
|
+
const output = parseOutput(options.output);
|
|
47766
|
+
const codeUploadId = requireUuid(codeUploadIdArg, "code upload id");
|
|
47767
|
+
const organizationId = await resolveOrganizationId();
|
|
47768
|
+
const upload = await requireUpload(organizationId, codeUploadId);
|
|
47769
|
+
outputUpload(upload, output);
|
|
47770
|
+
}
|
|
47771
|
+
async function runWait(codeUploadIdArg, options, runtime) {
|
|
47772
|
+
const output = parseOutput(options.output);
|
|
47773
|
+
const codeUploadId = requireUuid(codeUploadIdArg, "code upload id");
|
|
47774
|
+
const organizationId = await resolveOrganizationId();
|
|
47775
|
+
const upload = await waitForTerminal(organizationId, codeUploadId, runtime);
|
|
47776
|
+
if (process.stderr.isTTY) process.stderr.write("\n");
|
|
47777
|
+
printWaitOutcome(upload, output);
|
|
47778
|
+
}
|
|
47779
|
+
async function runDelete5(codeUploadIdArg, options) {
|
|
47780
|
+
const codeUploadId = requireUuid(codeUploadIdArg, "code upload id");
|
|
47781
|
+
const confirmed = await confirmDeletion(`upload ${codeUploadId}`, options.yes);
|
|
47782
|
+
if (!confirmed) {
|
|
47783
|
+
console.log("Aborted.");
|
|
47784
|
+
return;
|
|
47785
|
+
}
|
|
47786
|
+
const organizationId = await resolveOrganizationId();
|
|
47787
|
+
const result = await authenticatedRequest(
|
|
47788
|
+
(client) => client.codeUpload.deleteCodeUpload({
|
|
47789
|
+
params: { organizationId, codeUploadId }
|
|
47790
|
+
})
|
|
47791
|
+
);
|
|
47792
|
+
if (result.status !== NO_CONTENT_STATUS) {
|
|
47793
|
+
failWriteOp5("delete", result.status, result.body);
|
|
47794
|
+
}
|
|
47795
|
+
console.log(colorSuccess(`Deleted upload ${codeUploadId}`));
|
|
47796
|
+
}
|
|
47797
|
+
async function runLink(options) {
|
|
47798
|
+
const output = parseOutput(options.output);
|
|
47799
|
+
const applicationId = requireUuid(options.app, "--app");
|
|
47800
|
+
const codeUploadId = requireUuid(options.upload, "--upload");
|
|
47801
|
+
const organizationId = await resolveOrganizationId();
|
|
47802
|
+
const upload = await requireUpload(organizationId, codeUploadId);
|
|
47803
|
+
if (isApplicationBuildArtifactKind(upload.artifactKind)) {
|
|
47804
|
+
console.error(colorError("APK and IPA uploads cannot be linked as source repositories."));
|
|
47805
|
+
process.exit(1);
|
|
47806
|
+
}
|
|
47807
|
+
if (upload.status !== "READY" || upload.malwareScanResult !== "NO_THREATS_FOUND") {
|
|
47808
|
+
console.error(
|
|
47809
|
+
colorError(
|
|
47810
|
+
`Upload is ${formatStatus(upload.status)}; it must be ready and pass malware scanning before it can be linked.`
|
|
47811
|
+
)
|
|
47812
|
+
);
|
|
47813
|
+
process.exit(1);
|
|
47814
|
+
}
|
|
47815
|
+
const result = await authenticatedRequest(
|
|
47816
|
+
(client) => client.application.createApplicationRepository({
|
|
47817
|
+
params: { organizationId, applicationId },
|
|
47818
|
+
body: {
|
|
47819
|
+
repositoryId: upload.repositoryId,
|
|
47820
|
+
...options.path !== void 0 ? { repositoryPath: options.path } : {}
|
|
47821
|
+
}
|
|
47822
|
+
})
|
|
47823
|
+
);
|
|
47824
|
+
if (result.status !== CREATED_STATUS) {
|
|
47825
|
+
failWriteOp5("link", result.status, result.body);
|
|
47826
|
+
}
|
|
47827
|
+
if (output === "json") {
|
|
47828
|
+
console.log(JSON.stringify(result.body, null, 2));
|
|
47829
|
+
return;
|
|
47830
|
+
}
|
|
47831
|
+
if (output === "tsv") {
|
|
47832
|
+
console.log(["applicationId", "repositoryId", "codeUploadId"].join(" "));
|
|
47833
|
+
console.log([applicationId, upload.repositoryId, codeUploadId].join(" "));
|
|
47834
|
+
return;
|
|
47835
|
+
}
|
|
47836
|
+
console.log(
|
|
47837
|
+
colorSuccess(`Linked ${sanitizeDisplay(upload.displayName)} to application ${applicationId}.`)
|
|
47838
|
+
);
|
|
47839
|
+
}
|
|
47840
|
+
function createCreateCommand5(runtime) {
|
|
47841
|
+
return new Command("create").alias("source").description("Upload a source ZIP as a code archive (not a mobile build)").argument("<file>", "Path to a .zip source archive").option("--name <displayName>", "Display name (defaults to the filename without extension)").option("--wait", "Wait until malware scanning finishes").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
|
|
47842
|
+
"after",
|
|
47843
|
+
`
|
|
47844
|
+
This is a code upload: a source ZIP that becomes an uploaded repository after
|
|
47845
|
+
it is ready. Link it with \`upload link\`. APK and IPA files belong on
|
|
47846
|
+
\`upload build --app\`, which attaches a build to an existing application.
|
|
47847
|
+
|
|
47848
|
+
Requires a human login (\`tracecli auth login\`) on a pentest-enabled organization.
|
|
47849
|
+
API keys are rejected.
|
|
47850
|
+
|
|
47851
|
+
Examples:
|
|
47852
|
+
tracecli upload create ./checkout.zip
|
|
47853
|
+
tracecli upload create ./checkout.zip --name "Checkout" --wait`
|
|
47854
|
+
).action(async (file2, options) => {
|
|
47855
|
+
await runCreate5(file2, options, runtime);
|
|
47856
|
+
});
|
|
47857
|
+
}
|
|
47858
|
+
function createBuildCommand(runtime) {
|
|
47859
|
+
return new Command("build").description("Upload an APK or IPA and attach it to an existing application").argument("<file>", "Path to an .apk or .ipa").requiredOption("--app <applicationId>", "Application that owns this build").option("--name <displayName>", "Display name (defaults to the filename without extension)").option("--wait", "Wait until malware scanning finishes").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
|
|
47860
|
+
"after",
|
|
47861
|
+
`
|
|
47862
|
+
Build uploads are not source archives. They attach to --app immediately and
|
|
47863
|
+
cannot be linked as a repository. For a source ZIP, use \`upload create\`.
|
|
47864
|
+
|
|
47865
|
+
Examples:
|
|
47866
|
+
tracecli upload build ./app-release.apk --app <applicationId>
|
|
47867
|
+
tracecli upload build ./app.ipa --app <applicationId> --name "iOS build"`
|
|
47868
|
+
).action(async (file2, options) => {
|
|
47869
|
+
await runBuild(file2, options, runtime);
|
|
47870
|
+
});
|
|
47871
|
+
}
|
|
47872
|
+
function createListCommand7() {
|
|
47873
|
+
return new Command("list").description("List source and build uploads in the active organization").option("--kind <kind>", "Filter: source (code ZIP), apk, or ipa").option("--app <applicationId>", "Filter build uploads for one application").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").option("--no-pager", "Disable the interactive pager for table output").option("-w, --web", "Open the source uploads page in a browser").action(async (options) => {
|
|
47874
|
+
await runList5(options);
|
|
47875
|
+
});
|
|
47876
|
+
}
|
|
47877
|
+
function createGetCommand4() {
|
|
47878
|
+
return new Command("get").description("Show a single upload").argument("<codeUploadId>", "Upload UUID").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").action(async (codeUploadId, options) => {
|
|
47879
|
+
await runGet4(codeUploadId, options);
|
|
47880
|
+
});
|
|
47881
|
+
}
|
|
47882
|
+
function createResumeCommand(runtime) {
|
|
47883
|
+
return new Command("resume").description("Resume an interrupted upload with the same file").argument("<codeUploadId>", "Upload UUID from the interrupted create").argument("<file>", "The same .zip, .apk, or .ipa file").option("--wait", "Wait until malware scanning finishes").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
|
|
47884
|
+
"after",
|
|
47885
|
+
`
|
|
47886
|
+
The file must match the original size and SHA-256. Trace skips parts that
|
|
47887
|
+
already landed in storage.
|
|
47888
|
+
|
|
47889
|
+
Examples:
|
|
47890
|
+
tracecli upload resume <codeUploadId> ./checkout.zip`
|
|
47891
|
+
).action(async (codeUploadId, file2, options) => {
|
|
47892
|
+
await runResume(codeUploadId, file2, options, runtime);
|
|
47893
|
+
});
|
|
47894
|
+
}
|
|
47895
|
+
function createWaitCommand(runtime) {
|
|
47896
|
+
return new Command("wait").description("Wait until an upload finishes malware scanning and validation").argument("<codeUploadId>", "Upload UUID").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").action(async (codeUploadId, options) => {
|
|
47897
|
+
await runWait(codeUploadId, options, runtime);
|
|
47898
|
+
});
|
|
47899
|
+
}
|
|
47900
|
+
function createDeleteCommand5() {
|
|
47901
|
+
return new Command("delete").description("Delete an uploaded archive and its stored bytes").argument("<codeUploadId>", "Upload UUID").option("-y, --yes", "Skip the confirmation prompt (required in non-interactive shells)").action(async (codeUploadId, options) => {
|
|
47902
|
+
await runDelete5(codeUploadId, options);
|
|
47903
|
+
});
|
|
47904
|
+
}
|
|
47905
|
+
function createLinkCommand() {
|
|
47906
|
+
return new Command("link").description("Link a ready source upload to an application").requiredOption("--app <applicationId>", "Application UUID").requiredOption("--upload <codeUploadId>", "Upload UUID (must be a ready source ZIP)").option("--path <repositoryPath>", "Path within the archive").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
|
|
47907
|
+
"after",
|
|
47908
|
+
`
|
|
47909
|
+
Only a READY source archive that passed malware scanning can be linked.
|
|
47910
|
+
APK and IPA builds attach to an application with \`upload build --app\`.
|
|
47911
|
+
|
|
47912
|
+
Examples:
|
|
47913
|
+
tracecli upload link --app <applicationId> --upload <codeUploadId>`
|
|
47914
|
+
).action(async (options) => {
|
|
47915
|
+
await runLink(options);
|
|
47916
|
+
});
|
|
47917
|
+
}
|
|
47918
|
+
function createUploadCommand(runtime = {}) {
|
|
47919
|
+
const resolved = resolveRuntime(runtime);
|
|
47920
|
+
const upload = new Command("upload").alias("code-upload").description("Upload source archives (and separately, mobile builds) for pentest");
|
|
47921
|
+
upload.addCommand(createCreateCommand5(resolved));
|
|
47922
|
+
upload.addCommand(createBuildCommand(resolved));
|
|
47923
|
+
upload.addCommand(createListCommand7());
|
|
47924
|
+
upload.addCommand(createGetCommand4());
|
|
47925
|
+
upload.addCommand(createResumeCommand(resolved));
|
|
47926
|
+
upload.addCommand(createWaitCommand(resolved));
|
|
47927
|
+
upload.addCommand(createDeleteCommand5());
|
|
47928
|
+
upload.addCommand(createLinkCommand());
|
|
47929
|
+
return upload;
|
|
47930
|
+
}
|
|
47931
|
+
|
|
46696
47932
|
// src/vulnerabilities/commands.ts
|
|
46697
47933
|
var DEFAULT_LIMIT3 = 30;
|
|
46698
47934
|
var MAX_LIMIT3 = 100;
|
|
@@ -46869,7 +48105,7 @@ function printVulnerabilityDetailTsv(vulnerability) {
|
|
|
46869
48105
|
].map(sanitizeTsvField);
|
|
46870
48106
|
console.log(cols.join(" "));
|
|
46871
48107
|
}
|
|
46872
|
-
function
|
|
48108
|
+
function createGetCommand5() {
|
|
46873
48109
|
return new Command("get").description("Get a vulnerability by display ID or UUID").argument("<id>", "Vulnerability display ID (e.g. TRACE-123 or 123) or UUID").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").option("-w, --web", "Open the vulnerability detail page in a browser").addHelpText(
|
|
46874
48110
|
"after",
|
|
46875
48111
|
`
|
|
@@ -46928,7 +48164,7 @@ Run \`tracecli vulnerabilities list\` to see available vulnerabilities.`
|
|
|
46928
48164
|
printVulnerabilityDetail(result.body);
|
|
46929
48165
|
});
|
|
46930
48166
|
}
|
|
46931
|
-
function
|
|
48167
|
+
function createListCommand8() {
|
|
46932
48168
|
return new Command("list").description("List vulnerabilities for your organization").option("--repo <repo>", "Filter by repository name or owner/repo").option(
|
|
46933
48169
|
"--severity <severity>",
|
|
46934
48170
|
"Filter by severity (CRITICAL, HIGH, MEDIUM, LOW)",
|
|
@@ -47061,8 +48297,8 @@ Examples:
|
|
|
47061
48297
|
}
|
|
47062
48298
|
function createVulnerabilitiesCommand() {
|
|
47063
48299
|
const vulnerabilities = new Command("vulnerabilities").description("Manage vulnerabilities");
|
|
47064
|
-
vulnerabilities.addCommand(
|
|
47065
|
-
vulnerabilities.addCommand(
|
|
48300
|
+
vulnerabilities.addCommand(createGetCommand5());
|
|
48301
|
+
vulnerabilities.addCommand(createListCommand8());
|
|
47066
48302
|
return vulnerabilities;
|
|
47067
48303
|
}
|
|
47068
48304
|
|
|
@@ -47085,6 +48321,7 @@ program2.addCommand(createInboxCommand());
|
|
|
47085
48321
|
program2.addCommand(createRepoCommand());
|
|
47086
48322
|
program2.addCommand(createVulnerabilitiesCommand());
|
|
47087
48323
|
program2.addCommand(createCodeSizeCommand());
|
|
48324
|
+
program2.addCommand(createUploadCommand());
|
|
47088
48325
|
program2.addCommand(createPentestCommand());
|
|
47089
48326
|
program2.addCommand(createCompletionCommand(program2));
|
|
47090
48327
|
program2.addCommand(createUpgradeCommand());
|