securewithtrace 0.45.0 → 0.46.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.
Files changed (3) hide show
  1. package/README.md +6 -2
  2. package/dist/index.js +1262 -406
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3695,6 +3695,7 @@ var PENTEST_FINDING_STATUS_VALUES = [
3695
3695
  "REMEDIATED",
3696
3696
  "VERIFIED_FIXED",
3697
3697
  "VERIFIED_OPEN",
3698
+ "PARTIALLY_FIXED",
3698
3699
  "ACCEPTED_WITH_CONTROLS",
3699
3700
  "DISMISSED"
3700
3701
  ];
@@ -6292,7 +6293,7 @@ var $ZodBase64 = /* @__PURE__ */ $constructor("$ZodBase64", (inst, def) => {
6292
6293
  function isValidBase64URL(data) {
6293
6294
  if (!base64url.test(data))
6294
6295
  return false;
6295
- const base643 = data.replace(/[-_]/g, (c62) => c62 === "-" ? "+" : "/");
6296
+ const base643 = data.replace(/[-_]/g, (c65) => c65 === "-" ? "+" : "/");
6296
6297
  const padded = base643.padEnd(Math.ceil(base643.length / 4) * 4, "=");
6297
6298
  return isValidBase64(padded);
6298
6299
  }
@@ -16336,9 +16337,9 @@ var ZodDate = /* @__PURE__ */ $constructor("ZodDate", (inst, def) => {
16336
16337
  inst._zod.processJSONSchema = (ctx, json2, params) => dateProcessor(inst, ctx, json2, params);
16337
16338
  inst.min = (value, params) => inst.check(_gte(value, params));
16338
16339
  inst.max = (value, params) => inst.check(_lte(value, params));
16339
- const c62 = inst._zod.bag;
16340
- inst.minDate = c62.minimum ? new Date(c62.minimum) : null;
16341
- inst.maxDate = c62.maximum ? new Date(c62.maximum) : null;
16340
+ const c65 = inst._zod.bag;
16341
+ inst.minDate = c65.minimum ? new Date(c65.minimum) : null;
16342
+ inst.maxDate = c65.maximum ? new Date(c65.maximum) : null;
16342
16343
  });
16343
16344
  function date3(params) {
16344
16345
  return _date(ZodDate, params);
@@ -22162,6 +22163,8 @@ var AgentSessionFailureReasonValues = [
22162
22163
  "INTERNAL"
22163
22164
  ];
22164
22165
  var AgentSessionFailureReason = external_exports.enum(AgentSessionFailureReasonValues);
22166
+ var AgentSessionLaunchTargetValues = ["ECS", "LOCAL"];
22167
+ var AgentSessionLaunchTarget = external_exports.enum(AgentSessionLaunchTargetValues);
22165
22168
  var AgentSessionProviderValues = ["BEDROCK", "ANTHROPIC", "OPENAI"];
22166
22169
  var AgentSessionProvider = external_exports.enum(AgentSessionProviderValues);
22167
22170
  var AgentSessionEventKindValues = [
@@ -22194,6 +22197,9 @@ var MAX_AGENT_SESSION_OBJECTIVE_CHARS = 32e3;
22194
22197
  var CreateAgentSessionCommonSchema = external_exports.object({
22195
22198
  provider: AgentSessionProvider.optional(),
22196
22199
  model: external_exports.string().min(1).max(200).optional(),
22200
+ /** LOCAL leaves the launch for the caller to claim (`claimLocalLaunch`) instead of
22201
+ * submitting a Fargate task. Staff tooling only; the dashboard never sends it. */
22202
+ launchTarget: AgentSessionLaunchTarget.optional(),
22197
22203
  maxUsd: external_exports.number().positive().max(MAX_AGENT_SESSION_MAX_USD).optional(),
22198
22204
  maxWallClockMin: external_exports.number().int().positive().max(24 * 60).optional()
22199
22205
  });
@@ -22280,7 +22286,25 @@ var ResumeAgentSessionRequestSchema = external_exports.object({
22280
22286
  /** Budget raise — required to leave WAITING_ON_STAFF(BUDGET_EXHAUSTED). Same
22281
22287
  * lifetime ceiling as create: a raise past it is not expressible, which is why
22282
22288
  * the create cap had to move for the engagement-wide validator. */
22283
- maxUsd: external_exports.number().positive().max(MAX_AGENT_SESSION_MAX_USD).optional()
22289
+ maxUsd: external_exports.number().positive().max(MAX_AGENT_SESSION_MAX_USD).optional(),
22290
+ /** Move the session between the Fargate path and a staff-claimed local host. Omitted
22291
+ * keeps the row's current target. */
22292
+ launchTarget: AgentSessionLaunchTarget.optional()
22293
+ });
22294
+ var ClaimLocalLaunchResponseSchema = external_exports.object({
22295
+ agentSessionId: external_exports.uuid(),
22296
+ runAttemptId: external_exports.uuid(),
22297
+ runVersion: external_exports.number().int().positive(),
22298
+ /** The host image this environment's task definition runs (`<repo>:<assetHash>` in the
22299
+ * environment's ECR). Null when the environment has no deployed image (the local stack). */
22300
+ imageUri: external_exports.string().nullable(),
22301
+ /** The full container env contract: the same keys the ECS launch passes as container
22302
+ * overrides (`AGENT_SESSION_*` plus the credential env). Carries the run token, so it is
22303
+ * returned once and never logged. */
22304
+ env: external_exports.record(external_exports.string(), external_exports.string())
22305
+ });
22306
+ var LocalHostImageResponseSchema = external_exports.object({
22307
+ imageUri: external_exports.string().nullable()
22284
22308
  });
22285
22309
  var ListAgentSessionEventsQuerySchema = external_exports.object({
22286
22310
  /** Return events with seq > sinceSeq (poll cursor). */
@@ -22315,6 +22339,10 @@ var AgentSessionSummarySchema = external_exports.object({
22315
22339
  launchedAt: external_exports.coerce.date().nullable(),
22316
22340
  lastActivityAt: external_exports.coerce.date().nullable(),
22317
22341
  completedAt: external_exports.coerce.date().nullable(),
22342
+ launchTarget: AgentSessionLaunchTarget,
22343
+ /** Null while parked, and on a LOCAL row until its launch is claimed: LAUNCHING with this
22344
+ * null on a LOCAL row is "awaiting claim". */
22345
+ taskSubmittedAt: external_exports.coerce.date().nullable(),
22318
22346
  createdById: external_exports.uuid(),
22319
22347
  createdAt: external_exports.coerce.date(),
22320
22348
  updatedAt: external_exports.coerce.date()
@@ -22618,6 +22646,43 @@ var agentSessionContract = c2.router({
22618
22646
  500: ErrorResponseSchema
22619
22647
  }
22620
22648
  },
22649
+ // The host image this environment's agent-session task definition runs. Reads
22650
+ // config, mints nothing: it exists so a staff CLI can pull the image BEFORE it
22651
+ // creates or resumes a LOCAL session, keeping the boot deadline off the pull.
22652
+ getLocalHostImage: {
22653
+ method: "GET",
22654
+ path: "/organizations/:organizationId/agent-sessions/local-host-image",
22655
+ pathParams: OrgIdParamsSchema,
22656
+ responses: {
22657
+ 200: LocalHostImageResponseSchema,
22658
+ 401: ErrorResponseSchema,
22659
+ 403: ErrorResponseSchema,
22660
+ 500: ErrorResponseSchema
22661
+ }
22662
+ },
22663
+ // Claim a LOCAL session's launch: mints the run token and returns the container
22664
+ // env the ECS launch would have passed as overrides. Single-shot (a second
22665
+ // claim is 409): two containers must never hold valid tokens for one run.
22666
+ // Verified staff only: the response carries the token and the org's
22667
+ // customer credential env.
22668
+ claimLocalLaunch: {
22669
+ method: "POST",
22670
+ path: "/organizations/:organizationId/pentests/:pentestId/agent-sessions/:agentSessionId/local-launch",
22671
+ pathParams: AgentSessionIdParamsSchema,
22672
+ body: null,
22673
+ responses: {
22674
+ 200: ClaimLocalLaunchResponseSchema,
22675
+ 401: ErrorResponseSchema,
22676
+ 403: ErrorResponseSchema,
22677
+ 404: ErrorResponseSchema,
22678
+ // LAUNCH_TARGET_NOT_LOCAL (an ECS row) or LOCAL_LAUNCH_NOT_PENDING (already
22679
+ // claimed, parked, or terminal).
22680
+ 409: ErrorResponseSchema,
22681
+ 500: ErrorResponseSchema,
22682
+ // LOCAL_LAUNCH_UNCONFIGURED: this environment has no public host api URL.
22683
+ 503: ErrorResponseSchema
22684
+ }
22685
+ },
22621
22686
  // Staff "Review": advance a VALIDATION pentest VALIDATION_RUNNING →
22622
22687
  // AWAITING_VALIDATION_REVIEW WITHOUT terminating the session (it stays
22623
22688
  // IDLE/resumable for a customer-feedback follow-up). Distinct from stop, which
@@ -22858,6 +22923,145 @@ var ListAgentTasksQuerySchema = external_exports.object({
22858
22923
  });
22859
22924
  var ListAgentTasksResponseSchema = external_exports.array(AgentTaskResponseSchema);
22860
22925
 
22926
+ // ../../packages/api-contracts/src/schemas/api/v1/code-upload.api.ts
22927
+ var CODE_UPLOAD_MAX_BYTES = 1024 * 1024 * 1024;
22928
+ var CODE_UPLOAD_PART_SIZE_BYTES = 10 * 1024 * 1024;
22929
+ var CodeUploadStatusValues = [
22930
+ "UPLOADING",
22931
+ "FINALIZING",
22932
+ "SCANNING",
22933
+ "VALIDATING",
22934
+ "READY",
22935
+ "REJECTED",
22936
+ "DELETING",
22937
+ "FAILED"
22938
+ ];
22939
+ var CodeUploadMalwareScanResultValues = [
22940
+ "NO_THREATS_FOUND",
22941
+ "THREATS_FOUND",
22942
+ "UNSUPPORTED",
22943
+ "ACCESS_DENIED",
22944
+ "FAILED"
22945
+ ];
22946
+ var CodeUploadRejectionReasonValues = [
22947
+ "MALWARE_DETECTED",
22948
+ "MALWARE_SCAN_UNSUPPORTED",
22949
+ "MALWARE_SCAN_UNAVAILABLE",
22950
+ "INVALID_ARCHIVE",
22951
+ "INTEGRITY_MISMATCH"
22952
+ ];
22953
+ var CodeUploadArtifactKindValues = ["SOURCE_ARCHIVE", "ANDROID_APK", "IOS_IPA"];
22954
+ function isApplicationBuildArtifactKind(kind) {
22955
+ return kind === "ANDROID_APK" || kind === "IOS_IPA";
22956
+ }
22957
+ var CodeUploadIdParamsSchema = OrgIdParamsSchema.extend({
22958
+ codeUploadId: external_exports.uuid()
22959
+ });
22960
+ var ListCodeUploadsQuerySchema = external_exports.object({
22961
+ artifactKind: external_exports.enum(CodeUploadArtifactKindValues).optional(),
22962
+ applicationId: external_exports.uuid().optional()
22963
+ }).strict();
22964
+ var InitializeCodeUploadRequestSchema = external_exports.object({
22965
+ displayName: external_exports.string().trim().min(1).max(200),
22966
+ originalFilename: external_exports.string().trim().min(1).max(255),
22967
+ sizeBytes: external_exports.number().int().min(1).max(CODE_UPLOAD_MAX_BYTES),
22968
+ archiveSha256: external_exports.string().regex(/^[0-9a-f]{64}$/),
22969
+ // Defaulted so a pre-this-release client that omitted the field still
22970
+ // initializes a source ZIP during a mixed-version rollout.
22971
+ artifactKind: external_exports.enum(CodeUploadArtifactKindValues).default("SOURCE_ARCHIVE"),
22972
+ applicationId: external_exports.uuid().optional()
22973
+ }).strict().superRefine((data, ctx) => {
22974
+ const filename = data.originalFilename.toLowerCase();
22975
+ if (isApplicationBuildArtifactKind(data.artifactKind)) {
22976
+ const extension = data.artifactKind === "ANDROID_APK" ? ".apk" : ".ipa";
22977
+ if (!filename.endsWith(extension)) {
22978
+ ctx.addIssue({
22979
+ code: "custom",
22980
+ path: ["originalFilename"],
22981
+ message: `originalFilename must end in ${extension}`
22982
+ });
22983
+ }
22984
+ if (data.applicationId == null) {
22985
+ ctx.addIssue({
22986
+ code: "custom",
22987
+ path: ["applicationId"],
22988
+ message: "A build upload must target a mobile application."
22989
+ });
22990
+ }
22991
+ return;
22992
+ }
22993
+ if (!filename.endsWith(".zip")) {
22994
+ ctx.addIssue({
22995
+ code: "custom",
22996
+ path: ["originalFilename"],
22997
+ message: "originalFilename must end in .zip"
22998
+ });
22999
+ }
23000
+ if (data.applicationId != null) {
23001
+ ctx.addIssue({
23002
+ code: "custom",
23003
+ path: ["applicationId"],
23004
+ message: "Source archives are linked to an application after they are ready."
23005
+ });
23006
+ }
23007
+ });
23008
+ var LinkedCodeUploadApplicationSchema = external_exports.object({
23009
+ applicationId: external_exports.uuid(),
23010
+ name: external_exports.string()
23011
+ });
23012
+ var CodeUploadSchema = external_exports.object({
23013
+ codeUploadId: external_exports.uuid(),
23014
+ repositoryId: external_exports.uuid(),
23015
+ displayName: external_exports.string(),
23016
+ originalFilename: external_exports.string(),
23017
+ sizeBytes: external_exports.number().int().positive(),
23018
+ archiveSha256: external_exports.string().regex(/^[0-9a-f]{64}$/),
23019
+ status: external_exports.enum(CodeUploadStatusValues),
23020
+ malwareScanResult: external_exports.enum(CodeUploadMalwareScanResultValues).nullable(),
23021
+ rejectionReason: external_exports.enum(CodeUploadRejectionReasonValues).nullable(),
23022
+ // Defaulted so a new client reading a pre-this-release API during a rolling
23023
+ // deploy doesn't reject source-upload rows that omit the field.
23024
+ artifactKind: external_exports.enum(CodeUploadArtifactKindValues).default("SOURCE_ARCHIVE"),
23025
+ applicationId: external_exports.uuid().nullable().default(null),
23026
+ // z.coerce.date(), not z.date(): web server actions safeParse the raw
23027
+ // ts-rest JSON body, where these arrive as ISO strings.
23028
+ scanningStartedAt: external_exports.coerce.date().nullable(),
23029
+ readyAt: external_exports.coerce.date().nullable(),
23030
+ createdAt: external_exports.coerce.date(),
23031
+ linkedApplications: external_exports.array(LinkedCodeUploadApplicationSchema)
23032
+ });
23033
+ var CodeUploadPartUrlSchema = external_exports.object({
23034
+ partNumber: external_exports.number().int().positive(),
23035
+ uploadUrl: external_exports.url()
23036
+ });
23037
+ var UploadedCodeUploadPartSchema = external_exports.object({
23038
+ partNumber: external_exports.number().int().positive(),
23039
+ sizeBytes: external_exports.number().int().positive()
23040
+ });
23041
+ var CodeUploadMultipartSchema = external_exports.object({
23042
+ partSizeBytes: external_exports.literal(CODE_UPLOAD_PART_SIZE_BYTES),
23043
+ parts: external_exports.array(CodeUploadPartUrlSchema),
23044
+ expiresAt: external_exports.coerce.date()
23045
+ });
23046
+ var InitializeCodeUploadResponseSchema = external_exports.object({
23047
+ upload: CodeUploadSchema,
23048
+ multipart: CodeUploadMultipartSchema
23049
+ });
23050
+ var ResumeCodeUploadResponseSchema = external_exports.object({
23051
+ upload: CodeUploadSchema,
23052
+ multipart: CodeUploadMultipartSchema.extend({
23053
+ uploadedParts: external_exports.array(UploadedCodeUploadPartSchema)
23054
+ })
23055
+ });
23056
+ var ListCodeUploadsResponseSchema = external_exports.object({
23057
+ uploads: external_exports.array(CodeUploadSchema)
23058
+ });
23059
+ var DownloadCodeUploadResponseSchema = external_exports.object({
23060
+ upload: CodeUploadSchema,
23061
+ downloadUrl: external_exports.url(),
23062
+ expiresAt: external_exports.coerce.date()
23063
+ });
23064
+
22861
23065
  // ../../packages/api-contracts/src/schemas/api/v1/inbox.api.ts
22862
23066
  var InboxLabelSchema = external_exports.string().regex(
22863
23067
  /^[a-z][a-z0-9-]{0,39}$/,
@@ -22930,6 +23134,87 @@ var GetInboxMessageResponseSchema = external_exports.object({
22930
23134
  })
22931
23135
  });
22932
23136
 
23137
+ // ../../packages/api-contracts/src/schemas/api/v1/payment-card.api.ts
23138
+ var PAYMENT_CARD_NOTES_MAX = 2e3;
23139
+ function passesLuhn(digits) {
23140
+ if (!/^\d+$/.test(digits)) return false;
23141
+ let sum = 0;
23142
+ let double = false;
23143
+ for (let i2 = digits.length - 1; i2 >= 0; i2--) {
23144
+ let d = digits.charCodeAt(i2) - 48;
23145
+ if (double) {
23146
+ d *= 2;
23147
+ if (d > 9) d -= 9;
23148
+ }
23149
+ sum += d;
23150
+ double = !double;
23151
+ }
23152
+ return sum % 10 === 0;
23153
+ }
23154
+ var PaymentCardIdParamsSchema = external_exports.object({
23155
+ paymentCardId: external_exports.uuid()
23156
+ });
23157
+ var PaymentCardBillingAddressSchema = external_exports.object({
23158
+ line1: external_exports.string().min(1).max(200),
23159
+ line2: external_exports.string().max(200).optional(),
23160
+ city: external_exports.string().min(1).max(100),
23161
+ region: external_exports.string().max(100).optional(),
23162
+ postalCode: external_exports.string().min(1).max(20),
23163
+ /** ISO 3166-1 alpha-2, upper-cased by the service. */
23164
+ country: external_exports.string().regex(/^[A-Za-z]{2}$/, "Country is a two-letter code, like US.")
23165
+ }).strict();
23166
+ var CardNumberSchema = external_exports.string().regex(/^\d{12,19}$/, "Card number must be 12 to 19 digits.").refine(passesLuhn, { message: "Card number fails its check digit." });
23167
+ var CardCvcSchema = external_exports.string().regex(/^\d{3,4}$/, "CVC must be 3 or 4 digits.");
23168
+ var CardExpMonthSchema = external_exports.number().int().min(1).max(12);
23169
+ var CardExpYearSchema = external_exports.number().int().min(2026).max(2100);
23170
+ var PaymentCardResponseSchema = external_exports.object({
23171
+ paymentCardId: external_exports.uuid(),
23172
+ label: external_exports.string(),
23173
+ last4: external_exports.string(),
23174
+ expMonth: external_exports.number().int(),
23175
+ expYear: external_exports.number().int(),
23176
+ cardholderName: external_exports.string(),
23177
+ billingAddress: PaymentCardBillingAddressSchema,
23178
+ notes: external_exports.string(),
23179
+ active: external_exports.boolean(),
23180
+ /** Expiry month is before the current UTC month; the gate treats such a card as absent. */
23181
+ expired: external_exports.boolean(),
23182
+ /** Purchases with status AUTHORIZED or COMPLETED, across every engagement. */
23183
+ purchaseCount: external_exports.number().int(),
23184
+ /** Sum of those purchases' amounts, USD. Answers "how close to the issuer limit". */
23185
+ committedUsd: external_exports.number(),
23186
+ /**
23187
+ * False once ANY purchase row references the card, whatever its status: the
23188
+ * FK is Restrict, so delete would be refused. The UI offers Turn off instead.
23189
+ */
23190
+ deletable: external_exports.boolean(),
23191
+ createdAt: external_exports.date(),
23192
+ updatedAt: external_exports.date()
23193
+ }).strict();
23194
+ var ListPaymentCardsResponseSchema = external_exports.array(PaymentCardResponseSchema);
23195
+ var CreatePaymentCardRequestSchema = external_exports.object({
23196
+ label: external_exports.string().min(1).max(200),
23197
+ number: CardNumberSchema,
23198
+ cvc: CardCvcSchema,
23199
+ expMonth: CardExpMonthSchema,
23200
+ expYear: CardExpYearSchema,
23201
+ cardholderName: external_exports.string().min(1).max(200),
23202
+ billingAddress: PaymentCardBillingAddressSchema,
23203
+ notes: external_exports.string().max(PAYMENT_CARD_NOTES_MAX).optional(),
23204
+ /**
23205
+ * Defaults true. Creating an active card deactivates the current active card
23206
+ * in the same transaction.
23207
+ */
23208
+ active: external_exports.boolean().optional()
23209
+ }).strict();
23210
+ var UpdatePaymentCardRequestSchema = external_exports.object({
23211
+ label: external_exports.string().min(1).max(200).optional(),
23212
+ cardholderName: external_exports.string().min(1).max(200).optional(),
23213
+ billingAddress: PaymentCardBillingAddressSchema.optional(),
23214
+ notes: external_exports.string().max(PAYMENT_CARD_NOTES_MAX).optional(),
23215
+ active: external_exports.boolean().optional()
23216
+ }).strict();
23217
+
22933
23218
  // ../../packages/api-contracts/src/schemas/api/v1/pentest-attack-chain.api.ts
22934
23219
  var PentestAttackChainParamsSchema = OrgIdParamsSchema.extend({
22935
23220
  pentestId: external_exports.uuid()
@@ -23185,6 +23470,8 @@ var RepositoryResponseSchema = external_exports.object({
23185
23470
  prScansEnabled: external_exports.boolean(),
23186
23471
  /** Customer-set gate: false = no scans of any kind run for this repo until it is included again. */
23187
23472
  includedInScanning: external_exports.boolean(),
23473
+ /** Host archive flag mirrored from the provider. */
23474
+ isArchived: external_exports.boolean(),
23188
23475
  createdAt: external_exports.date(),
23189
23476
  updatedAt: external_exports.date()
23190
23477
  });
@@ -23715,6 +24002,10 @@ var ReportCanvasFindingSchema = external_exports.object({
23715
24002
  */
23716
24003
  description: external_exports.string(),
23717
24004
  proofOfConcept: external_exports.string().nullable(),
24005
+ /** Customer-visible acceptance rationale a RAW-rendered ACCEPTED_WITH_CONTROLS
24006
+ * finding shows under Compensating Controls; null otherwise. Optional while the
24007
+ * web and API roll independently. */
24008
+ acceptanceRationale: external_exports.string().nullable().optional(),
23718
24009
  // Per-finding prose staleness (precise — keyed to the finding's own columns).
23719
24010
  proseConfirmed: external_exports.boolean(),
23720
24011
  statusFramingStale: external_exports.boolean(),
@@ -23974,6 +24265,9 @@ var IssuedFindingSnapshotSchema = external_exports.object({
23974
24265
  description: external_exports.string(),
23975
24266
  proofOfConcept: external_exports.string().nullable(),
23976
24267
  remediation: external_exports.string().nullable(),
24268
+ /** Compensating Controls text of a RAW-rendered ACCEPTED_WITH_CONTROLS finding;
24269
+ * null otherwise. Optional so pre-feature issue snapshots remain parseable. */
24270
+ acceptanceRationale: external_exports.string().nullable().optional(),
23977
24271
  repositories: external_exports.array(
23978
24272
  external_exports.object({
23979
24273
  repositoryName: external_exports.string(),
@@ -25003,12 +25297,22 @@ var StartProgressPentestFindingRequestSchema = external_exports.object({});
25003
25297
  var ReportRemediationPentestFindingRequestSchema = external_exports.object({
25004
25298
  note: external_exports.string().trim().min(1).max(1e4).optional()
25005
25299
  });
25006
- var AutomationFindingTransitionSchema = external_exports.enum(["IN_PROGRESS", "REMEDIATED"]);
25300
+ var AcceptCustomerPentestFindingRequestSchema = external_exports.object({
25301
+ rationale: external_exports.string().trim().min(1).max(1e4)
25302
+ });
25303
+ var AutomationFindingTransitionSchema = external_exports.enum([
25304
+ "IN_PROGRESS",
25305
+ "REMEDIATED",
25306
+ "ACCEPTED_WITH_CONTROLS"
25307
+ ]);
25007
25308
  var AutomationStatusUpdateRequestSchema = external_exports.object({
25008
25309
  status: AutomationFindingTransitionSchema,
25009
25310
  note: external_exports.string().trim().min(1).max(1e4).optional()
25010
- }).refine((value) => value.note === void 0 || value.status === "REMEDIATED", {
25011
- message: "note is only accepted when reporting remediation (status REMEDIATED)",
25311
+ }).refine((value) => value.note === void 0 || value.status !== "IN_PROGRESS", {
25312
+ message: "note is not accepted when starting progress (status IN_PROGRESS)",
25313
+ path: ["note"]
25314
+ }).refine((value) => value.note !== void 0 || value.status !== "ACCEPTED_WITH_CONTROLS", {
25315
+ message: "note is required when accepting a finding (status ACCEPTED_WITH_CONTROLS)",
25012
25316
  path: ["note"]
25013
25317
  });
25014
25318
  var ReopenPentestFindingTargetStatusSchema = external_exports.enum(["OPEN", "IN_PROGRESS"]);
@@ -25025,10 +25329,11 @@ var retestVerificationOnlyOnFixed = (value, ctx) => {
25025
25329
  });
25026
25330
  }
25027
25331
  };
25332
+ var PENTEST_FINDING_RETEST_VERIFICATION_MAX_LENGTH = 8e3;
25028
25333
  var CreatePentestFindingRetestRequestSchema = external_exports.object({
25029
25334
  outcome: ManualRetestOutcome,
25030
25335
  notes: external_exports.string().trim().min(1).max(1e4),
25031
- verification: external_exports.string().trim().min(1).max(8e3).optional()
25336
+ verification: external_exports.string().trim().min(1).max(PENTEST_FINDING_RETEST_VERIFICATION_MAX_LENGTH).optional()
25032
25337
  });
25033
25338
  var CreatePentestFindingRetestBodySchema = CreatePentestFindingRetestRequestSchema.superRefine(retestVerificationOnlyOnFixed);
25034
25339
  var CreatePentestFindingNoteRequestSchema = external_exports.object({
@@ -25224,6 +25529,46 @@ var PromotePentestHypothesisRequestSchema = external_exports.object({
25224
25529
  manualFindingIds: HypothesisSourceIdsSchema.optional()
25225
25530
  }).strict().optional();
25226
25531
 
25532
+ // ../../packages/api-contracts/src/schemas/api/v1/pentest-purchase.api.ts
25533
+ var PurchaseStatusValues = ["AUTHORIZED", "COMPLETED", "DECLINED", "VOIDED"];
25534
+ var PurchaseStatus = external_exports.enum(PurchaseStatusValues);
25535
+ var PurchaseOutcomeValues = ["COMPLETED", "DECLINED"];
25536
+ var PurchaseOutcome = external_exports.enum(PurchaseOutcomeValues);
25537
+ var PentestPurchaseParamsSchema = OrgIdParamsSchema.extend({
25538
+ pentestId: PentestIdOrDisplayIdSchema
25539
+ });
25540
+ var PentestPurchaseIdParamsSchema = PentestPurchaseParamsSchema.extend({
25541
+ purchaseId: external_exports.uuid()
25542
+ });
25543
+ var PentestPurchaseSchema = external_exports.object({
25544
+ purchaseId: external_exports.uuid(),
25545
+ agentSessionId: external_exports.uuid(),
25546
+ agentSessionType: AgentSessionType,
25547
+ paymentCardLabel: external_exports.string(),
25548
+ paymentCardLast4: external_exports.string(),
25549
+ amountUsd: external_exports.number(),
25550
+ merchant: external_exports.string(),
25551
+ purpose: external_exports.string(),
25552
+ status: PurchaseStatus,
25553
+ voidedAt: external_exports.coerce.date().nullable(),
25554
+ voidedByLabel: external_exports.string().nullable(),
25555
+ voidReason: external_exports.string().nullable(),
25556
+ createdAt: external_exports.coerce.date(),
25557
+ updatedAt: external_exports.coerce.date()
25558
+ }).strict();
25559
+ var ListPentestPurchasesResponseSchema = external_exports.object({
25560
+ capUsd: external_exports.number(),
25561
+ /** Every AUTHORIZED and COMPLETED amount, summed in cents. */
25562
+ committedUsd: external_exports.number(),
25563
+ /** `capUsd - committedUsd`, never below 0 (a cap lowered under the committed sum). */
25564
+ remainingUsd: external_exports.number(),
25565
+ /** Newest first. */
25566
+ purchases: external_exports.array(PentestPurchaseSchema)
25567
+ }).strict();
25568
+ var VoidPentestPurchaseRequestSchema = external_exports.object({
25569
+ reason: external_exports.string().trim().min(1).max(1e3)
25570
+ }).strict();
25571
+
25227
25572
  // ../../packages/api-contracts/src/schemas/api/v1/pentest.api.ts
25228
25573
  var PentestIdParamsSchema = OrgIdParamsSchema.extend({
25229
25574
  pentestId: external_exports.string().min(1)
@@ -25243,6 +25588,10 @@ var CustomerPentestStatusValues = [
25243
25588
  "PAUSED"
25244
25589
  ];
25245
25590
  var CustomerPentestStatus = external_exports.enum(CustomerPentestStatusValues);
25591
+ var PentestFindingStatusCountShape = Object.fromEntries(
25592
+ PentestFindingStatusValues.map((status) => [status, external_exports.number().default(0)])
25593
+ );
25594
+ var PentestFindingStatusCountsByStatusSchema = external_exports.object(PentestFindingStatusCountShape).catchall(external_exports.number());
25246
25595
  var BoundPentestApplicationSchema = external_exports.object({
25247
25596
  applicationId: external_exports.uuid(),
25248
25597
  name: external_exports.string(),
@@ -25302,6 +25651,12 @@ var PentestResponseSchema = external_exports.object({
25302
25651
  hypothesisBudgetCapUsd: external_exports.number(),
25303
25652
  validationBudgetCapUsd: external_exports.number(),
25304
25653
  perHypothesisBudgetCapUsd: external_exports.number(),
25654
+ /**
25655
+ * Per-engagement purchase allowance (USD; 0 = purchasing off). `.optional()`
25656
+ * for the rolling-deploy reason `testType` states above: the staff panel
25657
+ * renders the row read-only when an older API omits it.
25658
+ */
25659
+ purchaseCapUsd: external_exports.number().optional(),
25305
25660
  startedAt: external_exports.coerce.date().nullable(),
25306
25661
  endedAt: external_exports.coerce.date().nullable(),
25307
25662
  /**
@@ -25317,7 +25672,7 @@ var PentestResponseSchema = external_exports.object({
25317
25672
  findingCounts: external_exports.object({
25318
25673
  total: external_exports.number(),
25319
25674
  bySeverity: external_exports.record(PentestFindingSeverity, external_exports.number()),
25320
- byStatus: external_exports.record(PentestFindingStatus, external_exports.number())
25675
+ byStatus: PentestFindingStatusCountsByStatusSchema
25321
25676
  })
25322
25677
  });
25323
25678
  var ListPentestsResponseSchema = external_exports.array(PentestResponseSchema);
@@ -25373,7 +25728,7 @@ var CustomerPentestShellResponseSchema = external_exports.object({
25373
25728
  findingCounts: external_exports.object({
25374
25729
  total: external_exports.number(),
25375
25730
  bySeverity: external_exports.record(PentestFindingSeverity, external_exports.number()),
25376
- byStatus: external_exports.record(PentestFindingStatus, external_exports.number())
25731
+ byStatus: PentestFindingStatusCountsByStatusSchema
25377
25732
  })
25378
25733
  });
25379
25734
  var ListCustomerPentestShellsResponseSchema = external_exports.array(CustomerPentestShellResponseSchema);
@@ -25498,7 +25853,8 @@ var CreatePentestRequestSchema = external_exports.object({
25498
25853
  customerPriorityCategories: external_exports.array(CustomerPriorityCategory).max(20).optional(),
25499
25854
  hypothesisBudgetCapUsd: external_exports.number().min(0).max(1e5).optional(),
25500
25855
  validationBudgetCapUsd: external_exports.number().min(0).max(1e5).optional(),
25501
- perHypothesisBudgetCapUsd: external_exports.number().min(0).max(1e5).optional()
25856
+ perHypothesisBudgetCapUsd: external_exports.number().min(0).max(1e5).optional(),
25857
+ purchaseCapUsd: external_exports.number().min(0).max(1e5).optional()
25502
25858
  });
25503
25859
  var UpdatePentestRequestSchema = external_exports.object({
25504
25860
  title: external_exports.string().min(1).max(500).optional(),
@@ -25529,6 +25885,7 @@ var UpdatePentestRequestSchema = external_exports.object({
25529
25885
  hypothesisBudgetCapUsd: external_exports.number().min(0).max(1e5).optional(),
25530
25886
  validationBudgetCapUsd: external_exports.number().min(0).max(1e5).optional(),
25531
25887
  perHypothesisBudgetCapUsd: external_exports.number().min(0).max(1e5).optional(),
25888
+ purchaseCapUsd: external_exports.number().min(0).max(1e5).optional(),
25532
25889
  lifecycleReason: external_exports.string().trim().min(1).max(2e3).optional()
25533
25890
  });
25534
25891
  var BindPentestApplicationRequestSchema = external_exports.object({
@@ -25643,13 +26000,13 @@ var StorageStateSchema = external_exports.object({
25643
26000
  } catch {
25644
26001
  return;
25645
26002
  }
25646
- s.cookies.forEach((c62, i2) => {
25647
- const d = c62.domain.replace(/^\./, "").toLowerCase();
26003
+ s.cookies.forEach((c65, i2) => {
26004
+ const d = c65.domain.replace(/^\./, "").toLowerCase();
25648
26005
  if (d !== host && !host.endsWith(`.${d}`)) {
25649
26006
  ctx.addIssue({
25650
26007
  code: "custom",
25651
26008
  path: ["cookies", i2, "domain"],
25652
- message: `cookie domain "${c62.domain}" is not the capture origin host "${host}" or a parent domain of it`
26009
+ message: `cookie domain "${c65.domain}" is not the capture origin host "${host}" or a parent domain of it`
25653
26010
  });
25654
26011
  }
25655
26012
  });
@@ -25876,6 +26233,7 @@ var DesktopTargetStatusValues = [
25876
26233
  "TERMINATED",
25877
26234
  "FAILED"
25878
26235
  ];
26236
+ var DesktopTargetPlatformValues = ["WINDOWS", "MACOS"];
25879
26237
  var DesktopActionStatusValues = [
25880
26238
  "PENDING",
25881
26239
  "CLAIMED",
@@ -26796,6 +27154,103 @@ var AgentSessionSshPrivateKeyResponseSchema = external_exports.object({
26796
27154
  */
26797
27155
  secret: SshPrivateKeySecretSchema
26798
27156
  });
27157
+ var AgentSessionAndroidBuildSchema = CodeUploadSchema.pick({
27158
+ codeUploadId: true,
27159
+ displayName: true,
27160
+ originalFilename: true,
27161
+ archiveSha256: true,
27162
+ status: true,
27163
+ malwareScanResult: true
27164
+ }).extend({
27165
+ applicationId: external_exports.uuid(),
27166
+ applicationName: external_exports.string(),
27167
+ sizeBytes: external_exports.number().int().positive().max(CODE_UPLOAD_MAX_BYTES),
27168
+ createdAt: external_exports.iso.datetime()
27169
+ });
27170
+ var AgentSessionListAndroidBuildsRequestSchema = external_exports.object({
27171
+ runVersion: external_exports.number().int().nonnegative(),
27172
+ afterCodeUploadId: external_exports.uuid().optional()
27173
+ });
27174
+ var AgentSessionListAndroidBuildsResponseSchema = external_exports.object({
27175
+ builds: external_exports.array(AgentSessionAndroidBuildSchema).max(50),
27176
+ nextAfterCodeUploadId: external_exports.uuid().nullable()
27177
+ });
27178
+ var AgentSessionGetAndroidBuildRequestSchema = external_exports.object({
27179
+ runVersion: external_exports.number().int().nonnegative(),
27180
+ codeUploadId: external_exports.uuid()
27181
+ });
27182
+ var AgentSessionAndroidBuildGrantSchema = AgentSessionAndroidBuildSchema.pick({
27183
+ codeUploadId: true,
27184
+ applicationId: true,
27185
+ archiveSha256: true,
27186
+ sizeBytes: true
27187
+ }).extend({
27188
+ downloadUrl: external_exports.url(),
27189
+ urlExpiresAt: external_exports.iso.datetime()
27190
+ });
27191
+ var AgentSessionListTestIntegrationsRequestSchema = external_exports.object({
27192
+ runVersion: external_exports.number().int().nonnegative()
27193
+ });
27194
+ var AgentSessionListTestIntegrationsResponseSchema = external_exports.object({
27195
+ /** Every Trace test integration by label, ascending. Empty when none exist. */
27196
+ labels: external_exports.array(external_exports.string())
27197
+ });
27198
+ var AgentSessionGetTestIntegrationRequestSchema = external_exports.object({
27199
+ runVersion: external_exports.number().int().nonnegative(),
27200
+ label: external_exports.string().min(1).max(200)
27201
+ });
27202
+ var AgentSessionTestIntegrationResponseSchema = external_exports.object({
27203
+ testIntegrationId: external_exports.uuid(),
27204
+ label: external_exports.string(),
27205
+ /** Staff-written, non-secret access instructions. */
27206
+ notes: external_exports.string(),
27207
+ /** Verbatim as stored: the host seeds its redactor with these exact bytes. */
27208
+ apiKey: external_exports.string().optional(),
27209
+ login: external_exports.object({ username: external_exports.string(), password: external_exports.string() }).optional()
27210
+ });
27211
+ var AgentSessionRequestPaymentCardRequestSchema = external_exports.object({
27212
+ runVersion: external_exports.number().int().nonnegative(),
27213
+ /** Minted by the host per tool call; reused across that call's HTTP retries. */
27214
+ requestKey: external_exports.uuid(),
27215
+ /** USD, two decimals: what the agent expects the merchant to charge. */
27216
+ amountUsd: external_exports.number().positive().max(1e4).multipleOf(0.01),
27217
+ merchant: external_exports.string().min(1).max(200),
27218
+ purpose: external_exports.string().min(1).max(1e3)
27219
+ });
27220
+ var AgentSessionPaymentCardResponseSchema = external_exports.object({
27221
+ purchaseId: external_exports.uuid(),
27222
+ /** True when this response replays an authorization an earlier attempt already committed. */
27223
+ replayed: external_exports.boolean(),
27224
+ paymentCardId: external_exports.uuid(),
27225
+ label: external_exports.string(),
27226
+ last4: external_exports.string(),
27227
+ expMonth: external_exports.number().int(),
27228
+ expYear: external_exports.number().int(),
27229
+ cardholderName: external_exports.string(),
27230
+ billingAddress: PaymentCardBillingAddressSchema,
27231
+ /** Staff-written, non-secret: the billing email to give, what the issuer declines. */
27232
+ notes: external_exports.string(),
27233
+ /** Cap minus every AUTHORIZED and COMPLETED amount for this pentest, this one included. */
27234
+ remainingUsd: external_exports.number(),
27235
+ capUsd: external_exports.number(),
27236
+ /** Verbatim as stored: the host seeds its redactor with these exact bytes. */
27237
+ number: external_exports.string(),
27238
+ cvc: external_exports.string()
27239
+ });
27240
+ var AgentSessionReportPurchaseOutcomeRequestSchema = external_exports.object({
27241
+ runVersion: external_exports.number().int().nonnegative(),
27242
+ purchaseId: external_exports.uuid(),
27243
+ outcome: PurchaseOutcome
27244
+ });
27245
+ var AgentSessionPurchaseOutcomeResponseSchema = external_exports.object({
27246
+ purchaseId: external_exports.uuid(),
27247
+ /** The row's status after the call. */
27248
+ status: PurchaseStatus,
27249
+ /** True when the row already carried this outcome (a retried report). */
27250
+ replayed: external_exports.boolean(),
27251
+ remainingUsd: external_exports.number(),
27252
+ capUsd: external_exports.number()
27253
+ });
26799
27254
  var AgentSessionPasskeySchema = external_exports.object({
26800
27255
  /** Relying party id (a hostname). */
26801
27256
  rpId: external_exports.string().min(1).max(253),
@@ -27203,8 +27658,9 @@ var ReportUpdateScopeRequestSchema = external_exports.object({
27203
27658
  });
27204
27659
  var RequestDesktopTargetRequestSchema = external_exports.object({
27205
27660
  runVersion: external_exports.number().int().min(0),
27206
- /** Only Windows exists; a literal keeps the macOS follow-on additive. */
27207
- platform: external_exports.literal("WINDOWS")
27661
+ /** A MACOS request is also gated on the session's pinned toolset (the api's
27662
+ * `DESKTOP_MACOS_CAPABLE_TOOLSETS`); the schema alone does not authorize it. */
27663
+ platform: external_exports.enum(DesktopTargetPlatformValues)
27208
27664
  });
27209
27665
  var DesktopCredentialRefSchema = external_exports.object({
27210
27666
  credentialId: external_exports.uuid(),
@@ -27231,7 +27687,11 @@ var DesktopTargetStatusRequestSchema = external_exports.object({
27231
27687
  });
27232
27688
  var DesktopTargetStatusResponseSchema = external_exports.object({
27233
27689
  status: external_exports.enum(DesktopTargetStatusValues),
27234
- failureReason: external_exports.string().nullable()
27690
+ failureReason: external_exports.string().nullable(),
27691
+ /** How the host learns the platform of a target it did not request in this
27692
+ * process (a resumed session): the key chords, job paths and recording rules
27693
+ * it applies all depend on it. */
27694
+ platform: external_exports.enum(DesktopTargetPlatformValues)
27235
27695
  });
27236
27696
  var DESKTOP_ACTION_MAX_WAIT_MS = 9e4;
27237
27697
  var EnqueueDesktopActionRequestSchema = external_exports.object({
@@ -27688,6 +28148,112 @@ var agentSessionInternalContract = c4.router({
27688
28148
  500: ErrorResponseSchema
27689
28149
  }
27690
28150
  },
28151
+ listAndroidBuilds: {
28152
+ method: "POST",
28153
+ path: "/internal/v1/agent-sessions/:agentSessionId/android-builds/list",
28154
+ pathParams: AgentSessionInternalParamsSchema,
28155
+ body: AgentSessionListAndroidBuildsRequestSchema,
28156
+ responses: {
28157
+ 200: AgentSessionListAndroidBuildsResponseSchema,
28158
+ 400: ErrorResponseSchema,
28159
+ 401: ErrorResponseSchema,
28160
+ 403: ErrorResponseSchema,
28161
+ 409: ErrorResponseSchema,
28162
+ 500: ErrorResponseSchema
28163
+ }
28164
+ },
28165
+ getAndroidBuild: {
28166
+ method: "POST",
28167
+ path: "/internal/v1/agent-sessions/:agentSessionId/android-builds/get",
28168
+ pathParams: AgentSessionInternalParamsSchema,
28169
+ body: AgentSessionGetAndroidBuildRequestSchema,
28170
+ responses: {
28171
+ 200: AgentSessionAndroidBuildGrantSchema,
28172
+ 400: ErrorResponseSchema,
28173
+ 401: ErrorResponseSchema,
28174
+ 403: ErrorResponseSchema,
28175
+ 404: ErrorResponseSchema,
28176
+ 409: ErrorResponseSchema,
28177
+ 422: ErrorResponseSchema,
28178
+ 500: ErrorResponseSchema,
28179
+ 503: ErrorResponseSchema
28180
+ }
28181
+ },
28182
+ // get_test_integration, no name: every Trace test integration by label. Gated on the
28183
+ // session type (403 for a type that receives none) and on the run still being live.
28184
+ listTestIntegrations: {
28185
+ method: "POST",
28186
+ path: "/internal/v1/agent-sessions/:agentSessionId/test-integrations",
28187
+ pathParams: AgentSessionInternalParamsSchema,
28188
+ body: AgentSessionListTestIntegrationsRequestSchema,
28189
+ responses: {
28190
+ 200: AgentSessionListTestIntegrationsResponseSchema,
28191
+ 400: ErrorResponseSchema,
28192
+ 401: ErrorResponseSchema,
28193
+ 403: ErrorResponseSchema,
28194
+ 409: ErrorResponseSchema,
28195
+ 500: ErrorResponseSchema
28196
+ }
28197
+ },
28198
+ // get_test_integration, with a name: that integration's notes and decrypted facets.
28199
+ // Same gates as the list. A label that matches no integration is a 404 whose message
28200
+ // names the available labels, which are Trace data, not customer data.
28201
+ getTestIntegration: {
28202
+ method: "POST",
28203
+ path: "/internal/v1/agent-sessions/:agentSessionId/test-integration",
28204
+ pathParams: AgentSessionInternalParamsSchema,
28205
+ body: AgentSessionGetTestIntegrationRequestSchema,
28206
+ responses: {
28207
+ 200: AgentSessionTestIntegrationResponseSchema,
28208
+ 400: ErrorResponseSchema,
28209
+ 401: ErrorResponseSchema,
28210
+ 403: ErrorResponseSchema,
28211
+ 404: ErrorResponseSchema,
28212
+ 409: ErrorResponseSchema,
28213
+ 500: ErrorResponseSchema
28214
+ }
28215
+ },
28216
+ // request_payment_card: declare a purchase against the engagement's cap and, when
28217
+ // it fits, receive the active card's facets. 402 PURCHASE_CAP_EXCEEDED carries
28218
+ // `details: { remainingUsd, capUsd }`; 403 when the run's pinned toolset is not
28219
+ // purchase-capable; 409 RUN_REVOKED, PAYMENT_CARD_UNAVAILABLE (no active card, or
28220
+ // the active card is expired or changed since a replayed request), or
28221
+ // ENGAGEMENT_ENDED (the engagement was cancelled or closed while the session ran).
28222
+ requestPaymentCard: {
28223
+ method: "POST",
28224
+ path: "/internal/v1/agent-sessions/:agentSessionId/payment-card",
28225
+ pathParams: AgentSessionInternalParamsSchema,
28226
+ body: AgentSessionRequestPaymentCardRequestSchema,
28227
+ responses: {
28228
+ 200: AgentSessionPaymentCardResponseSchema,
28229
+ 400: ErrorResponseSchema,
28230
+ 401: ErrorResponseSchema,
28231
+ 402: ErrorResponseSchema,
28232
+ 403: ErrorResponseSchema,
28233
+ 409: ErrorResponseSchema,
28234
+ 500: ErrorResponseSchema
28235
+ }
28236
+ },
28237
+ // report_purchase_outcome: COMPLETED or DECLINED for a purchase this session
28238
+ // authorized. 403 when the run's pinned toolset is not purchase-capable; 404
28239
+ // 404 (no code) for any purchase this session did not make; 409 RUN_REVOKED,
28240
+ // or PURCHASE_OUTCOME_CONFLICT with `details: { status }` when the row was already
28241
+ // reported differently or staff voided it. A repeated identical report replays.
28242
+ reportPurchaseOutcome: {
28243
+ method: "POST",
28244
+ path: "/internal/v1/agent-sessions/:agentSessionId/purchase-outcome",
28245
+ pathParams: AgentSessionInternalParamsSchema,
28246
+ body: AgentSessionReportPurchaseOutcomeRequestSchema,
28247
+ responses: {
28248
+ 200: AgentSessionPurchaseOutcomeResponseSchema,
28249
+ 400: ErrorResponseSchema,
28250
+ 401: ErrorResponseSchema,
28251
+ 403: ErrorResponseSchema,
28252
+ 404: ErrorResponseSchema,
28253
+ 409: ErrorResponseSchema,
28254
+ 500: ErrorResponseSchema
28255
+ }
28256
+ },
27691
28257
  // provision_passkey, read half: every passkey Trace holds for one of the run's
27692
28258
  // accounts, decrypted, so the host can load them into the virtual authenticator
27693
28259
  // it arms on the agent's browser. Same resolution and ownership gate as
@@ -29966,6 +30532,19 @@ var OrganizationCodeSizeResponseSchema = external_exports.object({
29966
30532
  languageCount: external_exports.number().int().nonnegative()
29967
30533
  })
29968
30534
  });
30535
+ var CodeSizeRecalculateResponseSchema = external_exports.object({
30536
+ /** Repos the request covered. */
30537
+ requested: external_exports.number().int().nonnegative(),
30538
+ /** Messages the queue accepted. Lower than `requested` is a partial send,
30539
+ * reported rather than masked. */
30540
+ enqueued: external_exports.number().int().nonnegative()
30541
+ });
30542
+ var CodeSizeRecalculateLimitedResponseSchema = ErrorResponseSchema.extend({
30543
+ /** Recalculates allowed per org in any 24 hours. */
30544
+ limit: external_exports.number().int().positive(),
30545
+ /** When the oldest request in the window ages out and frees a slot. */
30546
+ retryAt: external_exports.iso.datetime()
30547
+ });
29969
30548
  var StaffCodeSizeRepositorySchema = external_exports.object({
29970
30549
  repositoryId: external_exports.uuid(),
29971
30550
  repositoryUrl: external_exports.url(),
@@ -30009,7 +30588,11 @@ var StaffCodeSizeRemeasureResponseSchema = external_exports.object({
30009
30588
  requested: external_exports.number().int().nonnegative(),
30010
30589
  /** Messages SQS accepted. Lower than `requested` means a partial send —
30011
30590
  * reported rather than masked (the panel states this number). */
30012
- enqueued: external_exports.number().int().nonnegative()
30591
+ enqueued: external_exports.number().int().nonnegative(),
30592
+ /** Repos re-read from GitHub (default branch, archive state) before the
30593
+ * scope was selected. Null when no refresh ran: scope `unmeasured`, or no
30594
+ * GitHub App credentials on this environment. */
30595
+ refreshedRepoCount: external_exports.number().int().nonnegative().nullable()
30013
30596
  });
30014
30597
 
30015
30598
  // ../../packages/api-contracts/src/contracts/v1/code-size.ts
@@ -30027,6 +30610,23 @@ var codeSizeContract = c11.router({
30027
30610
  500: ErrorResponseSchema
30028
30611
  }
30029
30612
  },
30613
+ // Customer Recalculate (MANAGE_INTEGRATED_REPOSITORIES). Enqueue-only.
30614
+ recalculateOrganizationCodeSize: {
30615
+ method: "POST",
30616
+ path: "/organizations/:organizationId/code-size/recalculate",
30617
+ pathParams: OrgIdParamsSchema,
30618
+ body: c11.noBody(),
30619
+ responses: {
30620
+ 200: CodeSizeRecalculateResponseSchema,
30621
+ 401: ErrorResponseSchema,
30622
+ 403: ErrorResponseSchema,
30623
+ 404: ErrorResponseSchema,
30624
+ 429: CodeSizeRecalculateLimitedResponseSchema,
30625
+ 500: ErrorResponseSchema,
30626
+ // Measurement enqueueing is unconfigured (REPO_METADATA_QUEUE_URL unset).
30627
+ 503: ErrorResponseSchema
30628
+ }
30629
+ },
30030
30630
  // Staff-only: per-repo measurement freshness for the admin Controls panel.
30031
30631
  getStaffOrganizationCodeSize: {
30032
30632
  method: "GET",
@@ -30053,151 +30653,15 @@ var codeSizeContract = c11.router({
30053
30653
  403: ErrorResponseSchema,
30054
30654
  404: ErrorResponseSchema,
30055
30655
  500: ErrorResponseSchema,
30656
+ // Scope `all` could not refresh repository state from GitHub; nothing
30657
+ // was re-measured.
30658
+ 502: ErrorResponseSchema,
30056
30659
  // Measurement enqueueing is unconfigured (REPO_METADATA_QUEUE_URL unset).
30057
30660
  503: ErrorResponseSchema
30058
30661
  }
30059
30662
  }
30060
30663
  });
30061
30664
 
30062
- // ../../packages/api-contracts/src/schemas/api/v1/code-upload.api.ts
30063
- var CODE_UPLOAD_MAX_BYTES = 1024 * 1024 * 1024;
30064
- var CODE_UPLOAD_PART_SIZE_BYTES = 10 * 1024 * 1024;
30065
- var CodeUploadStatusValues = [
30066
- "UPLOADING",
30067
- "FINALIZING",
30068
- "SCANNING",
30069
- "VALIDATING",
30070
- "READY",
30071
- "REJECTED",
30072
- "DELETING",
30073
- "FAILED"
30074
- ];
30075
- var CodeUploadMalwareScanResultValues = [
30076
- "NO_THREATS_FOUND",
30077
- "THREATS_FOUND",
30078
- "UNSUPPORTED",
30079
- "ACCESS_DENIED",
30080
- "FAILED"
30081
- ];
30082
- var CodeUploadRejectionReasonValues = [
30083
- "MALWARE_DETECTED",
30084
- "MALWARE_SCAN_UNSUPPORTED",
30085
- "MALWARE_SCAN_UNAVAILABLE",
30086
- "INVALID_ARCHIVE",
30087
- "INTEGRITY_MISMATCH"
30088
- ];
30089
- var CodeUploadArtifactKindValues = ["SOURCE_ARCHIVE", "ANDROID_APK", "IOS_IPA"];
30090
- function isApplicationBuildArtifactKind(kind) {
30091
- return kind === "ANDROID_APK" || kind === "IOS_IPA";
30092
- }
30093
- var CodeUploadIdParamsSchema = OrgIdParamsSchema.extend({
30094
- codeUploadId: external_exports.uuid()
30095
- });
30096
- var ListCodeUploadsQuerySchema = external_exports.object({
30097
- artifactKind: external_exports.enum(CodeUploadArtifactKindValues).optional(),
30098
- applicationId: external_exports.uuid().optional()
30099
- }).strict();
30100
- var InitializeCodeUploadRequestSchema = external_exports.object({
30101
- displayName: external_exports.string().trim().min(1).max(200),
30102
- originalFilename: external_exports.string().trim().min(1).max(255),
30103
- sizeBytes: external_exports.number().int().min(1).max(CODE_UPLOAD_MAX_BYTES),
30104
- archiveSha256: external_exports.string().regex(/^[0-9a-f]{64}$/),
30105
- // Defaulted so a pre-this-release client that omitted the field still
30106
- // initializes a source ZIP during a mixed-version rollout.
30107
- artifactKind: external_exports.enum(CodeUploadArtifactKindValues).default("SOURCE_ARCHIVE"),
30108
- applicationId: external_exports.uuid().optional()
30109
- }).strict().superRefine((data, ctx) => {
30110
- const filename = data.originalFilename.toLowerCase();
30111
- if (isApplicationBuildArtifactKind(data.artifactKind)) {
30112
- const extension = data.artifactKind === "ANDROID_APK" ? ".apk" : ".ipa";
30113
- if (!filename.endsWith(extension)) {
30114
- ctx.addIssue({
30115
- code: "custom",
30116
- path: ["originalFilename"],
30117
- message: `originalFilename must end in ${extension}`
30118
- });
30119
- }
30120
- if (data.applicationId == null) {
30121
- ctx.addIssue({
30122
- code: "custom",
30123
- path: ["applicationId"],
30124
- message: "A build upload must target a mobile application."
30125
- });
30126
- }
30127
- return;
30128
- }
30129
- if (!filename.endsWith(".zip")) {
30130
- ctx.addIssue({
30131
- code: "custom",
30132
- path: ["originalFilename"],
30133
- message: "originalFilename must end in .zip"
30134
- });
30135
- }
30136
- if (data.applicationId != null) {
30137
- ctx.addIssue({
30138
- code: "custom",
30139
- path: ["applicationId"],
30140
- message: "Source archives are linked to an application after they are ready."
30141
- });
30142
- }
30143
- });
30144
- var LinkedCodeUploadApplicationSchema = external_exports.object({
30145
- applicationId: external_exports.uuid(),
30146
- name: external_exports.string()
30147
- });
30148
- var CodeUploadSchema = external_exports.object({
30149
- codeUploadId: external_exports.uuid(),
30150
- repositoryId: external_exports.uuid(),
30151
- displayName: external_exports.string(),
30152
- originalFilename: external_exports.string(),
30153
- sizeBytes: external_exports.number().int().positive(),
30154
- archiveSha256: external_exports.string().regex(/^[0-9a-f]{64}$/),
30155
- status: external_exports.enum(CodeUploadStatusValues),
30156
- malwareScanResult: external_exports.enum(CodeUploadMalwareScanResultValues).nullable(),
30157
- rejectionReason: external_exports.enum(CodeUploadRejectionReasonValues).nullable(),
30158
- // Defaulted so a new client reading a pre-this-release API during a rolling
30159
- // deploy doesn't reject source-upload rows that omit the field.
30160
- artifactKind: external_exports.enum(CodeUploadArtifactKindValues).default("SOURCE_ARCHIVE"),
30161
- applicationId: external_exports.uuid().nullable().default(null),
30162
- // z.coerce.date(), not z.date(): web server actions safeParse the raw
30163
- // ts-rest JSON body, where these arrive as ISO strings.
30164
- scanningStartedAt: external_exports.coerce.date().nullable(),
30165
- readyAt: external_exports.coerce.date().nullable(),
30166
- createdAt: external_exports.coerce.date(),
30167
- linkedApplications: external_exports.array(LinkedCodeUploadApplicationSchema)
30168
- });
30169
- var CodeUploadPartUrlSchema = external_exports.object({
30170
- partNumber: external_exports.number().int().positive(),
30171
- uploadUrl: external_exports.url()
30172
- });
30173
- var UploadedCodeUploadPartSchema = external_exports.object({
30174
- partNumber: external_exports.number().int().positive(),
30175
- sizeBytes: external_exports.number().int().positive()
30176
- });
30177
- var CodeUploadMultipartSchema = external_exports.object({
30178
- partSizeBytes: external_exports.literal(CODE_UPLOAD_PART_SIZE_BYTES),
30179
- parts: external_exports.array(CodeUploadPartUrlSchema),
30180
- expiresAt: external_exports.coerce.date()
30181
- });
30182
- var InitializeCodeUploadResponseSchema = external_exports.object({
30183
- upload: CodeUploadSchema,
30184
- multipart: CodeUploadMultipartSchema
30185
- });
30186
- var ResumeCodeUploadResponseSchema = external_exports.object({
30187
- upload: CodeUploadSchema,
30188
- multipart: CodeUploadMultipartSchema.extend({
30189
- uploadedParts: external_exports.array(UploadedCodeUploadPartSchema)
30190
- })
30191
- });
30192
- var ListCodeUploadsResponseSchema = external_exports.object({
30193
- uploads: external_exports.array(CodeUploadSchema)
30194
- });
30195
- var DownloadCodeUploadResponseSchema = external_exports.object({
30196
- upload: CodeUploadSchema,
30197
- downloadUrl: external_exports.url(),
30198
- expiresAt: external_exports.coerce.date()
30199
- });
30200
-
30201
30665
  // ../../packages/api-contracts/src/contracts/v1/code-upload.ts
30202
30666
  var c12 = initContract();
30203
30667
  var commonErrors = {
@@ -31399,7 +31863,9 @@ var environmentContract = c17.router({
31399
31863
  403: ErrorResponseSchema,
31400
31864
  404: ErrorResponseSchema,
31401
31865
  // 409 — environment target is frozen by a non-terminal pentest
31402
- // (errorCode ENVIRONMENT_TARGET_FROZEN_BY_PENTEST).
31866
+ // (errorCode ENVIRONMENT_TARGET_FROZEN_BY_PENTEST), or a live pentest
31867
+ // still links the environment (errorCode ENVIRONMENT_IN_USE_BY_PENTEST,
31868
+ // details.pentestDisplayIds names the holders).
31403
31869
  409: ErrorResponseSchema,
31404
31870
  500: ErrorResponseSchema
31405
31871
  }
@@ -31579,7 +32045,9 @@ var GitHubRepoSchema = external_exports.object({
31579
32045
  private: external_exports.boolean(),
31580
32046
  htmlUrl: external_exports.string().url(),
31581
32047
  githubDefaultBranch: external_exports.string(),
31582
- language: external_exports.string().nullable()
32048
+ language: external_exports.string().nullable(),
32049
+ /** Archived on GitHub. Archived repos stay listed; archiving excludes them once. */
32050
+ archived: external_exports.boolean()
31583
32051
  });
31584
32052
  var ListGitHubInstallationReposResponseSchema = external_exports.array(GitHubRepoSchema);
31585
32053
 
@@ -32870,9 +33338,10 @@ var PrScanAnalyticsDeveloperSchema = external_exports.object({
32870
33338
  criticalHighFixedCount: external_exports.number().int().nonnegative(),
32871
33339
  falsePositiveCount: external_exports.number().int().nonnegative()
32872
33340
  });
33341
+ var PrScanAnalyticsMonthKeySchema = external_exports.string().regex(/^[1-9]\d{3}-(0[1-9]|1[0-2])$/);
32873
33342
  var PrScanAnalyticsMonthSchema = external_exports.object({
32874
33343
  /** UTC calendar month, `YYYY-MM`. */
32875
- month: external_exports.string().regex(/^\d{4}-\d{2}$/),
33344
+ month: PrScanAnalyticsMonthKeySchema,
32876
33345
  prCount: external_exports.number().int().nonnegative(),
32877
33346
  developerCount: external_exports.number().int().nonnegative(),
32878
33347
  findingsCount: external_exports.number().int().nonnegative(),
@@ -32911,28 +33380,92 @@ var PrScanAnalyticsSummarySchema = external_exports.object({
32911
33380
  /** One row per severity, CRITICAL first. */
32912
33381
  timeToFix: external_exports.array(PrScanAnalyticsTimeToFixSchema).length(VulnerabilitySeverityValues.length)
32913
33382
  });
33383
+ var PrScanAnalyticsFindingSchema = external_exports.object({
33384
+ vulnerabilityId: external_exports.uuid(),
33385
+ title: external_exports.string(),
33386
+ severity: VulnerabilitySeverity,
33387
+ status: VulnerabilityStatus,
33388
+ /** The PR the finding was first detected on; its review comment lives there. */
33389
+ pullRequestNumber: external_exports.number().int().positive().nullable()
33390
+ });
33391
+ var PrScanAnalyticsFindingsQuerySchema = external_exports.object({
33392
+ category: external_exports.string().min(1).max(100),
33393
+ asOf: external_exports.iso.datetime(),
33394
+ afterStatus: VulnerabilityStatus.optional(),
33395
+ afterSeverity: VulnerabilitySeverity.optional(),
33396
+ afterCreatedAt: external_exports.iso.datetime().optional(),
33397
+ afterVulnerabilityId: external_exports.uuid().optional()
33398
+ }).refine(
33399
+ ({ afterStatus, afterSeverity, afterCreatedAt, afterVulnerabilityId }) => {
33400
+ const provided = [afterStatus, afterSeverity, afterCreatedAt, afterVulnerabilityId].filter(
33401
+ (field) => field !== void 0
33402
+ ).length;
33403
+ return provided === 0 || provided === 4;
33404
+ },
33405
+ { message: "Provide all four cursor fields or none", path: ["afterCreatedAt"] }
33406
+ );
33407
+ var PrScanAnalyticsFindingsResponseSchema = external_exports.object({
33408
+ /** Open first (then In progress, Fixed, Archived, False positive, Dismissed), most severe first within a status, then newest. */
33409
+ findings: external_exports.array(PrScanAnalyticsFindingSchema).max(25),
33410
+ total: external_exports.number().int().nonnegative(),
33411
+ nextCursor: external_exports.object({
33412
+ status: VulnerabilityStatus,
33413
+ severity: VulnerabilitySeverity,
33414
+ firstDetectedAt: external_exports.iso.datetime(),
33415
+ vulnerabilityId: external_exports.uuid()
33416
+ }).nullable()
33417
+ });
33418
+ var PrScanAnalyticsFindingCommentParamsSchema = external_exports.object({
33419
+ organizationId: external_exports.uuid(),
33420
+ vulnerabilityId: external_exports.uuid()
33421
+ });
33422
+ var PrScanAnalyticsFindingCommentResponseSchema = external_exports.object({
33423
+ url: external_exports.url(),
33424
+ target: external_exports.enum(["comment", "pull_request"])
33425
+ });
33426
+ var PrScanAnalyticsTotalsSchema = external_exports.object({
33427
+ prCount: external_exports.number().int().nonnegative(),
33428
+ findingsCount: external_exports.number().int().nonnegative(),
33429
+ criticalHighCount: external_exports.number().int().nonnegative(),
33430
+ remediatedCount: external_exports.number().int().nonnegative(),
33431
+ byClass: external_exports.array(PrScanAnalyticsClassCountSchema)
33432
+ });
32914
33433
  var PrScanAnalyticsResponseSchema = external_exports.object({
32915
33434
  generatedAt: external_exports.iso.datetime(),
32916
33435
  months: external_exports.array(PrScanAnalyticsMonthSchema).length(12),
32917
- summary: PrScanAnalyticsSummarySchema
33436
+ summary: PrScanAnalyticsSummarySchema,
33437
+ totals: PrScanAnalyticsTotalsSchema.optional()
32918
33438
  });
32919
33439
  var ProductPlanParamsSchema = external_exports.object({
32920
33440
  organizationId: external_exports.uuid(),
32921
33441
  product: external_exports.enum(ProductValues)
32922
33442
  });
33443
+ var ProseSpellingValues = ["US", "UK"];
33444
+ var ProseSpellingSchema = external_exports.enum(ProseSpellingValues);
32923
33445
  var ReferrerSchema = external_exports.object({
32924
33446
  referrerId: external_exports.uuid(),
32925
33447
  name: external_exports.string(),
32926
33448
  slug: external_exports.string(),
32927
- reportTemplate: PentestReportTemplateSchema
33449
+ reportTemplate: PentestReportTemplateSchema,
33450
+ /** Spelling the agents write customer-facing prose in for this partner's orgs. */
33451
+ proseSpelling: ProseSpellingSchema
33452
+ });
33453
+ var ReferrerParamsSchema = external_exports.object({
33454
+ referrerId: external_exports.uuid()
33455
+ });
33456
+ var UpdateReferrerRequestSchema = external_exports.object({
33457
+ proseSpelling: ProseSpellingSchema
32928
33458
  });
33459
+ var UpdateReferrerResponseSchema = ReferrerSchema;
32929
33460
  var ListReferrersResponseSchema = external_exports.object({
32930
33461
  referrers: external_exports.array(ReferrerSchema)
32931
33462
  });
32932
33463
  var CreateReferrerRequestSchema = external_exports.object({
32933
33464
  name: external_exports.string().trim().min(2, "Partner name must be at least 2 characters").max(100, "Partner name must be 100 characters or fewer"),
32934
33465
  /** Report template for orgs this partner refers. Defaults to TRACE. */
32935
- reportTemplate: PentestReportTemplateSchema.optional()
33466
+ reportTemplate: PentestReportTemplateSchema.optional(),
33467
+ /** Prose spelling for orgs this partner refers. Defaults to US. */
33468
+ proseSpelling: ProseSpellingSchema.optional()
32936
33469
  });
32937
33470
  var CreateReferrerResponseSchema = ReferrerSchema;
32938
33471
  var SetOrganizationReferrerRequestSchema = external_exports.object({
@@ -32993,9 +33526,14 @@ var CreatePrReviewerSubscriptionRequestSchema = external_exports.object({
32993
33526
  /** Calendar day the subscription starts, `YYYY-MM-DD`, UTC. Today or in the past. */
32994
33527
  startDate: external_exports.string().regex(/^\d{4}-\d{2}-\d{2}$/)
32995
33528
  });
33529
+ var BillingCollectionMethodValues = ["charge_automatically", "send_invoice"];
32996
33530
  var PrReviewerSubscriptionResponseSchema = external_exports.object({
32997
33531
  subscriptionId: external_exports.string(),
32998
33532
  status: external_exports.string(),
33533
+ /** Optional for rolling-deploy tolerance: an older API omits the key. */
33534
+ collectionMethod: external_exports.enum(BillingCollectionMethodValues).optional(),
33535
+ /** The customer opted into autopay but the saved card didn't pay the first invoice, so it was emailed. */
33536
+ firstChargeDeclined: external_exports.boolean().optional(),
32999
33537
  invoice: external_exports.object({
33000
33538
  id: external_exports.string(),
33001
33539
  status: external_exports.string(),
@@ -33044,6 +33582,33 @@ var BillingSubscriptionSchema = external_exports.object({
33044
33582
  currentPeriodEnd: external_exports.date().nullable(),
33045
33583
  cancelAtPeriodEnd: external_exports.boolean()
33046
33584
  });
33585
+ var BillingPaymentMethodSchema = external_exports.object({
33586
+ /** Stripe PaymentMethod type, e.g. `card` or `us_bank_account`. */
33587
+ type: external_exports.string(),
33588
+ /** Card network or bank name, when Stripe exposes one. */
33589
+ brand: external_exports.string().nullable(),
33590
+ last4: external_exports.string().nullable(),
33591
+ expMonth: external_exports.number().int().nullable(),
33592
+ expYear: external_exports.number().int().nullable()
33593
+ });
33594
+ var BillingAutopayStateValues = ["off", "card_only", "on"];
33595
+ var BillingAutopaySchema = external_exports.object({
33596
+ state: external_exports.enum(BillingAutopayStateValues),
33597
+ /** The customer's default card; null when state is `off`. */
33598
+ paymentMethod: BillingPaymentMethodSchema.nullable(),
33599
+ /**
33600
+ * Open PR reviewer invoices that enabling autopay charges right away, once
33601
+ * the admin confirms them. Enabling charges these ids and no others.
33602
+ */
33603
+ chargeOnEnable: external_exports.object({
33604
+ invoiceIds: external_exports.array(external_exports.string()).min(1),
33605
+ invoiceCount: external_exports.number().int().positive(),
33606
+ amountCents: external_exports.number().int().positive(),
33607
+ currency: external_exports.string(),
33608
+ /** At least one was already charged and declined, rather than never attempted. */
33609
+ declined: external_exports.boolean()
33610
+ }).nullable()
33611
+ });
33047
33612
  var OrganizationBillingSchema = external_exports.object({
33048
33613
  prReviewerBillingRequired: external_exports.boolean(),
33049
33614
  hasStripeCustomer: external_exports.boolean(),
@@ -33053,11 +33618,44 @@ var OrganizationBillingSchema = external_exports.object({
33053
33618
  /** Optional for rolling-deploy tolerance. */
33054
33619
  subscription: BillingSubscriptionSchema.nullable().optional(),
33055
33620
  /** Optional for rolling-deploy tolerance: an older API omits the key. */
33056
- paymentDue: BillingPaymentDueSchema.nullable().optional()
33621
+ paymentDue: BillingPaymentDueSchema.nullable().optional(),
33622
+ /**
33623
+ * Null when there's no Stripe customer, or the card lookup failed (the row is
33624
+ * hidden rather than offering setup over a card that may exist). Optional for
33625
+ * rolling-deploy tolerance.
33626
+ */
33627
+ autopay: BillingAutopaySchema.nullable().optional()
33057
33628
  });
33058
33629
  var BillingPortalResponseSchema = external_exports.object({
33059
33630
  url: external_exports.url()
33060
33631
  });
33632
+ var STRIPE_CHECKOUT_SESSION_ID_PATTERN = /^cs_(test|live)_[A-Za-z0-9]+$/;
33633
+ var EnableAutopayRequestSchema = external_exports.object({
33634
+ /**
33635
+ * Checkout session (setup mode) the admin just completed. Omitted when the
33636
+ * customer already has a default card on file and only the opt-in and the
33637
+ * PR reviewer subscriptions need to switch.
33638
+ */
33639
+ checkoutSessionId: external_exports.string().regex(STRIPE_CHECKOUT_SESSION_ID_PATTERN).optional(),
33640
+ /**
33641
+ * Card-on-file path: the open invoices the admin confirmed charging. Ignored
33642
+ * with a Checkout session, which carries its own confirmation.
33643
+ */
33644
+ confirmedInvoiceIds: external_exports.array(external_exports.string().regex(/^in_[A-Za-z0-9]+$/)).max(15).optional()
33645
+ });
33646
+ var CreateAutopaySetupSessionRequestSchema = external_exports.object({
33647
+ /** Open invoices the admin confirmed; the Checkout return charges these and no others. */
33648
+ confirmedInvoiceIds: external_exports.array(external_exports.string().regex(/^in_[A-Za-z0-9]+$/)).max(15)
33649
+ });
33650
+ var EnableAutopayResponseSchema = external_exports.object({
33651
+ paymentMethod: BillingPaymentMethodSchema,
33652
+ /** PR reviewer subscriptions moved to charge the customer's default card. */
33653
+ subscriptionsUpdated: external_exports.number().int(),
33654
+ /** Open PR reviewer invoices Stripe confirmed as paid. */
33655
+ openInvoicesPaid: external_exports.number().int(),
33656
+ /** Open PR reviewer invoices the card didn't pay; they stay open for manual payment. */
33657
+ openInvoicesDeclined: external_exports.number().int()
33658
+ });
33061
33659
  var ListOrganizationsResponseSchema = external_exports.array(OrganizationResponseSchema);
33062
33660
  var StaffOrganizationSummarySchema = external_exports.object({
33063
33661
  organizationId: external_exports.uuid(),
@@ -33280,6 +33878,22 @@ var organizationContract = c27.router({
33280
33878
  500: ErrorResponseSchema
33281
33879
  }
33282
33880
  },
33881
+ // Staff-only: change a partner's prose spelling. Reaches sessions launched
33882
+ // after the change; running sessions keep the header they started with.
33883
+ updateReferrer: {
33884
+ method: "PATCH",
33885
+ path: "/referrers/:referrerId",
33886
+ pathParams: ReferrerParamsSchema,
33887
+ body: UpdateReferrerRequestSchema,
33888
+ responses: {
33889
+ 200: UpdateReferrerResponseSchema,
33890
+ 400: ErrorResponseSchema,
33891
+ 401: ErrorResponseSchema,
33892
+ 403: ErrorResponseSchema,
33893
+ 404: ErrorResponseSchema,
33894
+ 500: ErrorResponseSchema
33895
+ }
33896
+ },
33283
33897
  // Staff-only: set (or clear with null) the org's referral partner.
33284
33898
  // Drives "Trace x <partner>" co-branding on pentest report covers.
33285
33899
  setOrganizationReferrer: {
@@ -33443,6 +34057,42 @@ var organizationContract = c27.router({
33443
34057
  500: ErrorResponseSchema
33444
34058
  }
33445
34059
  },
34060
+ // Signed-in admins only: mint a Stripe Checkout session (setup mode, cards)
34061
+ // that collects the autopay card. Stripe returns to the web's redemption route.
34062
+ createAutopaySetupSession: {
34063
+ method: "POST",
34064
+ path: "/organizations/:organizationId/billing/autopay/session",
34065
+ pathParams: OrgIdParamsSchema,
34066
+ body: CreateAutopaySetupSessionRequestSchema,
34067
+ responses: {
34068
+ 200: BillingPortalResponseSchema,
34069
+ 401: ErrorResponseSchema,
34070
+ 403: ErrorResponseSchema,
34071
+ 404: ErrorResponseSchema,
34072
+ 409: ErrorResponseSchema,
34073
+ 503: ErrorResponseSchema,
34074
+ 500: ErrorResponseSchema
34075
+ }
34076
+ },
34077
+ // Signed-in admins only: make the collected card the customer default, opt the
34078
+ // customer in, move live PR reviewer subscriptions onto it, and charge their
34079
+ // open invoices. The web confirms the charge before calling.
34080
+ enableAutopay: {
34081
+ method: "POST",
34082
+ path: "/organizations/:organizationId/billing/autopay",
34083
+ pathParams: OrgIdParamsSchema,
34084
+ body: EnableAutopayRequestSchema,
34085
+ responses: {
34086
+ 200: EnableAutopayResponseSchema,
34087
+ 400: ErrorResponseSchema,
34088
+ 401: ErrorResponseSchema,
34089
+ 403: ErrorResponseSchema,
34090
+ 404: ErrorResponseSchema,
34091
+ 409: ErrorResponseSchema,
34092
+ 503: ErrorResponseSchema,
34093
+ 500: ErrorResponseSchema
34094
+ }
34095
+ },
33446
34096
  // Member-readable: the caller's own org SCANNING plan + spend, for the
33447
34097
  // customer trial-credits meter. Scoped by requireOrgAccess (no staff gate).
33448
34098
  getScanUsage: {
@@ -33460,6 +34110,34 @@ var organizationContract = c27.router({
33460
34110
  // Member-readable: last 12 UTC months of PR scanner usage (unique PRs,
33461
34111
  // developers, PR-first-detected findings + remediations). Gated by
33462
34112
  // requireOrgAccess + VIEW_RESULTS + AUTO_PR_SCANS.
34113
+ getPrScanAnalyticsFindings: {
34114
+ method: "GET",
34115
+ path: "/organizations/:organizationId/pr-scan-analytics/findings",
34116
+ pathParams: OrgIdParamsSchema,
34117
+ query: PrScanAnalyticsFindingsQuerySchema,
34118
+ responses: {
34119
+ 200: PrScanAnalyticsFindingsResponseSchema,
34120
+ 400: ErrorResponseSchema,
34121
+ 401: ErrorResponseSchema,
34122
+ 403: ErrorResponseSchema,
34123
+ 404: ErrorResponseSchema,
34124
+ 500: ErrorResponseSchema
34125
+ }
34126
+ },
34127
+ // Resolves a finding's PR review comment on GitHub (by the hidden
34128
+ // vulnerability marker) so the analytics row can link straight to it.
34129
+ getPrScanAnalyticsFindingComment: {
34130
+ method: "GET",
34131
+ path: "/organizations/:organizationId/pr-scan-analytics/findings/:vulnerabilityId/comment",
34132
+ pathParams: PrScanAnalyticsFindingCommentParamsSchema,
34133
+ responses: {
34134
+ 200: PrScanAnalyticsFindingCommentResponseSchema,
34135
+ 401: ErrorResponseSchema,
34136
+ 403: ErrorResponseSchema,
34137
+ 404: ErrorResponseSchema,
34138
+ 500: ErrorResponseSchema
34139
+ }
34140
+ },
33463
34141
  getPrScanAnalytics: {
33464
34142
  method: "GET",
33465
34143
  path: "/organizations/:organizationId/pr-scan-analytics",
@@ -33504,6 +34182,65 @@ var organizationContract = c27.router({
33504
34182
  }
33505
34183
  });
33506
34184
 
34185
+ // ../../packages/api-contracts/src/contracts/v1/payment-card.ts
34186
+ var c28 = initContract();
34187
+ var paymentCardContract = c28.router({
34188
+ listPaymentCards: {
34189
+ method: "GET",
34190
+ path: "/staff/payment-cards",
34191
+ responses: {
34192
+ 200: ListPaymentCardsResponseSchema,
34193
+ 401: ErrorResponseSchema,
34194
+ 403: ErrorResponseSchema,
34195
+ 500: ErrorResponseSchema
34196
+ }
34197
+ },
34198
+ createPaymentCard: {
34199
+ method: "POST",
34200
+ path: "/staff/payment-cards",
34201
+ body: CreatePaymentCardRequestSchema,
34202
+ responses: {
34203
+ 201: PaymentCardResponseSchema,
34204
+ 400: ErrorResponseSchema,
34205
+ // PAYMENT_CARD_EXPIRED, or a contract failure
34206
+ 401: ErrorResponseSchema,
34207
+ 403: ErrorResponseSchema,
34208
+ 409: ErrorResponseSchema,
34209
+ // PAYMENT_CARD_LABEL_TAKEN, PAYMENT_CARD_ACTIVE_CONFLICT
34210
+ 500: ErrorResponseSchema
34211
+ }
34212
+ },
34213
+ updatePaymentCard: {
34214
+ method: "PATCH",
34215
+ path: "/staff/payment-cards/:paymentCardId",
34216
+ pathParams: PaymentCardIdParamsSchema,
34217
+ body: UpdatePaymentCardRequestSchema,
34218
+ responses: {
34219
+ 200: PaymentCardResponseSchema,
34220
+ 400: ErrorResponseSchema,
34221
+ 401: ErrorResponseSchema,
34222
+ 403: ErrorResponseSchema,
34223
+ 404: ErrorResponseSchema,
34224
+ 409: ErrorResponseSchema,
34225
+ 500: ErrorResponseSchema
34226
+ }
34227
+ },
34228
+ deletePaymentCard: {
34229
+ method: "DELETE",
34230
+ path: "/staff/payment-cards/:paymentCardId",
34231
+ pathParams: PaymentCardIdParamsSchema,
34232
+ responses: {
34233
+ 204: DeleteResponseSchema,
34234
+ 401: ErrorResponseSchema,
34235
+ 403: ErrorResponseSchema,
34236
+ 404: ErrorResponseSchema,
34237
+ 409: ErrorResponseSchema,
34238
+ // PAYMENT_CARD_HAS_PURCHASES
34239
+ 500: ErrorResponseSchema
34240
+ }
34241
+ }
34242
+ });
34243
+
33507
34244
  // ../../packages/api-contracts/src/schemas/api/v1/pentest-cost-rollup.api.ts
33508
34245
  var PentestCostRollupResponseSchema = external_exports.object({
33509
34246
  pentestId: external_exports.uuid(),
@@ -33796,8 +34533,8 @@ var ScanReuseSuggestionsResponseSchema = external_exports.object({
33796
34533
  });
33797
34534
 
33798
34535
  // ../../packages/api-contracts/src/contracts/v1/pentest.ts
33799
- var c28 = initContract();
33800
- var pentestContract = c28.router({
34536
+ var c29 = initContract();
34537
+ var pentestContract = c29.router({
33801
34538
  listPentests: {
33802
34539
  method: "GET",
33803
34540
  path: "/organizations/:organizationId/pentests",
@@ -34107,8 +34844,8 @@ var pentestContract = c28.router({
34107
34844
  });
34108
34845
 
34109
34846
  // ../../packages/api-contracts/src/contracts/v1/pentest-attack-chain.ts
34110
- var c29 = initContract();
34111
- var pentestAttackChainContract = c29.router({
34847
+ var c30 = initContract();
34848
+ var pentestAttackChainContract = c30.router({
34112
34849
  listAttackChains: {
34113
34850
  method: "GET",
34114
34851
  path: "/organizations/:organizationId/pentests/:pentestId/attack-chains",
@@ -34227,7 +34964,7 @@ var pentestAttackChainContract = c29.router({
34227
34964
  method: "DELETE",
34228
34965
  path: "/organizations/:organizationId/pentests/:pentestId/attack-chains/:attackChainId",
34229
34966
  pathParams: PentestAttackChainIdParamsSchema,
34230
- body: c29.noBody(),
34967
+ body: c30.noBody(),
34231
34968
  responses: {
34232
34969
  200: DeleteResponseSchema,
34233
34970
  401: ErrorResponseSchema,
@@ -34388,8 +35125,8 @@ var ReadAttestationDownloadResponseSchema = external_exports.union([
34388
35125
  ]);
34389
35126
 
34390
35127
  // ../../packages/api-contracts/src/contracts/v1/pentest-attestation.ts
34391
- var c30 = initContract();
34392
- var pentestAttestationContract = c30.router({
35128
+ var c31 = initContract();
35129
+ var pentestAttestationContract = c31.router({
34393
35130
  getDefaults: {
34394
35131
  method: "GET",
34395
35132
  path: "/organizations/:organizationId/pentests/:pentestId/attestations/defaults",
@@ -34532,8 +35269,8 @@ var ListPentestAuditLogResponseSchema = external_exports.object({
34532
35269
  });
34533
35270
 
34534
35271
  // ../../packages/api-contracts/src/contracts/v1/pentest-audit-log.ts
34535
- var c31 = initContract();
34536
- var pentestAuditLogContract = c31.router({
35272
+ var c32 = initContract();
35273
+ var pentestAuditLogContract = c32.router({
34537
35274
  listAuditLog: {
34538
35275
  method: "GET",
34539
35276
  path: "/organizations/:organizationId/pentests/:pentestId/audit-log",
@@ -34580,8 +35317,8 @@ var CreatePentestAuthorizedDomainRequestSchema = external_exports.object({
34580
35317
  }).strict();
34581
35318
 
34582
35319
  // ../../packages/api-contracts/src/contracts/v1/pentest-authorized-domain.ts
34583
- var c32 = initContract();
34584
- var pentestAuthorizedDomainContract = c32.router({
35320
+ var c33 = initContract();
35321
+ var pentestAuthorizedDomainContract = c33.router({
34585
35322
  getPentestAuthorizedScope: {
34586
35323
  method: "GET",
34587
35324
  path: "/organizations/:organizationId/pentests/:pentestId/authorized-scope",
@@ -34635,8 +35372,8 @@ var PentestEgressResponseSchema = external_exports.object({
34635
35372
  }).strict();
34636
35373
 
34637
35374
  // ../../packages/api-contracts/src/contracts/v1/pentest-egress.ts
34638
- var c33 = initContract();
34639
- var pentestEgressContract = c33.router({
35375
+ var c34 = initContract();
35376
+ var pentestEgressContract = c34.router({
34640
35377
  getPentestEgress: {
34641
35378
  method: "GET",
34642
35379
  path: "/staff/pentest-egress",
@@ -34675,8 +35412,8 @@ var CreatePentestEngagementExclusionRequestSchema = external_exports.object({
34675
35412
  }).strict();
34676
35413
 
34677
35414
  // ../../packages/api-contracts/src/contracts/v1/pentest-engagement-exclusion.ts
34678
- var c34 = initContract();
34679
- var pentestEngagementExclusionContract = c34.router({
35415
+ var c35 = initContract();
35416
+ var pentestEngagementExclusionContract = c35.router({
34680
35417
  listPentestEngagementExclusions: {
34681
35418
  method: "GET",
34682
35419
  path: "/organizations/:organizationId/pentests/:pentestId/engagement-exclusions",
@@ -34740,8 +35477,8 @@ var CreatePentestEnvironmentRequestSchema = external_exports.object({
34740
35477
  }).strict();
34741
35478
 
34742
35479
  // ../../packages/api-contracts/src/contracts/v1/pentest-environment.ts
34743
- var c35 = initContract();
34744
- var pentestEnvironmentContract = c35.router({
35480
+ var c36 = initContract();
35481
+ var pentestEnvironmentContract = c36.router({
34745
35482
  listPentestEnvironments: {
34746
35483
  method: "GET",
34747
35484
  path: "/organizations/:organizationId/pentests/:pentestId/environments",
@@ -34790,8 +35527,8 @@ var pentestEnvironmentContract = c35.router({
34790
35527
  });
34791
35528
 
34792
35529
  // ../../packages/api-contracts/src/contracts/v1/pentest-finding.ts
34793
- var c36 = initContract();
34794
- var pentestFindingContract = c36.router({
35530
+ var c37 = initContract();
35531
+ var pentestFindingContract = c37.router({
34795
35532
  // ─── Findings ───
34796
35533
  listFindings: {
34797
35534
  method: "GET",
@@ -35213,6 +35950,26 @@ var pentestFindingContract = c36.router({
35213
35950
  500: ErrorResponseSchema
35214
35951
  }
35215
35952
  },
35953
+ // Customer accepts the finding → ACCEPTED_WITH_CONTROLS without a dispute or a
35954
+ // staff decision. Human principals here; an API key sends the same transition
35955
+ // through `automationStatusUpdate` with status ACCEPTED_WITH_CONTROLS.
35956
+ accept: {
35957
+ method: "POST",
35958
+ path: "/organizations/:organizationId/customer-pentests/:pentestId/findings/:pentestFindingId/accept",
35959
+ pathParams: CustomerPentestFindingIdParamsSchema,
35960
+ body: AcceptCustomerPentestFindingRequestSchema,
35961
+ responses: {
35962
+ 200: CustomerPentestFindingResponseSchema,
35963
+ 400: ErrorResponseSchema,
35964
+ 401: ErrorResponseSchema,
35965
+ 403: ErrorResponseSchema,
35966
+ 404: ErrorResponseSchema,
35967
+ // FINDING_TRANSITION_NOT_ALLOWED (bad source status / dispute pending),
35968
+ // FINDING_STALE (concurrent write), or PENTEST_CLOSED.
35969
+ 409: ErrorResponseSchema,
35970
+ 500: ErrorResponseSchema
35971
+ }
35972
+ },
35216
35973
  // ─── Automation lifecycle transition (API keys) ───
35217
35974
  // A separate route rather than a widened `start-progress` / `report-remediation`:
35218
35975
  // those stay human-only, and everything that makes a machine-driven write
@@ -35423,8 +36180,8 @@ var pentestFindingContract = c36.router({
35423
36180
  });
35424
36181
 
35425
36182
  // ../../packages/api-contracts/src/contracts/v1/pentest-hypothesis.ts
35426
- var c37 = initContract();
35427
- var pentestHypothesisContract = c37.router({
36183
+ var c38 = initContract();
36184
+ var pentestHypothesisContract = c38.router({
35428
36185
  listHypotheses: {
35429
36186
  method: "GET",
35430
36187
  path: "/organizations/:organizationId/pentests/:pentestId/hypotheses",
@@ -35579,8 +36336,8 @@ var DownloadPentestIntakeDocumentResponseSchema = external_exports.object({
35579
36336
  });
35580
36337
 
35581
36338
  // ../../packages/api-contracts/src/contracts/v1/pentest-intake-document.ts
35582
- var c38 = initContract();
35583
- var pentestIntakeDocumentContract = c38.router({
36339
+ var c39 = initContract();
36340
+ var pentestIntakeDocumentContract = c39.router({
35584
36341
  listDocuments: {
35585
36342
  method: "GET",
35586
36343
  path: "/organizations/:organizationId/customer-pentests/:pentestId/questionnaire/documents",
@@ -35666,8 +36423,8 @@ var pentestIntakeDocumentContract = c38.router({
35666
36423
  });
35667
36424
 
35668
36425
  // ../../packages/api-contracts/src/contracts/v1/pentest-manual-finding.ts
35669
- var c39 = initContract();
35670
- var pentestManualFindingContract = c39.router({
36426
+ var c40 = initContract();
36427
+ var pentestManualFindingContract = c40.router({
35671
36428
  listManualFindings: {
35672
36429
  method: "GET",
35673
36430
  path: "/organizations/:organizationId/pentests/:pentestId/manual-findings",
@@ -35753,9 +36510,42 @@ var pentestManualFindingContract = c39.router({
35753
36510
  }
35754
36511
  });
35755
36512
 
36513
+ // ../../packages/api-contracts/src/contracts/v1/pentest-purchase.ts
36514
+ var c41 = initContract();
36515
+ var pentestPurchaseContract = c41.router({
36516
+ listPurchases: {
36517
+ method: "GET",
36518
+ path: "/organizations/:organizationId/pentests/:pentestId/purchases",
36519
+ pathParams: PentestPurchaseParamsSchema,
36520
+ responses: {
36521
+ 200: ListPentestPurchasesResponseSchema,
36522
+ 401: ErrorResponseSchema,
36523
+ 403: ErrorResponseSchema,
36524
+ 404: ErrorResponseSchema,
36525
+ 500: ErrorResponseSchema
36526
+ }
36527
+ },
36528
+ voidPurchase: {
36529
+ method: "POST",
36530
+ path: "/organizations/:organizationId/pentests/:pentestId/purchases/:purchaseId/void",
36531
+ pathParams: PentestPurchaseIdParamsSchema,
36532
+ body: VoidPentestPurchaseRequestSchema,
36533
+ responses: {
36534
+ 200: PentestPurchaseSchema,
36535
+ 400: ErrorResponseSchema,
36536
+ 401: ErrorResponseSchema,
36537
+ 403: ErrorResponseSchema,
36538
+ 404: ErrorResponseSchema,
36539
+ 409: ErrorResponseSchema,
36540
+ // PURCHASE_NOT_VOIDABLE, details: { status }
36541
+ 500: ErrorResponseSchema
36542
+ }
36543
+ }
36544
+ });
36545
+
35756
36546
  // ../../packages/api-contracts/src/contracts/v1/pentest-report-pdf.ts
35757
- var c40 = initContract();
35758
- var pentestReportPdfContract = c40.router({
36547
+ var c42 = initContract();
36548
+ var pentestReportPdfContract = c42.router({
35759
36549
  getCurrent: {
35760
36550
  method: "GET",
35761
36551
  path: "/organizations/:organizationId/pentests/:pentestId/report-pdf",
@@ -35848,7 +36638,7 @@ var pentestReportPdfContract = c40.router({
35848
36638
  // No body: the render always reads current DB state (cover derived via
35849
36639
  // deriveReportCover(), narrative/scope from the row's columns). The legacy
35850
36640
  // dialog payload was retired with the Generate dialog (report-session RS5).
35851
- body: c40.noBody(),
36641
+ body: c42.noBody(),
35852
36642
  responses: {
35853
36643
  202: StartReportPdfGenerationTaskResponseSchema,
35854
36644
  400: ErrorResponseSchema,
@@ -36046,8 +36836,8 @@ var pentestReportPdfContract = c40.router({
36046
36836
  });
36047
36837
 
36048
36838
  // ../../packages/api-contracts/src/contracts/v1/pentest-validation.ts
36049
- var c41 = initContract();
36050
- var pentestValidationContract = c41.router({
36839
+ var c43 = initContract();
36840
+ var pentestValidationContract = c43.router({
36051
36841
  listValidationRuns: {
36052
36842
  method: "GET",
36053
36843
  path: "/organizations/:organizationId/pentests/:pentestId/validation-runs",
@@ -36155,8 +36945,8 @@ var pentestValidationContract = c41.router({
36155
36945
  });
36156
36946
 
36157
36947
  // ../../packages/api-contracts/src/contracts/v1/repository.ts
36158
- var c42 = initContract();
36159
- var repositoryContract = c42.router({
36948
+ var c44 = initContract();
36949
+ var repositoryContract = c44.router({
36160
36950
  createRepository: {
36161
36951
  method: "POST",
36162
36952
  path: "/organizations/:organizationId/repositories",
@@ -36361,7 +37151,7 @@ var repositoryContract = c42.router({
36361
37151
  method: "POST",
36362
37152
  path: "/organizations/:organizationId/repositories/scanning-branch/confirm-defaults",
36363
37153
  pathParams: OrgIdParamsSchema,
36364
- body: c42.noBody(),
37154
+ body: c44.noBody(),
36365
37155
  responses: {
36366
37156
  200: ConfirmScanningBranchDefaultsResponseSchema,
36367
37157
  401: ErrorResponseSchema,
@@ -36495,8 +37285,8 @@ var ListScanLogsResponseSchema = external_exports.object({
36495
37285
  });
36496
37286
 
36497
37287
  // ../../packages/api-contracts/src/contracts/v1/scan.ts
36498
- var c43 = initContract();
36499
- var scanContract = c43.router({
37288
+ var c45 = initContract();
37289
+ var scanContract = c45.router({
36500
37290
  createScan: {
36501
37291
  method: "POST",
36502
37292
  path: "/organizations/:organizationId/scans",
@@ -36617,8 +37407,8 @@ var StaffPentestStatsResponseSchema = external_exports.object({
36617
37407
  }).strict();
36618
37408
 
36619
37409
  // ../../packages/api-contracts/src/contracts/v1/staff-pentest-stats.ts
36620
- var c44 = initContract();
36621
- var staffPentestStatsContract = c44.router({
37410
+ var c46 = initContract();
37411
+ var staffPentestStatsContract = c46.router({
36622
37412
  getStaffPentestStats: {
36623
37413
  method: "GET",
36624
37414
  path: "/staff/pentest-stats",
@@ -36661,8 +37451,8 @@ var SetStaffOrganizationPentestCustomerVisibilityRequestSchema = external_export
36661
37451
  }).strict();
36662
37452
 
36663
37453
  // ../../packages/api-contracts/src/contracts/v1/staff-pentests.ts
36664
- var c45 = initContract();
36665
- var staffPentestsContract = c45.router({
37454
+ var c47 = initContract();
37455
+ var staffPentestsContract = c47.router({
36666
37456
  listStaffOrganizationPentests: {
36667
37457
  method: "GET",
36668
37458
  path: "/organizations/:organizationId/staff/pentests",
@@ -36813,8 +37603,8 @@ var StaffQueueResponseSchema = external_exports.object({
36813
37603
  }).strict();
36814
37604
 
36815
37605
  // ../../packages/api-contracts/src/contracts/v1/staff-queue.ts
36816
- var c46 = initContract();
36817
- var staffQueueContract = c46.router({
37606
+ var c48 = initContract();
37607
+ var staffQueueContract = c48.router({
36818
37608
  getStaffQueue: {
36819
37609
  method: "GET",
36820
37610
  path: "/staff/queue",
@@ -36833,12 +37623,6 @@ var NOTES_MAX = 2e3;
36833
37623
  var TestIntegrationIdParamsSchema = external_exports.object({
36834
37624
  testIntegrationId: external_exports.uuid()
36835
37625
  });
36836
- var PentestTestIntegrationsParamsSchema = OrgIdParamsSchema.extend({
36837
- pentestId: external_exports.uuid()
36838
- });
36839
- var PentestTestIntegrationIdParamsSchema = PentestTestIntegrationsParamsSchema.extend({
36840
- testIntegrationId: external_exports.uuid()
36841
- });
36842
37626
  var TestIntegrationResponseSchema = external_exports.object({
36843
37627
  testIntegrationId: external_exports.uuid(),
36844
37628
  label: external_exports.string(),
@@ -36846,20 +37630,14 @@ var TestIntegrationResponseSchema = external_exports.object({
36846
37630
  notes: external_exports.string(),
36847
37631
  createdAt: external_exports.date(),
36848
37632
  updatedAt: external_exports.date(),
36849
- /** How many pentests this fixture is attached to — blast-radius context. */
36850
- attachedPentestCount: external_exports.number().int()
37633
+ /**
37634
+ * The second factor's NON-secret parameters, or null when the integration has
37635
+ * none (or its stored parameters are unreadable). The setup key is never
37636
+ * returned by any route.
37637
+ */
37638
+ mfa: CredentialMfaSummarySchema.nullable()
36851
37639
  }).strict();
36852
37640
  var ListTestIntegrationsResponseSchema = external_exports.array(TestIntegrationResponseSchema);
36853
- var PentestTestIntegrationResponseSchema = external_exports.object({
36854
- testIntegrationId: external_exports.uuid(),
36855
- label: external_exports.string(),
36856
- notes: external_exports.string(),
36857
- attachedById: external_exports.uuid(),
36858
- attachedAt: external_exports.date()
36859
- }).strict();
36860
- var ListPentestTestIntegrationsResponseSchema = external_exports.array(
36861
- PentestTestIntegrationResponseSchema
36862
- );
36863
37641
  var TestIntegrationLoginSchema = external_exports.object({
36864
37642
  username: external_exports.string().min(1).max(512),
36865
37643
  password: external_exports.string().min(1).max(1024)
@@ -36879,13 +37657,10 @@ var UpdateTestIntegrationRequestSchema = external_exports.object({
36879
37657
  apiKey: external_exports.string().min(1).max(4096).optional(),
36880
37658
  login: TestIntegrationLoginSchema.optional()
36881
37659
  }).strict();
36882
- var AttachTestIntegrationRequestSchema = external_exports.object({
36883
- testIntegrationId: external_exports.uuid()
36884
- }).strict();
36885
37660
 
36886
37661
  // ../../packages/api-contracts/src/contracts/v1/test-integration.ts
36887
- var c47 = initContract();
36888
- var testIntegrationContract = c47.router({
37662
+ var c49 = initContract();
37663
+ var testIntegrationContract = c49.router({
36889
37664
  // -- Fixture CRUD (org-less, staff-only) ----------------------------------
36890
37665
  listTestIntegrations: {
36891
37666
  method: "GET",
@@ -36938,39 +37713,50 @@ var testIntegrationContract = c47.router({
36938
37713
  500: ErrorResponseSchema
36939
37714
  }
36940
37715
  },
36941
- // -- Attach edges (org-scoped, staff-only) --------------------------------
36942
- listPentestTestIntegrations: {
36943
- method: "GET",
36944
- path: "/organizations/:organizationId/staff/pentests/:pentestId/test-integrations",
36945
- pathParams: PentestTestIntegrationsParamsSchema,
37716
+ // -- Second factor (org-less, verified staff) ------------------------------
37717
+ // The same three routes as a customer credential's MFA (credential.ts), for
37718
+ // the same reasons: PUT carries the whole factor so re-sending is idempotent;
37719
+ // the code is a POST so it never sits in an access log or a cacheable read;
37720
+ // DELETE is idempotent. Agents never reach these: they get codes through
37721
+ // get_totp_code on the run-token channel, and never write a factor here.
37722
+ setTestIntegrationMfa: {
37723
+ method: "PUT",
37724
+ path: "/staff/test-integrations/:testIntegrationId/mfa",
37725
+ pathParams: TestIntegrationIdParamsSchema,
37726
+ body: SetCredentialMfaRequestSchema,
36946
37727
  responses: {
36947
- 200: ListPentestTestIntegrationsResponseSchema,
37728
+ // Never echoes the setup key: the integration shape, whose `mfa` carries
37729
+ // the derived non-secret parameters.
37730
+ 200: TestIntegrationResponseSchema,
37731
+ 400: ErrorResponseSchema,
37732
+ // CREDENTIAL_MFA_SETUP_KEY_INVALID
36948
37733
  401: ErrorResponseSchema,
36949
37734
  403: ErrorResponseSchema,
36950
37735
  404: ErrorResponseSchema,
36951
37736
  500: ErrorResponseSchema
36952
37737
  }
36953
37738
  },
36954
- attachTestIntegration: {
37739
+ generateTestIntegrationMfaCode: {
36955
37740
  method: "POST",
36956
- path: "/organizations/:organizationId/staff/pentests/:pentestId/test-integrations",
36957
- pathParams: PentestTestIntegrationsParamsSchema,
36958
- body: AttachTestIntegrationRequestSchema,
37741
+ path: "/staff/test-integrations/:testIntegrationId/mfa/code",
37742
+ pathParams: TestIntegrationIdParamsSchema,
37743
+ body: c49.noBody(),
36959
37744
  responses: {
36960
- 201: PentestTestIntegrationResponseSchema,
37745
+ 200: CredentialMfaCodeResponseSchema,
36961
37746
  401: ErrorResponseSchema,
36962
37747
  403: ErrorResponseSchema,
36963
37748
  404: ErrorResponseSchema,
36964
- // pentest or fixture not found
37749
+ 422: ErrorResponseSchema,
37750
+ // CREDENTIAL_MFA_NOT_ENROLLED
36965
37751
  500: ErrorResponseSchema
36966
37752
  }
36967
37753
  },
36968
- detachTestIntegration: {
37754
+ clearTestIntegrationMfa: {
36969
37755
  method: "DELETE",
36970
- path: "/organizations/:organizationId/staff/pentests/:pentestId/test-integrations/:testIntegrationId",
36971
- pathParams: PentestTestIntegrationIdParamsSchema,
37756
+ path: "/staff/test-integrations/:testIntegrationId/mfa",
37757
+ pathParams: TestIntegrationIdParamsSchema,
36972
37758
  responses: {
36973
- 204: DeleteResponseSchema,
37759
+ 200: TestIntegrationResponseSchema,
36974
37760
  401: ErrorResponseSchema,
36975
37761
  403: ErrorResponseSchema,
36976
37762
  404: ErrorResponseSchema,
@@ -37017,8 +37803,8 @@ var MyContextResponseSchema = external_exports.object({
37017
37803
  });
37018
37804
 
37019
37805
  // ../../packages/api-contracts/src/contracts/v1/user.ts
37020
- var c48 = initContract();
37021
- var userContract = c48.router({
37806
+ var c50 = initContract();
37807
+ var userContract = c50.router({
37022
37808
  getStaffProfile: {
37023
37809
  method: "GET",
37024
37810
  path: "/staff/profile",
@@ -37133,8 +37919,8 @@ var VantaIntegrationResponseSchema = external_exports.object({
37133
37919
  });
37134
37920
 
37135
37921
  // ../../packages/api-contracts/src/contracts/v1/vanta-integration.ts
37136
- var c49 = initContract();
37137
- var vantaIntegrationContract = c49.router({
37922
+ var c51 = initContract();
37923
+ var vantaIntegrationContract = c51.router({
37138
37924
  createVantaIntegration: {
37139
37925
  method: "POST",
37140
37926
  path: "/organizations/:organizationId/vanta-integration",
@@ -37476,8 +38262,8 @@ var VerifySharedVulnerabilityEmailCodeResponseSchema = external_exports.object({
37476
38262
  });
37477
38263
 
37478
38264
  // ../../packages/api-contracts/src/contracts/v1/vulnerability.ts
37479
- var c50 = initContract();
37480
- var vulnerabilityContract = c50.router({
38265
+ var c52 = initContract();
38266
+ var vulnerabilityContract = c52.router({
37481
38267
  filterVulnerabilities: {
37482
38268
  method: "POST",
37483
38269
  path: "/organizations/:organizationId/vulnerabilities/filter",
@@ -37702,8 +38488,8 @@ var UpdateVulnerabilityNoteRequestSchema = external_exports.object({
37702
38488
  });
37703
38489
 
37704
38490
  // ../../packages/api-contracts/src/contracts/v1/vulnerability-note.ts
37705
- var c51 = initContract();
37706
- var vulnerabilityNoteContract = c51.router({
38491
+ var c53 = initContract();
38492
+ var vulnerabilityNoteContract = c53.router({
37707
38493
  listNotes: {
37708
38494
  method: "GET",
37709
38495
  path: "/organizations/:organizationId/vulnerabilities/:vulnerabilityId/notes",
@@ -37884,8 +38670,8 @@ var ListWebhookDeliveriesResponseSchema = external_exports.object({
37884
38670
  });
37885
38671
 
37886
38672
  // ../../packages/api-contracts/src/contracts/v1/webhook-settings.ts
37887
- var c52 = initContract();
37888
- var webhookSettingsContract = c52.router({
38673
+ var c54 = initContract();
38674
+ var webhookSettingsContract = c54.router({
37889
38675
  listWebhookEndpoints: {
37890
38676
  method: "GET",
37891
38677
  path: "/organizations/:organizationId/webhook-settings/endpoints",
@@ -38023,8 +38809,8 @@ var webhookSettingsContract = c52.router({
38023
38809
  });
38024
38810
 
38025
38811
  // ../../packages/api-contracts/src/contracts/v1/index.ts
38026
- var c53 = initContract();
38027
- var v1Contract = c53.router(
38812
+ var c55 = initContract();
38813
+ var v1Contract = c55.router(
38028
38814
  {
38029
38815
  admin: adminContract,
38030
38816
  cloudIntegration: cloudIntegrationContract,
@@ -38074,6 +38860,8 @@ var v1Contract = c53.router(
38074
38860
  inviteLink: inviteLinkContract,
38075
38861
  engagement: engagementContract,
38076
38862
  testIntegration: testIntegrationContract,
38863
+ paymentCard: paymentCardContract,
38864
+ pentestPurchase: pentestPurchaseContract,
38077
38865
  pentestEgress: pentestEgressContract,
38078
38866
  staffPentestStats: staffPentestStatsContract,
38079
38867
  staffPentests: staffPentestsContract,
@@ -38085,19 +38873,60 @@ var v1Contract = c53.router(
38085
38873
  );
38086
38874
 
38087
38875
  // ../../packages/api-contracts/src/contracts/index.ts
38088
- var c54 = initContract();
38089
- var contract = c54.router({
38876
+ var c56 = initContract();
38877
+ var contract = c56.router({
38090
38878
  v1: v1Contract
38091
38879
  });
38092
38880
 
38881
+ // ../../packages/api-contracts/src/contracts/v1/desktop-host-internal.ts
38882
+ var c57 = initContract();
38883
+ var MAX_VMS_PER_SYNC = 16;
38884
+ var DesktopHostSyncRequestSchema = external_exports.object({
38885
+ /** Integer protocol the runner speaks. Below the api's minimum, the host gets
38886
+ * no new targets but keeps serving the ones it holds. */
38887
+ protocolVersion: external_exports.number().int().min(1),
38888
+ runnerVersion: external_exports.string().min(1).max(200),
38889
+ /** Target ids with a VM on disk OR being created right now. */
38890
+ presentVmIds: external_exports.array(external_exports.uuid()).max(MAX_VMS_PER_SYNC)
38891
+ });
38892
+ var DesktopHostSyncTargetSchema = external_exports.object({
38893
+ desktopTargetId: external_exports.uuid(),
38894
+ status: external_exports.enum(["PROVISIONING", "READY"]),
38895
+ runVersion: external_exports.number().int().min(0),
38896
+ runToken: external_exports.string().min(1),
38897
+ /** Epoch millis the host deletes the VM by, whatever the api says later. */
38898
+ localDeadlineMs: external_exports.number().int().positive(),
38899
+ heartbeatSec: external_exports.number().int().positive()
38900
+ });
38901
+ var DesktopHostSyncResponseSchema = external_exports.object({
38902
+ syncIntervalMs: external_exports.number().int().positive(),
38903
+ /** This host's PROVISIONING and READY targets. Any VM the runner holds for an
38904
+ * id not listed here is deleted. */
38905
+ targets: external_exports.array(DesktopHostSyncTargetSchema).max(MAX_VMS_PER_SYNC)
38906
+ });
38907
+ var desktopHostInternalContract = c57.router({
38908
+ sync: {
38909
+ method: "POST",
38910
+ path: "/internal/v1/desktop-hosts/sync",
38911
+ body: DesktopHostSyncRequestSchema,
38912
+ responses: {
38913
+ 200: DesktopHostSyncResponseSchema,
38914
+ 400: ErrorResponseSchema,
38915
+ // Bad, expired or revoked host token, or a decommissioned host.
38916
+ 401: ErrorResponseSchema,
38917
+ 500: ErrorResponseSchema
38918
+ }
38919
+ }
38920
+ });
38921
+
38093
38922
  // ../../packages/api-contracts/src/schemas/api/v1/github-webhook.api.ts
38094
38923
  var GitHubWebhookResponseSchema = external_exports.object({
38095
38924
  ok: external_exports.boolean()
38096
38925
  });
38097
38926
 
38098
38927
  // ../../packages/api-contracts/src/contracts/webhooks/github.ts
38099
- var c55 = initContract();
38100
- var githubWebhookContract = c55.router(
38928
+ var c58 = initContract();
38929
+ var githubWebhookContract = c58.router(
38101
38930
  {
38102
38931
  handleWebhook: {
38103
38932
  method: "POST",
@@ -38115,7 +38944,7 @@ var githubWebhookContract = c55.router(
38115
38944
  pathPrefix: "/webhooks"
38116
38945
  }
38117
38946
  );
38118
- var githubReadonlyWebhookContract = c55.router(
38947
+ var githubReadonlyWebhookContract = c58.router(
38119
38948
  {
38120
38949
  handleWebhook: {
38121
38950
  method: "POST",
@@ -38135,9 +38964,9 @@ var githubReadonlyWebhookContract = c55.router(
38135
38964
  );
38136
38965
 
38137
38966
  // ../../packages/api-contracts/src/contracts/webhooks/linear.ts
38138
- var c56 = initContract();
38967
+ var c59 = initContract();
38139
38968
  var LinearWebhookResponseSchema = external_exports.object({ ok: external_exports.boolean() });
38140
- var linearWebhookContract = c56.router(
38969
+ var linearWebhookContract = c59.router(
38141
38970
  {
38142
38971
  handleWebhook: {
38143
38972
  method: "POST",
@@ -38157,7 +38986,7 @@ var linearWebhookContract = c56.router(
38157
38986
  );
38158
38987
 
38159
38988
  // ../../packages/api-contracts/src/contracts/forge/bitbucket.ts
38160
- var c57 = initContract();
38989
+ var c60 = initContract();
38161
38990
  var InstallEventSchema = external_exports.object({
38162
38991
  eventType: external_exports.enum(["avi:forge:installed:app", "avi:forge:upgraded:app"]),
38163
38992
  context: external_exports.object({ cloudId: external_exports.string().min(1) }).loose(),
@@ -38186,7 +39015,7 @@ var ForgePairingCodeResponseSchema = external_exports.discriminatedUnion("state"
38186
39015
  expiresInSeconds: external_exports.number().int()
38187
39016
  })
38188
39017
  ]);
38189
- var forgeBitbucketContract = c57.router(
39018
+ var forgeBitbucketContract = c60.router(
38190
39019
  {
38191
39020
  lifecycle: {
38192
39021
  method: "POST",
@@ -38233,8 +39062,8 @@ var HealthResponseSchema = external_exports.object({
38233
39062
  });
38234
39063
 
38235
39064
  // ../../packages/api-contracts/src/contracts/health.ts
38236
- var c58 = initContract();
38237
- var healthContract = c58.router({
39065
+ var c61 = initContract();
39066
+ var healthContract = c61.router({
38238
39067
  getHealth: {
38239
39068
  method: "GET",
38240
39069
  path: "/health",
@@ -38246,8 +39075,8 @@ var healthContract = c58.router({
38246
39075
  });
38247
39076
 
38248
39077
  // ../../packages/api-contracts/src/contracts/v1/vulnerability-share.ts
38249
- var c59 = initContract();
38250
- var vulnerabilityShareContract = c59.router(
39078
+ var c62 = initContract();
39079
+ var vulnerabilityShareContract = c62.router(
38251
39080
  {
38252
39081
  resolveShareLink: {
38253
39082
  method: "GET",
@@ -38334,8 +39163,8 @@ var UpdatePrVulnerabilityRequestSchema = external_exports.object({
38334
39163
  });
38335
39164
 
38336
39165
  // ../../packages/api-contracts/src/contracts/v1/pr-vulnerability.ts
38337
- var c60 = initContract();
38338
- var prVulnerabilityContract = c60.router(
39166
+ var c63 = initContract();
39167
+ var prVulnerabilityContract = c63.router(
38339
39168
  {
38340
39169
  listPrVulnerabilities: {
38341
39170
  method: "GET",
@@ -39659,6 +40488,10 @@ var SEVERITY_ORDER = {
39659
40488
  LOW: 3,
39660
40489
  INFORMATIONAL: 4
39661
40490
  };
40491
+ function printJson(value) {
40492
+ process.stdout.write(`${JSON.stringify(value, null, 2)}
40493
+ `);
40494
+ }
39662
40495
  function formatStatus(status) {
39663
40496
  return status.toLowerCase().replace(/_/g, " ");
39664
40497
  }
@@ -40366,7 +41199,7 @@ async function runRepositoryListCommand(options) {
40366
41199
  process.exit(1);
40367
41200
  }
40368
41201
  if (options.output === "json") {
40369
- console.log(JSON.stringify(displayedRepositories, null, 2));
41202
+ printJson(displayedRepositories);
40370
41203
  return;
40371
41204
  }
40372
41205
  if (options.output === "tsv") {
@@ -40450,7 +41283,7 @@ async function runDependencyFilter(organizationId, options) {
40450
41283
  process.exit(1);
40451
41284
  }
40452
41285
  if (options.output === "json") {
40453
- console.log(JSON.stringify(displayedRepos, null, 2));
41286
+ printJson(displayedRepos);
40454
41287
  return;
40455
41288
  }
40456
41289
  if (options.output === "tsv") {
@@ -40782,7 +41615,7 @@ async function runSetScanningBranchCommand(repoUrl, options) {
40782
41615
  }
40783
41616
  const urlById = new Map(listResult2.body.map((r2) => [r2.repositoryId, r2.repositoryUrl]));
40784
41617
  if (options.output === "json") {
40785
- console.log(JSON.stringify(allResults, null, 2));
41618
+ printJson(allResults);
40786
41619
  return;
40787
41620
  }
40788
41621
  console.log("repositoryUrl status relabeledCount error");
@@ -40964,13 +41797,7 @@ async function runSetScanningInclusionCommand(references, includedInScanning, op
40964
41797
  process.exit(1);
40965
41798
  }
40966
41799
  if (options.output === "json") {
40967
- console.log(
40968
- JSON.stringify(
40969
- { includedInScanning, updatedCount, notFoundRepositoryIds, repositories: outcomes },
40970
- null,
40971
- 2
40972
- )
40973
- );
41800
+ printJson({ includedInScanning, updatedCount, notFoundRepositoryIds, repositories: outcomes });
40974
41801
  return;
40975
41802
  }
40976
41803
  const notFound = new Set(notFoundRepositoryIds);
@@ -41255,12 +42082,12 @@ function buildApplicationsTable(apps) {
41255
42082
  repos: String(a2.repositories.length),
41256
42083
  url: a2.applicationUrl ? sanitizeDisplay(a2.applicationUrl) : "\u2014"
41257
42084
  }));
41258
- const idWidth = Math.max(2, ...cells.map((c62) => c62.id.length));
41259
- const nameWidth = Math.max(4, ...cells.map((c62) => c62.name.length));
41260
- const typeWidth = Math.max(4, ...cells.map((c62) => c62.type.length));
42085
+ const idWidth = Math.max(2, ...cells.map((c65) => c65.id.length));
42086
+ const nameWidth = Math.max(4, ...cells.map((c65) => c65.name.length));
42087
+ const typeWidth = Math.max(4, ...cells.map((c65) => c65.type.length));
41261
42088
  const header = `${"ID".padEnd(idWidth)} ${"NAME".padEnd(nameWidth)} ${"TYPE".padEnd(typeWidth)} REPOS URL`;
41262
42089
  const rows = cells.map(
41263
- (c62) => `${c62.id.padEnd(idWidth)} ${c62.name.padEnd(nameWidth)} ${c62.type.padEnd(typeWidth)} ${c62.repos.padStart(5)} ${c62.url}`
42090
+ (c65) => `${c65.id.padEnd(idWidth)} ${c65.name.padEnd(nameWidth)} ${c65.type.padEnd(typeWidth)} ${c65.repos.padStart(5)} ${c65.url}`
41264
42091
  );
41265
42092
  return { header, rows };
41266
42093
  }
@@ -41280,12 +42107,12 @@ function buildApplicationRepositoriesTable(links) {
41280
42107
  path: l2.repositoryPath ? sanitizeDisplay(l2.repositoryPath) : "\u2014",
41281
42108
  status: formatStatus(l2.repositoryStatus)
41282
42109
  }));
41283
- const nameWidth = Math.max(10, ...cells.map((c62) => c62.name.length));
41284
- const roleWidth = Math.max(4, ...cells.map((c62) => c62.role.length));
41285
- const pathWidth = Math.max(4, ...cells.map((c62) => c62.path.length));
42110
+ const nameWidth = Math.max(10, ...cells.map((c65) => c65.name.length));
42111
+ const roleWidth = Math.max(4, ...cells.map((c65) => c65.role.length));
42112
+ const pathWidth = Math.max(4, ...cells.map((c65) => c65.path.length));
41286
42113
  const header = `${"REPOSITORY".padEnd(nameWidth)} SCAN ${"ROLE".padEnd(roleWidth)} ${"PATH".padEnd(pathWidth)} STATUS`;
41287
42114
  const rows = cells.map(
41288
- (c62) => `${c62.name.padEnd(nameWidth)} ${c62.scan.padEnd(4)} ${c62.role.padEnd(roleWidth)} ${c62.path.padEnd(pathWidth)} ${c62.status}`
42115
+ (c65) => `${c65.name.padEnd(nameWidth)} ${c65.scan.padEnd(4)} ${c65.role.padEnd(roleWidth)} ${c65.path.padEnd(pathWidth)} ${c65.status}`
41289
42116
  );
41290
42117
  return { header, rows };
41291
42118
  }
@@ -41326,7 +42153,7 @@ function printApplicationRepositoriesTsv(links) {
41326
42153
  }
41327
42154
  function outputApplication(app, output) {
41328
42155
  if (output === "json") {
41329
- console.log(JSON.stringify(app, null, 2));
42156
+ printJson(app);
41330
42157
  return;
41331
42158
  }
41332
42159
  if (output === "tsv") {
@@ -41411,7 +42238,7 @@ async function runList(options) {
41411
42238
  }
41412
42239
  const apps = result.body;
41413
42240
  if (output === "json") {
41414
- console.log(JSON.stringify(apps, null, 2));
42241
+ printJson(apps);
41415
42242
  return;
41416
42243
  }
41417
42244
  if (output === "tsv") {
@@ -41460,7 +42287,7 @@ async function runRepos(applicationId, options) {
41460
42287
  }
41461
42288
  const links = sortApplicationRepositoryLinks(result.body);
41462
42289
  if (output === "json") {
41463
- console.log(JSON.stringify(links, null, 2));
42290
+ printJson(links);
41464
42291
  return;
41465
42292
  }
41466
42293
  if (output === "tsv") {
@@ -42070,8 +42897,8 @@ function wrapTextWithPrefix(e, r2, o2, t2 = o2, s = o2, n3) {
42070
42897
  hard: true,
42071
42898
  trim: false
42072
42899
  }).split(`
42073
- `).map((c62, i2, m2) => {
42074
- const d = n3 ? n3(c62, i2) : c62;
42900
+ `).map((c65, i2, m2) => {
42901
+ const d = n3 ? n3(c65, i2) : c65;
42075
42902
  return i2 === 0 ? `${t2}${d}` : i2 === m2.length - 1 ? `${s}${d}` : `${o2}${d}`;
42076
42903
  }).join(`
42077
42904
  `);
@@ -42569,14 +43396,14 @@ var limitOptions = ({
42569
43396
  Math.min(l2 - a2 + 3, e.length - a2),
42570
43397
  0
42571
43398
  ));
42572
- let d = a2 < e.length && f > 0, c62 = a2 < e.length && f + a2 < e.length;
43399
+ let d = a2 < e.length && f > 0, c65 = a2 < e.length && f + a2 < e.length;
42573
43400
  const W = Math.min(
42574
43401
  f + a2,
42575
43402
  e.length
42576
43403
  ), s = [];
42577
43404
  let g = 0;
42578
- d && g++, c62 && g++;
42579
- const T = f + (d ? 1 : 0), y = W - (c62 ? 1 : 0);
43405
+ d && g++, c65 && g++;
43406
+ const T = f + (d ? 1 : 0), y = W - (c65 ? 1 : 0);
42580
43407
  for (let t2 = T; t2 < y; t2++) {
42581
43408
  const n3 = e[t2], o2 = n3 ? w(n3, t2 === l2) : "", h2 = wrapAnsi(o2, i2, {
42582
43409
  hard: true,
@@ -42597,14 +43424,14 @@ var limitOptions = ({
42597
43424
  u4,
42598
43425
  true
42599
43426
  );
42600
- d ? ({ lineCount: o2, removals: t2 } = L(), o2 > u4 && (c62 || (u4 -= 1), { lineCount: o2, removals: n3 } = E())) : (c62 || (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 && (c62 = true, s.splice(s.length - n3, n3));
43427
+ d ? ({ lineCount: o2, removals: t2 } = L(), o2 > u4 && (c65 || (u4 -= 1), { lineCount: o2, removals: n3 } = E())) : (c65 || (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 && (c65 = true, s.splice(s.length - n3, n3));
42601
43428
  }
42602
43429
  const x = [];
42603
43430
  d && x.push(M);
42604
43431
  for (const t2 of s)
42605
43432
  for (const n3 of t2)
42606
43433
  x.push(n3);
42607
- return c62 && x.push(M), x;
43434
+ return c65 && x.push(M), x;
42608
43435
  };
42609
43436
  var confirm = (i2) => {
42610
43437
  const a2 = i2.active ?? "Yes", s = i2.inactive ?? "No";
@@ -42623,15 +43450,15 @@ var confirm = (i2) => {
42623
43450
  u4
42624
43451
  ), o2 = `${e ? `${styleText2("gray", S_BAR)}
42625
43452
  ` : ""}${f}
42626
- `, c62 = this.value ? a2 : s;
43453
+ `, c65 = this.value ? a2 : s;
42627
43454
  switch (this.state) {
42628
43455
  case "submit": {
42629
43456
  const r2 = e ? `${styleText2("gray", S_BAR)} ` : "";
42630
- return `${o2}${r2}${styleText2("dim", c62)}`;
43457
+ return `${o2}${r2}${styleText2("dim", c65)}`;
42631
43458
  }
42632
43459
  case "cancel": {
42633
43460
  const r2 = e ? `${styleText2("gray", S_BAR)} ` : "";
42634
- return `${o2}${r2}${styleText2(["strikethrough", "dim"], c62)}${e ? `
43461
+ return `${o2}${r2}${styleText2(["strikethrough", "dim"], c65)}${e ? `
42635
43462
  ${styleText2("gray", S_BAR)}` : ""}`;
42636
43463
  }
42637
43464
  default: {
@@ -42779,13 +43606,13 @@ var multiline = (e) => new h({
42779
43606
  `, m2 = e.placeholder && e.placeholder.length > 0 ? (
42780
43607
  // biome-ignore lint/style/noNonNullAssertion: guarded by placeholder.length > 0
42781
43608
  styleText2("inverse", e.placeholder[0]) + styleText2("dim", e.placeholder.slice(1))
42782
- ) : styleText2(["inverse", "hidden"], "_"), a2 = this.userInput ? this.userInputWithCursor : m2, l2 = this.value ?? "", c62 = e.showSubmit ? `
43609
+ ) : styleText2(["inverse", "hidden"], "_"), a2 = this.userInput ? this.userInputWithCursor : m2, l2 = this.value ?? "", c65 = e.showSubmit ? `
42783
43610
  ${styleText2(this.focused === "submit" ? "cyan" : "dim", "[ submit ]")}` : "";
42784
43611
  switch (this.state) {
42785
43612
  case "error": {
42786
43613
  const n3 = `${styleText2("yellow", S_BAR)} `, r2 = i2 ? wrapTextWithPrefix(e.output, a2, n3, void 0) : a2, u4 = styleText2("yellow", S_BAR_END);
42787
43614
  return `${o2}${r2}
42788
- ${u4} ${styleText2("yellow", this.error)}${c62}
43615
+ ${u4} ${styleText2("yellow", this.error)}${c65}
42789
43616
  `;
42790
43617
  }
42791
43618
  case "submit": {
@@ -42813,7 +43640,7 @@ ${u4} ${styleText2("yellow", this.error)}${c62}
42813
43640
  default: {
42814
43641
  const n3 = i2 ? `${styleText2("cyan", S_BAR)} ` : "", r2 = i2 ? styleText2("cyan", S_BAR_END) : "", u4 = i2 ? wrapTextWithPrefix(e.output, a2, n3) : a2;
42815
43642
  return `${o2}${u4}
42816
- ${r2}${c62}
43643
+ ${r2}${c65}
42817
43644
  `;
42818
43645
  }
42819
43646
  }
@@ -42828,7 +43655,7 @@ var password = (r2) => new u$1({
42828
43655
  render() {
42829
43656
  const e = r2.withGuide ?? settings.withGuide, o2 = `${e ? `${styleText2("gray", S_BAR)}
42830
43657
  ` : ""}${symbol2(this.state)} ${r2.message}
42831
- `, c62 = this.userInputWithCursor, i2 = this.masked;
43658
+ `, c65 = this.userInputWithCursor, i2 = this.masked;
42832
43659
  switch (this.state) {
42833
43660
  case "error": {
42834
43661
  const s = e ? `${styleText2("yellow", S_BAR)} ` : "", n3 = e ? `${styleText2("yellow", S_BAR_END)} ` : "", l2 = i2 ?? "";
@@ -42848,7 +43675,7 @@ ${styleText2("gray", S_BAR)}` : ""}`;
42848
43675
  }
42849
43676
  default: {
42850
43677
  const s = e ? `${styleText2("cyan", S_BAR)} ` : "", n3 = e ? styleText2("cyan", S_BAR_END) : "";
42851
- return `${o2}${s}${c62}
43678
+ return `${o2}${s}${c65}
42852
43679
  ${n3}
42853
43680
  `;
42854
43681
  }
@@ -42864,7 +43691,7 @@ var SELECT_INSTRUCTIONS = [
42864
43691
  `${styleText2("dim", "\u2191/\u2193")} to navigate`,
42865
43692
  `${styleText2("dim", "Enter:")} confirm`
42866
43693
  ];
42867
- var c61 = (t2, o2) => t2.includes(`
43694
+ var c64 = (t2, o2) => t2.includes(`
42868
43695
  `) ? t2.split(`
42869
43696
  `).map((d) => o2(d)).join(`
42870
43697
  `) : o2(t2);
@@ -42875,15 +43702,15 @@ var select = (t2) => {
42875
43702
  const s = n3.label ?? String(n3.value);
42876
43703
  switch (m2) {
42877
43704
  case "disabled":
42878
- return `${styleText2("gray", S_RADIO_INACTIVE)} ${c61(s, (i2) => styleText2("gray", i2))}${n3.hint ? ` ${styleText2("dim", `(${n3.hint ?? "disabled"})`)}` : ""}`;
43705
+ return `${styleText2("gray", S_RADIO_INACTIVE)} ${c64(s, (i2) => styleText2("gray", i2))}${n3.hint ? ` ${styleText2("dim", `(${n3.hint ?? "disabled"})`)}` : ""}`;
42879
43706
  case "selected":
42880
- return `${c61(s, (i2) => styleText2("dim", i2))}`;
43707
+ return `${c64(s, (i2) => styleText2("dim", i2))}`;
42881
43708
  case "active":
42882
43709
  return `${styleText2("green", S_RADIO_ACTIVE)} ${s}${n3.hint ? ` ${styleText2("dim", `(${n3.hint})`)}` : ""}`;
42883
43710
  case "cancelled":
42884
- return `${c61(s, (i2) => styleText2(["strikethrough", "dim"], i2))}`;
43711
+ return `${c64(s, (i2) => styleText2(["strikethrough", "dim"], i2))}`;
42885
43712
  default:
42886
- return `${styleText2("dim", S_RADIO_INACTIVE)} ${c61(s, (i2) => styleText2("dim", i2))}`;
43713
+ return `${styleText2("dim", S_RADIO_INACTIVE)} ${c64(s, (i2) => styleText2("dim", i2))}`;
42887
43714
  }
42888
43715
  }, d = t2.showInstructions ?? true;
42889
43716
  return new n$1({
@@ -43165,7 +43992,7 @@ async function uploadLogo(organizationId, variant, file2) {
43165
43992
  }
43166
43993
  function outputOrganization(org, output, derived) {
43167
43994
  if (output === "json") {
43168
- console.log(JSON.stringify(org, null, 2));
43995
+ printJson(org);
43169
43996
  return;
43170
43997
  }
43171
43998
  if (output === "tsv") {
@@ -43697,7 +44524,7 @@ Examples:
43697
44524
  }
43698
44525
  }
43699
44526
  if (options.output === "json") {
43700
- console.log(JSON.stringify(info, null, 2));
44527
+ printJson(info);
43701
44528
  if (!info.loggedIn) {
43702
44529
  process.exitCode = 1;
43703
44530
  }
@@ -43836,7 +44663,7 @@ Examples:
43836
44663
  );
43837
44664
  const items = options.limit !== void 0 ? filteredItems.slice(0, options.limit) : filteredItems;
43838
44665
  if (options.output === "json") {
43839
- console.log(JSON.stringify(items, null, 2));
44666
+ printJson(items);
43840
44667
  return;
43841
44668
  }
43842
44669
  if (options.output === "tsv") {
@@ -43912,16 +44739,10 @@ Examples:
43912
44739
  const active = organizationContext.activeOrganization;
43913
44740
  const source = organizationContext.selectedOrganizationId === active.organizationId ? "selected" : "default";
43914
44741
  if (options.output === "json") {
43915
- console.log(
43916
- JSON.stringify(
43917
- {
43918
- ...active,
43919
- source
43920
- },
43921
- null,
43922
- 2
43923
- )
43924
- );
44742
+ printJson({
44743
+ ...active,
44744
+ source
44745
+ });
43925
44746
  return;
43926
44747
  }
43927
44748
  if (options.output === "tsv") {
@@ -44221,7 +45042,7 @@ Examples:
44221
45042
  }
44222
45043
  const { organizationId, slug } = resolution.organization;
44223
45044
  if (options.web) {
44224
- const url2 = `${getAppBaseUrl()}/dashboard/${slug}/settings/integrations/github`;
45045
+ const url2 = `${getAppBaseUrl()}/dashboard/${slug}/settings/integrations/source-code`;
44225
45046
  const opened = await openBrowser(url2);
44226
45047
  if (!opened) {
44227
45048
  console.log(`Open in browser: ${url2}`);
@@ -44241,7 +45062,7 @@ Examples:
44241
45062
  }
44242
45063
  const codeSize = result.body;
44243
45064
  if (options.output === "json") {
44244
- console.log(JSON.stringify(codeSize, null, 2));
45065
+ printJson(codeSize);
44245
45066
  return;
44246
45067
  }
44247
45068
  if (options.output === "tsv") {
@@ -44267,7 +45088,7 @@ function extractCommandTree(cmd) {
44267
45088
  description: o2.description,
44268
45089
  takesValue: o2.required || o2.optional
44269
45090
  }));
44270
- const subcommands = cmd.commands.filter((c62) => !c62._hidden).map((c62) => extractCommandTree(c62));
45091
+ const subcommands = cmd.commands.filter((c65) => !c65._hidden).map((c65) => extractCommandTree(c65));
44271
45092
  return {
44272
45093
  name: cmd.name(),
44273
45094
  description: cmd.description(),
@@ -44333,7 +45154,7 @@ function generateBashCompletion(tree, binName) {
44333
45154
  }
44334
45155
  function collectBashCases(tree, prefix) {
44335
45156
  const cases = /* @__PURE__ */ new Map();
44336
- const subcommandNames = tree.subcommands.map((c62) => c62.name);
45157
+ const subcommandNames = tree.subcommands.map((c65) => c65.name);
44337
45158
  const optionNames = tree.options.flatMap((o2) => o2.short ? [o2.long, o2.short] : [o2.long]);
44338
45159
  const extraOptions = prefix === "" ? ["--help", "--version"] : ["--help"];
44339
45160
  const allOptions = [.../* @__PURE__ */ new Set([...optionNames, ...extraOptions])];
@@ -44748,9 +45569,9 @@ function buildInboxesTable(inboxes) {
44748
45569
  address: sanitizeDisplay(inbox.address),
44749
45570
  label: sanitizeDisplay(inbox.label)
44750
45571
  }));
44751
- const addressWidth = Math.max(7, ...cells.map((c62) => c62.address.length));
45572
+ const addressWidth = Math.max(7, ...cells.map((c65) => c65.address.length));
44752
45573
  const header = `${"ADDRESS".padEnd(addressWidth)} LABEL`;
44753
- const rows = cells.map((c62) => `${c62.address.padEnd(addressWidth)} ${c62.label}`);
45574
+ const rows = cells.map((c65) => `${c65.address.padEnd(addressWidth)} ${c65.label}`);
44754
45575
  return { header, rows };
44755
45576
  }
44756
45577
  function formatInboxQuota(quota) {
@@ -44774,14 +45595,14 @@ function buildInboxEmailsTable(messages) {
44774
45595
  subject: sanitizeDisplay(message.subject ?? ""),
44775
45596
  unread: message.unread ? "yes" : "no"
44776
45597
  }));
44777
- const idWidth = Math.max(2, ...cells.map((c62) => c62.id.length));
44778
- const receivedWidth = Math.max(8, ...cells.map((c62) => c62.received.length));
44779
- const fromWidth = Math.max(4, ...cells.map((c62) => c62.from.length));
44780
- const toWidth = Math.max(2, ...cells.map((c62) => c62.to.length));
44781
- const subjectWidth = Math.max(7, ...cells.map((c62) => c62.subject.length));
45598
+ const idWidth = Math.max(2, ...cells.map((c65) => c65.id.length));
45599
+ const receivedWidth = Math.max(8, ...cells.map((c65) => c65.received.length));
45600
+ const fromWidth = Math.max(4, ...cells.map((c65) => c65.from.length));
45601
+ const toWidth = Math.max(2, ...cells.map((c65) => c65.to.length));
45602
+ const subjectWidth = Math.max(7, ...cells.map((c65) => c65.subject.length));
44782
45603
  const header = `${"ID".padEnd(idWidth)} ${"RECEIVED".padEnd(receivedWidth)} ${"FROM".padEnd(fromWidth)} ${"TO".padEnd(toWidth)} ${"SUBJECT".padEnd(subjectWidth)} UNREAD`;
44783
45604
  const rows = cells.map(
44784
- (c62) => `${c62.id.padEnd(idWidth)} ${c62.received.padEnd(receivedWidth)} ${c62.from.padEnd(fromWidth)} ${c62.to.padEnd(toWidth)} ${c62.subject.padEnd(subjectWidth)} ${c62.unread}`
45605
+ (c65) => `${c65.id.padEnd(idWidth)} ${c65.received.padEnd(receivedWidth)} ${c65.from.padEnd(fromWidth)} ${c65.to.padEnd(toWidth)} ${c65.subject.padEnd(subjectWidth)} ${c65.unread}`
44785
45606
  );
44786
45607
  return { header, rows };
44787
45608
  }
@@ -44894,7 +45715,7 @@ function parseEmailSince(value) {
44894
45715
  }
44895
45716
  function outputInbox(inbox, output) {
44896
45717
  if (output === "json") {
44897
- console.log(JSON.stringify(inbox, null, 2));
45718
+ printJson(inbox);
44898
45719
  return;
44899
45720
  }
44900
45721
  if (output === "tsv") {
@@ -44939,7 +45760,7 @@ async function runList2(options) {
44939
45760
  }
44940
45761
  const { inboxes, quota } = result.body;
44941
45762
  if (output === "json") {
44942
- console.log(JSON.stringify({ inboxes, quota }, null, 2));
45763
+ printJson({ inboxes, quota });
44943
45764
  return;
44944
45765
  }
44945
45766
  if (output === "tsv") {
@@ -45025,7 +45846,7 @@ async function runEmails(label, options) {
45025
45846
  }
45026
45847
  const { address, messages } = result.body;
45027
45848
  if (output === "json") {
45028
- console.log(JSON.stringify(result.body, null, 2));
45849
+ printJson(result.body);
45029
45850
  return;
45030
45851
  }
45031
45852
  if (output === "tsv") {
@@ -45061,7 +45882,7 @@ async function runEmail(label, messageId, options) {
45061
45882
  failReadOp2("read email", result.status, result.body, label);
45062
45883
  }
45063
45884
  if (output === "json") {
45064
- console.log(JSON.stringify(result.body, null, 2));
45885
+ printJson(result.body);
45065
45886
  return;
45066
45887
  }
45067
45888
  if (output === "tsv") {
@@ -45556,22 +46377,22 @@ function printCredentialsTsv(creds) {
45556
46377
  }
45557
46378
  }
45558
46379
  function buildCredentialsTable(creds) {
45559
- const cells = creds.map((c62) => ({
45560
- id: c62.credentialId,
45561
- label: sanitizeDisplay(c62.label),
45562
- type: c62.credentialType
46380
+ const cells = creds.map((c65) => ({
46381
+ id: c65.credentialId,
46382
+ label: sanitizeDisplay(c65.label),
46383
+ type: c65.credentialType
45563
46384
  }));
45564
- const idWidth = Math.max(2, ...cells.map((c62) => c62.id.length));
45565
- const labelWidth = Math.max(5, ...cells.map((c62) => c62.label.length));
46385
+ const idWidth = Math.max(2, ...cells.map((c65) => c65.id.length));
46386
+ const labelWidth = Math.max(5, ...cells.map((c65) => c65.label.length));
45566
46387
  const header = `${"ID".padEnd(idWidth)} ${"LABEL".padEnd(labelWidth)} TYPE`;
45567
46388
  const rows = cells.map(
45568
- (c62) => `${c62.id.padEnd(idWidth)} ${c62.label.padEnd(labelWidth)} ${c62.type}`
46389
+ (c65) => `${c65.id.padEnd(idWidth)} ${c65.label.padEnd(labelWidth)} ${c65.type}`
45569
46390
  );
45570
46391
  return { header, rows };
45571
46392
  }
45572
46393
  function outputCredential(cred, output) {
45573
46394
  if (output === "json") {
45574
- console.log(JSON.stringify(cred, null, 2));
46395
+ printJson(cred);
45575
46396
  return;
45576
46397
  }
45577
46398
  if (output === "tsv") {
@@ -45771,7 +46592,7 @@ async function runList3(options) {
45771
46592
  }
45772
46593
  const creds = result.body;
45773
46594
  if (output === "json") {
45774
- console.log(JSON.stringify(creds, null, 2));
46595
+ printJson(creds);
45775
46596
  return;
45776
46597
  }
45777
46598
  if (output === "tsv") {
@@ -45972,7 +46793,7 @@ async function runMfaCode(credentialId, options) {
45972
46793
  failMfaOp("generate a code for", result.status, result.body, credentialId);
45973
46794
  }
45974
46795
  if (output === "json") {
45975
- console.log(JSON.stringify(result.body, null, 2));
46796
+ printJson(result.body);
45976
46797
  return;
45977
46798
  }
45978
46799
  if (output === "tsv") {
@@ -46210,6 +47031,12 @@ function failWriteOp4(action, status, body, notFoundLabel) {
46210
47031
  message ?? "This environment is frozen by an active pentest and cannot be changed."
46211
47032
  )
46212
47033
  );
47034
+ } else if (errorCode === "ENVIRONMENT_IN_USE_BY_PENTEST") {
47035
+ console.error(
47036
+ colorError(
47037
+ message ?? "A pentest still uses this environment. Remove it from the engagement first."
47038
+ )
47039
+ );
46213
47040
  } else {
46214
47041
  console.error(colorError(message ?? "Conflict (status 409)."));
46215
47042
  }
@@ -46329,14 +47156,14 @@ function buildEnvironmentTable(envs, leading) {
46329
47156
  url: e.primaryUrl != null ? sanitizeDisplay(e.primaryUrl) : "\u2014"
46330
47157
  }));
46331
47158
  const leadingWidths = leading.map(
46332
- (column, i2) => Math.max(column.header.length, ...cells.map((c62) => c62.leading[i2]?.length ?? 0))
47159
+ (column, i2) => Math.max(column.header.length, ...cells.map((c65) => c65.leading[i2]?.length ?? 0))
46333
47160
  );
46334
- const nameWidth = Math.max(4, ...cells.map((c62) => c62.name.length));
47161
+ const nameWidth = Math.max(4, ...cells.map((c65) => c65.name.length));
46335
47162
  const padLeading = (values) => values.map((v, i2) => v.padEnd(leadingWidths[i2] ?? 0)).join(" ");
46336
47163
  return {
46337
- header: `${padLeading(leading.map((c62) => c62.header))} ${"NAME".padEnd(nameWidth)} PROD URL`,
47164
+ header: `${padLeading(leading.map((c65) => c65.header))} ${"NAME".padEnd(nameWidth)} PROD URL`,
46338
47165
  rows: cells.map(
46339
- (c62) => `${padLeading(c62.leading)} ${c62.name.padEnd(nameWidth)} ${c62.prod.padEnd(4)} ${c62.url}`
47166
+ (c65) => `${padLeading(c65.leading)} ${c65.name.padEnd(nameWidth)} ${c65.prod.padEnd(4)} ${c65.url}`
46340
47167
  )
46341
47168
  };
46342
47169
  }
@@ -46355,7 +47182,7 @@ function buildEnvironmentsTable(envs) {
46355
47182
  }
46356
47183
  function outputEnvironment(env2, output) {
46357
47184
  if (output === "json") {
46358
- console.log(JSON.stringify(env2, null, 2));
47185
+ printJson(env2);
46359
47186
  return;
46360
47187
  }
46361
47188
  if (output === "tsv") {
@@ -46477,7 +47304,7 @@ async function runListAcrossOrganization(output, pager) {
46477
47304
  createOrgEnvironmentRequests(organizationId)
46478
47305
  );
46479
47306
  if (output === "json") {
46480
- console.log(JSON.stringify(envs, null, 2));
47307
+ printJson(envs);
46481
47308
  return;
46482
47309
  }
46483
47310
  if (output === "tsv") {
@@ -46517,7 +47344,7 @@ async function runList4(options) {
46517
47344
  }
46518
47345
  const envs = result.body;
46519
47346
  if (output === "json") {
46520
- console.log(JSON.stringify(envs, null, 2));
47347
+ printJson(envs);
46521
47348
  return;
46522
47349
  }
46523
47350
  if (output === "tsv") {
@@ -47011,7 +47838,7 @@ async function runCreateFinding(options) {
47011
47838
  failCreateFinding(result.status, result.body, options.pentest);
47012
47839
  }
47013
47840
  if (options.output === "json") {
47014
- console.log(JSON.stringify(result.body, null, 2));
47841
+ printJson(result.body);
47015
47842
  return;
47016
47843
  }
47017
47844
  printCreatedFinding({
@@ -47180,6 +48007,12 @@ async function prepareUploadFile(filePath, options = {}) {
47180
48007
  }
47181
48008
 
47182
48009
  // src/pentest/status-update.ts
48010
+ var STATUS_UPDATE_TARGETS = [
48011
+ "IN_PROGRESS",
48012
+ "REMEDIATED",
48013
+ "ACCEPTED_WITH_CONTROLS"
48014
+ ];
48015
+ var STATUS_UPDATE_TARGET_LIST = STATUS_UPDATE_TARGETS.join(", ");
47183
48016
  var PENTEST_IDENTIFIER_PATTERN = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|pt-\d+|\d+)$/i;
47184
48017
  var FINDING_IDENTIFIER_PATTERN = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|ptf-\d+|\d+)$/i;
47185
48018
  var MAX_NOTE_LENGTH = 1e4;
@@ -47190,11 +48023,15 @@ function parseStatusUpdateTarget(raw) {
47190
48023
  error: "IN_REVIEW is not a finding status. Use IN_PROGRESS while fixing, then REMEDIATED when the fix is ready for retest."
47191
48024
  };
47192
48025
  }
47193
- if (normalized === "IN_PROGRESS" || normalized === "REMEDIATED") {
47194
- return normalized;
48026
+ if (normalized === "ACCEPTED" || normalized === "ACCEPT") {
48027
+ return "ACCEPTED_WITH_CONTROLS";
48028
+ }
48029
+ const target = STATUS_UPDATE_TARGETS.find((candidate) => candidate === normalized);
48030
+ if (target !== void 0) {
48031
+ return target;
47195
48032
  }
47196
48033
  return {
47197
- error: `Invalid --status '${sanitizeDisplay(raw)}'. Use IN_PROGRESS or REMEDIATED.`
48034
+ error: `Invalid --status '${sanitizeDisplay(raw)}'. Use ${STATUS_UPDATE_TARGET_LIST}.`
47198
48035
  };
47199
48036
  }
47200
48037
  function isPentestIdentifier(value) {
@@ -47203,6 +48040,17 @@ function isPentestIdentifier(value) {
47203
48040
  function isFindingIdentifier(value) {
47204
48041
  return FINDING_IDENTIFIER_PATTERN.test(value);
47205
48042
  }
48043
+ function requireAcceptRationale(note) {
48044
+ if (note === void 0) {
48045
+ console.error(
48046
+ colorError(
48047
+ "--note is required when accepting a finding: say why the risk is acceptable or which controls cover it."
48048
+ )
48049
+ );
48050
+ process.exit(1);
48051
+ }
48052
+ return note;
48053
+ }
47206
48054
  function failStatusUpdate(status, body, viaApiKey) {
47207
48055
  const { message, errorCode } = readErrorFields(body);
47208
48056
  if (status === UNAUTHORIZED_STATUS2) {
@@ -47295,10 +48143,13 @@ async function runStatusUpdate(options) {
47295
48143
  }
47296
48144
  if (note !== void 0 && target === "IN_PROGRESS") {
47297
48145
  console.error(
47298
- colorError("--note is only used when reporting remediation (--status REMEDIATED).")
48146
+ colorError(
48147
+ "--note is only used when reporting remediation or accepting (--status REMEDIATED or ACCEPTED_WITH_CONTROLS)."
48148
+ )
47299
48149
  );
47300
48150
  process.exit(1);
47301
48151
  }
48152
+ const rationale = target === "ACCEPTED_WITH_CONTROLS" ? requireAcceptRationale(note) : null;
47302
48153
  const viaApiKey = requireAuth().kind === "api_key";
47303
48154
  const organizationId = await resolveOrganizationId();
47304
48155
  const params = {
@@ -47311,6 +48162,8 @@ async function runStatusUpdate(options) {
47311
48162
  params,
47312
48163
  body: { status: target, ...note !== void 0 ? { note } : {} }
47313
48164
  })
48165
+ ) : rationale !== null ? await authenticatedRequest(
48166
+ (client) => client.pentestFinding.accept({ params, body: { rationale } })
47314
48167
  ) : target === "IN_PROGRESS" ? await authenticatedRequest(
47315
48168
  (client) => client.pentestFinding.startProgress({ params, body: {} })
47316
48169
  ) : await authenticatedRequest(
@@ -47323,7 +48176,7 @@ async function runStatusUpdate(options) {
47323
48176
  failStatusUpdate(result.status, result.body, viaApiKey);
47324
48177
  }
47325
48178
  if (options.output === "json") {
47326
- console.log(JSON.stringify(result.body, null, 2));
48179
+ printJson(result.body);
47327
48180
  return;
47328
48181
  }
47329
48182
  const displayId = result.body.displayId;
@@ -47331,19 +48184,24 @@ async function runStatusUpdate(options) {
47331
48184
  console.log(colorSuccess(`PTF-${displayId} is now ${status}`));
47332
48185
  }
47333
48186
  function createStatusUpdateCommand() {
47334
- return new Command("status-update").description("Move a pentest finding to IN_PROGRESS or REMEDIATED").requiredOption("--pentest <id>", "Pentest display ID (e.g. PT-3) or UUID").requiredOption("--finding <id>", "Finding number (e.g. PTF-7) or UUID").requiredOption(
48187
+ return new Command("status-update").description("Move a pentest finding to IN_PROGRESS, REMEDIATED, or ACCEPTED_WITH_CONTROLS").requiredOption("--pentest <id>", "Pentest display ID (e.g. PT-3) or UUID").requiredOption("--finding <id>", "Finding number (e.g. PTF-7) or UUID").requiredOption(
47335
48188
  "--status <status>",
47336
- "IN_PROGRESS (start work) or REMEDIATED (ready for retest)"
47337
- ).option("--note <text>", "Optional context when reporting remediation").option("-o, --output <format>", "Output format: text, json (default: text)", "text").addHelpText(
48189
+ "IN_PROGRESS (start work), REMEDIATED (ready for retest), or ACCEPTED_WITH_CONTROLS (accept the risk)"
48190
+ ).option(
48191
+ "--note <text>",
48192
+ "Context when reporting remediation; the required rationale when accepting"
48193
+ ).option("-o, --output <format>", "Output format: text, json (default: text)", "text").addHelpText(
47338
48194
  "after",
47339
48195
  `
47340
48196
  Customer-facing status writes \u2014 the same transitions as the dashboard. An agent
47341
48197
  can mark a finding in progress when it starts the fix, then remediated when the
47342
48198
  fix is ready for Trace to re-test. Leaving the finding IN_PROGRESS (and not
47343
- sending REMEDIATED) keeps it out of the retest queue.
48199
+ sending REMEDIATED) keeps it out of the retest queue. ACCEPTED_WITH_CONTROLS
48200
+ (also spelled ACCEPTED) closes the finding as an accepted risk with no Trace
48201
+ review; --note carries the rationale and is required.
47344
48202
 
47345
- IN_PROGRESS is allowed from OPEN or VERIFIED_OPEN. REMEDIATED is allowed from
47346
- OPEN, IN_PROGRESS, or VERIFIED_OPEN.
48203
+ IN_PROGRESS is allowed from OPEN, VERIFIED_OPEN, or PARTIALLY_FIXED. REMEDIATED and
48204
+ ACCEPTED_WITH_CONTROLS are allowed from OPEN, IN_PROGRESS, VERIFIED_OPEN, or PARTIALLY_FIXED.
47347
48205
 
47348
48206
  A signed-in session (\`tracecli auth login\`) attributes the change to you. A
47349
48207
  Trace API key works too, once Trace enables finding automation for your
@@ -47354,7 +48212,9 @@ Examples:
47354
48212
  tracecli pentest findings status-update --pentest PT-3 --finding 7 --status IN_PROGRESS
47355
48213
  tracecli pentest findings status-update --pentest PT-3 --finding PTF-7 --status REMEDIATED
47356
48214
  tracecli pentest findings status-update --pentest PT-3 --finding 7 --status REMEDIATED \\
47357
- --note "Fixed in PR 412" --output json`
48215
+ --note "Fixed in PR 412" --output json
48216
+ tracecli pentest findings status-update --pentest PT-3 --finding 7 --status ACCEPTED \\
48217
+ --note "Internal-only endpoint behind SSO; residual risk accepted"`
47358
48218
  ).action(async (options) => {
47359
48219
  await runStatusUpdate(options);
47360
48220
  });
@@ -47616,7 +48476,7 @@ async function runReportDownload(pentestIdentifier, options) {
47616
48476
  output
47617
48477
  });
47618
48478
  if (output === "json") {
47619
- console.log(JSON.stringify({ report, artifact, path: destination, sizeBytes: bytes }, null, 2));
48479
+ printJson({ report, artifact, path: destination, sizeBytes: bytes });
47620
48480
  return;
47621
48481
  }
47622
48482
  if (output === "tsv") {
@@ -47720,7 +48580,7 @@ async function runAttestationList(pentestIdentifier, options) {
47720
48580
  const organizationId = await resolveOrganizationId();
47721
48581
  const attestations = await fetchAttestations(organizationId, pentestIdentifier);
47722
48582
  if (output === "json") {
47723
- console.log(JSON.stringify(attestations, null, 2));
48583
+ printJson(attestations);
47724
48584
  return;
47725
48585
  }
47726
48586
  if (output === "tsv") {
@@ -47805,7 +48665,7 @@ async function runAttestationDownload(pentestIdentifier, options) {
47805
48665
  output
47806
48666
  });
47807
48667
  if (output === "json") {
47808
- console.log(JSON.stringify({ attestation, path: destination, sizeBytes: bytes }, null, 2));
48668
+ printJson({ attestation, path: destination, sizeBytes: bytes });
47809
48669
  return;
47810
48670
  }
47811
48671
  if (output === "tsv") {
@@ -47994,7 +48854,7 @@ async function runAttachEvidence(options) {
47994
48854
  process.exit(1);
47995
48855
  }
47996
48856
  if (options.output === "json") {
47997
- console.log(JSON.stringify(attached.body, null, 2));
48857
+ printJson(attached.body);
47998
48858
  return;
47999
48859
  }
48000
48860
  const visibility = attached.body.customerFacing ? "customer-facing" : "staff-internal";
@@ -48147,7 +49007,7 @@ async function runGetFinding(options) {
48147
49007
  failGetFinding(result.status, result.body);
48148
49008
  }
48149
49009
  if (options.output === "json") {
48150
- console.log(JSON.stringify(result.body, null, 2));
49010
+ printJson(result.body);
48151
49011
  return;
48152
49012
  }
48153
49013
  process.stdout.write(formatFindingMarkdown(result.body));
@@ -48388,7 +49248,7 @@ Examples:
48388
49248
  return;
48389
49249
  }
48390
49250
  if (isJson) {
48391
- console.log(JSON.stringify(pentests, null, 2));
49251
+ printJson(pentests);
48392
49252
  return;
48393
49253
  }
48394
49254
  if (isTsv) {
@@ -48439,7 +49299,7 @@ function createFindingsListCommand() {
48439
49299
  (value) => value.toUpperCase()
48440
49300
  ).option(
48441
49301
  "--status <status>",
48442
- "Filter by status (OPEN, IN_PROGRESS, CONTESTED, REMEDIATED, VERIFIED_FIXED, VERIFIED_OPEN, ACCEPTED_WITH_CONTROLS, DISMISSED)",
49302
+ `Filter by status (${PentestFindingStatusValues.join(", ")})`,
48443
49303
  (value) => value.toUpperCase()
48444
49304
  ).option(
48445
49305
  "-L, --limit <n>",
@@ -48471,7 +49331,9 @@ Full detail, for feeding an agent that fixes the findings:
48471
49331
 
48472
49332
  Then mark work as it happens:
48473
49333
  tracecli pentest findings status-update --pentest PT-3 --finding 7 --status IN_PROGRESS
48474
- tracecli pentest findings status-update --pentest PT-3 --finding 7 --status REMEDIATED`
49334
+ tracecli pentest findings status-update --pentest PT-3 --finding 7 --status REMEDIATED
49335
+ tracecli pentest findings status-update --pentest PT-3 --finding 7 --status ACCEPTED \\
49336
+ --note "Internal-only endpoint behind SSO; residual risk accepted"`
48475
49337
  ).action(
48476
49338
  async (options) => {
48477
49339
  if (options.detail && options.output !== "json") {
@@ -48537,7 +49399,7 @@ Re-run with: tracecli pentest findings list --pentest ${options.pentest} --detai
48537
49399
  return;
48538
49400
  }
48539
49401
  if (isJson) {
48540
- console.log(JSON.stringify(findings, null, 2));
49402
+ printJson(findings);
48541
49403
  return;
48542
49404
  }
48543
49405
  if (isTsv) {
@@ -48630,7 +49492,7 @@ async function runFindingsDetailPull(organizationId, options) {
48630
49492
  }
48631
49493
  return { findings: result.body.findings, total: result.body.total };
48632
49494
  }, options);
48633
- console.log(JSON.stringify(matching, null, 2));
49495
+ printJson(matching);
48634
49496
  }
48635
49497
  function renderPentestFindingLines(finding) {
48636
49498
  const sev = formatFindingSeverity(finding.severity);
@@ -48791,7 +49653,7 @@ function printPentestUpdateTsv(pt) {
48791
49653
  }
48792
49654
  function outputPentestUpdate(pt, output) {
48793
49655
  if (output === "json") {
48794
- console.log(JSON.stringify(pt, null, 2));
49656
+ printJson(pt);
48795
49657
  return;
48796
49658
  }
48797
49659
  if (output === "tsv") {
@@ -49956,13 +50818,13 @@ function buildUploadsTable(uploads) {
49956
50818
  size: formatArchiveBytes(upload.sizeBytes),
49957
50819
  id: upload.codeUploadId
49958
50820
  }));
49959
- const nameWidth = Math.max(4, ...cells.map((c62) => c62.name.length));
49960
- const kindWidth = Math.max(4, ...cells.map((c62) => c62.kind.length));
49961
- const statusWidth = Math.max(6, ...cells.map((c62) => c62.status.length));
49962
- const sizeWidth = Math.max(4, ...cells.map((c62) => c62.size.length));
50821
+ const nameWidth = Math.max(4, ...cells.map((c65) => c65.name.length));
50822
+ const kindWidth = Math.max(4, ...cells.map((c65) => c65.kind.length));
50823
+ const statusWidth = Math.max(6, ...cells.map((c65) => c65.status.length));
50824
+ const sizeWidth = Math.max(4, ...cells.map((c65) => c65.size.length));
49963
50825
  const header = `${"NAME".padEnd(nameWidth)} ${"KIND".padEnd(kindWidth)} ${"STATUS".padEnd(statusWidth)} ${"SIZE".padEnd(sizeWidth)} ID`;
49964
50826
  const rows = cells.map(
49965
- (c62) => `${c62.name.padEnd(nameWidth)} ${c62.kind.padEnd(kindWidth)} ${c62.status.padEnd(statusWidth)} ${c62.size.padEnd(sizeWidth)} ${c62.id}`
50827
+ (c65) => `${c65.name.padEnd(nameWidth)} ${c65.kind.padEnd(kindWidth)} ${c65.status.padEnd(statusWidth)} ${c65.size.padEnd(sizeWidth)} ${c65.id}`
49966
50828
  );
49967
50829
  return { header, rows };
49968
50830
  }
@@ -50025,7 +50887,7 @@ function printUploadsTsv(uploads) {
50025
50887
  }
50026
50888
  function outputUpload(upload, output) {
50027
50889
  if (output === "json") {
50028
- console.log(JSON.stringify(upload, null, 2));
50890
+ printJson(upload);
50029
50891
  return;
50030
50892
  }
50031
50893
  if (output === "tsv") {
@@ -50320,7 +51182,7 @@ async function runList5(options) {
50320
51182
  const output = parseOutput(options.output);
50321
51183
  if (options.web) {
50322
51184
  const slug = await resolveOrganizationSlug();
50323
- const url2 = `${getAppBaseUrl()}/dashboard/${slug}/settings/integrations/sources`;
51185
+ const url2 = `${getAppBaseUrl()}/dashboard/${slug}/settings/integrations/source-code/upload`;
50324
51186
  const opened = await openBrowser(url2);
50325
51187
  if (!opened) console.log(url2);
50326
51188
  return;
@@ -50333,7 +51195,7 @@ async function runList5(options) {
50333
51195
  ...applicationId !== void 0 ? { applicationId } : {}
50334
51196
  });
50335
51197
  if (output === "json") {
50336
- console.log(JSON.stringify({ uploads }, null, 2));
51198
+ printJson({ uploads });
50337
51199
  return;
50338
51200
  }
50339
51201
  if (output === "tsv") {
@@ -50397,18 +51259,12 @@ async function runDownload(codeUploadIdArg, options, runtime) {
50397
51259
  process.exit(1);
50398
51260
  }
50399
51261
  if (output === "json") {
50400
- console.log(
50401
- JSON.stringify(
50402
- {
50403
- upload,
50404
- path: destination,
50405
- sizeBytes: upload.sizeBytes,
50406
- archiveSha256: upload.archiveSha256
50407
- },
50408
- null,
50409
- 2
50410
- )
50411
- );
51262
+ printJson({
51263
+ upload,
51264
+ path: destination,
51265
+ sizeBytes: upload.sizeBytes,
51266
+ archiveSha256: upload.archiveSha256
51267
+ });
50412
51268
  return;
50413
51269
  }
50414
51270
  if (output === "tsv") {
@@ -50486,7 +51342,7 @@ async function runLink(options) {
50486
51342
  failWriteOp5("link", result.status, result.body);
50487
51343
  }
50488
51344
  if (output === "json") {
50489
- console.log(JSON.stringify(result.body, null, 2));
51345
+ printJson(result.body);
50490
51346
  return;
50491
51347
  }
50492
51348
  if (output === "tsv") {
@@ -50833,7 +51689,7 @@ Run \`tracecli vulnerabilities list\` to see available vulnerabilities.`
50833
51689
  process.exit(1);
50834
51690
  }
50835
51691
  if (options.output === "json") {
50836
- console.log(JSON.stringify(result.body, null, 2));
51692
+ printJson(result.body);
50837
51693
  return;
50838
51694
  }
50839
51695
  if (options.output === "tsv") {
@@ -50957,7 +51813,7 @@ Examples:
50957
51813
  return;
50958
51814
  }
50959
51815
  if (isJson) {
50960
- console.log(JSON.stringify(items, null, 2));
51816
+ printJson(items);
50961
51817
  } else if (isTsv) {
50962
51818
  printVulnerabilitiesTsv(items);
50963
51819
  } else {