securewithtrace 0.45.1 → 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 +1211 -341
  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()
32928
33455
  });
33456
+ var UpdateReferrerRequestSchema = external_exports.object({
33457
+ proseSpelling: ProseSpellingSchema
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",
@@ -41253,12 +42082,12 @@ function buildApplicationsTable(apps) {
41253
42082
  repos: String(a2.repositories.length),
41254
42083
  url: a2.applicationUrl ? sanitizeDisplay(a2.applicationUrl) : "\u2014"
41255
42084
  }));
41256
- const idWidth = Math.max(2, ...cells.map((c62) => c62.id.length));
41257
- const nameWidth = Math.max(4, ...cells.map((c62) => c62.name.length));
41258
- 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));
41259
42088
  const header = `${"ID".padEnd(idWidth)} ${"NAME".padEnd(nameWidth)} ${"TYPE".padEnd(typeWidth)} REPOS URL`;
41260
42089
  const rows = cells.map(
41261
- (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}`
41262
42091
  );
41263
42092
  return { header, rows };
41264
42093
  }
@@ -41278,12 +42107,12 @@ function buildApplicationRepositoriesTable(links) {
41278
42107
  path: l2.repositoryPath ? sanitizeDisplay(l2.repositoryPath) : "\u2014",
41279
42108
  status: formatStatus(l2.repositoryStatus)
41280
42109
  }));
41281
- const nameWidth = Math.max(10, ...cells.map((c62) => c62.name.length));
41282
- const roleWidth = Math.max(4, ...cells.map((c62) => c62.role.length));
41283
- 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));
41284
42113
  const header = `${"REPOSITORY".padEnd(nameWidth)} SCAN ${"ROLE".padEnd(roleWidth)} ${"PATH".padEnd(pathWidth)} STATUS`;
41285
42114
  const rows = cells.map(
41286
- (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}`
41287
42116
  );
41288
42117
  return { header, rows };
41289
42118
  }
@@ -42068,8 +42897,8 @@ function wrapTextWithPrefix(e, r2, o2, t2 = o2, s = o2, n3) {
42068
42897
  hard: true,
42069
42898
  trim: false
42070
42899
  }).split(`
42071
- `).map((c62, i2, m2) => {
42072
- const d = n3 ? n3(c62, i2) : c62;
42900
+ `).map((c65, i2, m2) => {
42901
+ const d = n3 ? n3(c65, i2) : c65;
42073
42902
  return i2 === 0 ? `${t2}${d}` : i2 === m2.length - 1 ? `${s}${d}` : `${o2}${d}`;
42074
42903
  }).join(`
42075
42904
  `);
@@ -42567,14 +43396,14 @@ var limitOptions = ({
42567
43396
  Math.min(l2 - a2 + 3, e.length - a2),
42568
43397
  0
42569
43398
  ));
42570
- 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;
42571
43400
  const W = Math.min(
42572
43401
  f + a2,
42573
43402
  e.length
42574
43403
  ), s = [];
42575
43404
  let g = 0;
42576
- d && g++, c62 && g++;
42577
- 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);
42578
43407
  for (let t2 = T; t2 < y; t2++) {
42579
43408
  const n3 = e[t2], o2 = n3 ? w(n3, t2 === l2) : "", h2 = wrapAnsi(o2, i2, {
42580
43409
  hard: true,
@@ -42595,14 +43424,14 @@ var limitOptions = ({
42595
43424
  u4,
42596
43425
  true
42597
43426
  );
42598
- 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));
42599
43428
  }
42600
43429
  const x = [];
42601
43430
  d && x.push(M);
42602
43431
  for (const t2 of s)
42603
43432
  for (const n3 of t2)
42604
43433
  x.push(n3);
42605
- return c62 && x.push(M), x;
43434
+ return c65 && x.push(M), x;
42606
43435
  };
42607
43436
  var confirm = (i2) => {
42608
43437
  const a2 = i2.active ?? "Yes", s = i2.inactive ?? "No";
@@ -42621,15 +43450,15 @@ var confirm = (i2) => {
42621
43450
  u4
42622
43451
  ), o2 = `${e ? `${styleText2("gray", S_BAR)}
42623
43452
  ` : ""}${f}
42624
- `, c62 = this.value ? a2 : s;
43453
+ `, c65 = this.value ? a2 : s;
42625
43454
  switch (this.state) {
42626
43455
  case "submit": {
42627
43456
  const r2 = e ? `${styleText2("gray", S_BAR)} ` : "";
42628
- return `${o2}${r2}${styleText2("dim", c62)}`;
43457
+ return `${o2}${r2}${styleText2("dim", c65)}`;
42629
43458
  }
42630
43459
  case "cancel": {
42631
43460
  const r2 = e ? `${styleText2("gray", S_BAR)} ` : "";
42632
- return `${o2}${r2}${styleText2(["strikethrough", "dim"], c62)}${e ? `
43461
+ return `${o2}${r2}${styleText2(["strikethrough", "dim"], c65)}${e ? `
42633
43462
  ${styleText2("gray", S_BAR)}` : ""}`;
42634
43463
  }
42635
43464
  default: {
@@ -42777,13 +43606,13 @@ var multiline = (e) => new h({
42777
43606
  `, m2 = e.placeholder && e.placeholder.length > 0 ? (
42778
43607
  // biome-ignore lint/style/noNonNullAssertion: guarded by placeholder.length > 0
42779
43608
  styleText2("inverse", e.placeholder[0]) + styleText2("dim", e.placeholder.slice(1))
42780
- ) : 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 ? `
42781
43610
  ${styleText2(this.focused === "submit" ? "cyan" : "dim", "[ submit ]")}` : "";
42782
43611
  switch (this.state) {
42783
43612
  case "error": {
42784
43613
  const n3 = `${styleText2("yellow", S_BAR)} `, r2 = i2 ? wrapTextWithPrefix(e.output, a2, n3, void 0) : a2, u4 = styleText2("yellow", S_BAR_END);
42785
43614
  return `${o2}${r2}
42786
- ${u4} ${styleText2("yellow", this.error)}${c62}
43615
+ ${u4} ${styleText2("yellow", this.error)}${c65}
42787
43616
  `;
42788
43617
  }
42789
43618
  case "submit": {
@@ -42811,7 +43640,7 @@ ${u4} ${styleText2("yellow", this.error)}${c62}
42811
43640
  default: {
42812
43641
  const n3 = i2 ? `${styleText2("cyan", S_BAR)} ` : "", r2 = i2 ? styleText2("cyan", S_BAR_END) : "", u4 = i2 ? wrapTextWithPrefix(e.output, a2, n3) : a2;
42813
43642
  return `${o2}${u4}
42814
- ${r2}${c62}
43643
+ ${r2}${c65}
42815
43644
  `;
42816
43645
  }
42817
43646
  }
@@ -42826,7 +43655,7 @@ var password = (r2) => new u$1({
42826
43655
  render() {
42827
43656
  const e = r2.withGuide ?? settings.withGuide, o2 = `${e ? `${styleText2("gray", S_BAR)}
42828
43657
  ` : ""}${symbol2(this.state)} ${r2.message}
42829
- `, c62 = this.userInputWithCursor, i2 = this.masked;
43658
+ `, c65 = this.userInputWithCursor, i2 = this.masked;
42830
43659
  switch (this.state) {
42831
43660
  case "error": {
42832
43661
  const s = e ? `${styleText2("yellow", S_BAR)} ` : "", n3 = e ? `${styleText2("yellow", S_BAR_END)} ` : "", l2 = i2 ?? "";
@@ -42846,7 +43675,7 @@ ${styleText2("gray", S_BAR)}` : ""}`;
42846
43675
  }
42847
43676
  default: {
42848
43677
  const s = e ? `${styleText2("cyan", S_BAR)} ` : "", n3 = e ? styleText2("cyan", S_BAR_END) : "";
42849
- return `${o2}${s}${c62}
43678
+ return `${o2}${s}${c65}
42850
43679
  ${n3}
42851
43680
  `;
42852
43681
  }
@@ -42862,7 +43691,7 @@ var SELECT_INSTRUCTIONS = [
42862
43691
  `${styleText2("dim", "\u2191/\u2193")} to navigate`,
42863
43692
  `${styleText2("dim", "Enter:")} confirm`
42864
43693
  ];
42865
- var c61 = (t2, o2) => t2.includes(`
43694
+ var c64 = (t2, o2) => t2.includes(`
42866
43695
  `) ? t2.split(`
42867
43696
  `).map((d) => o2(d)).join(`
42868
43697
  `) : o2(t2);
@@ -42873,15 +43702,15 @@ var select = (t2) => {
42873
43702
  const s = n3.label ?? String(n3.value);
42874
43703
  switch (m2) {
42875
43704
  case "disabled":
42876
- 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"})`)}` : ""}`;
42877
43706
  case "selected":
42878
- return `${c61(s, (i2) => styleText2("dim", i2))}`;
43707
+ return `${c64(s, (i2) => styleText2("dim", i2))}`;
42879
43708
  case "active":
42880
43709
  return `${styleText2("green", S_RADIO_ACTIVE)} ${s}${n3.hint ? ` ${styleText2("dim", `(${n3.hint})`)}` : ""}`;
42881
43710
  case "cancelled":
42882
- return `${c61(s, (i2) => styleText2(["strikethrough", "dim"], i2))}`;
43711
+ return `${c64(s, (i2) => styleText2(["strikethrough", "dim"], i2))}`;
42883
43712
  default:
42884
- 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))}`;
42885
43714
  }
42886
43715
  }, d = t2.showInstructions ?? true;
42887
43716
  return new n$1({
@@ -44213,7 +45042,7 @@ Examples:
44213
45042
  }
44214
45043
  const { organizationId, slug } = resolution.organization;
44215
45044
  if (options.web) {
44216
- const url2 = `${getAppBaseUrl()}/dashboard/${slug}/settings/integrations/github`;
45045
+ const url2 = `${getAppBaseUrl()}/dashboard/${slug}/settings/integrations/source-code`;
44217
45046
  const opened = await openBrowser(url2);
44218
45047
  if (!opened) {
44219
45048
  console.log(`Open in browser: ${url2}`);
@@ -44259,7 +45088,7 @@ function extractCommandTree(cmd) {
44259
45088
  description: o2.description,
44260
45089
  takesValue: o2.required || o2.optional
44261
45090
  }));
44262
- 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));
44263
45092
  return {
44264
45093
  name: cmd.name(),
44265
45094
  description: cmd.description(),
@@ -44325,7 +45154,7 @@ function generateBashCompletion(tree, binName) {
44325
45154
  }
44326
45155
  function collectBashCases(tree, prefix) {
44327
45156
  const cases = /* @__PURE__ */ new Map();
44328
- const subcommandNames = tree.subcommands.map((c62) => c62.name);
45157
+ const subcommandNames = tree.subcommands.map((c65) => c65.name);
44329
45158
  const optionNames = tree.options.flatMap((o2) => o2.short ? [o2.long, o2.short] : [o2.long]);
44330
45159
  const extraOptions = prefix === "" ? ["--help", "--version"] : ["--help"];
44331
45160
  const allOptions = [.../* @__PURE__ */ new Set([...optionNames, ...extraOptions])];
@@ -44740,9 +45569,9 @@ function buildInboxesTable(inboxes) {
44740
45569
  address: sanitizeDisplay(inbox.address),
44741
45570
  label: sanitizeDisplay(inbox.label)
44742
45571
  }));
44743
- const addressWidth = Math.max(7, ...cells.map((c62) => c62.address.length));
45572
+ const addressWidth = Math.max(7, ...cells.map((c65) => c65.address.length));
44744
45573
  const header = `${"ADDRESS".padEnd(addressWidth)} LABEL`;
44745
- const rows = cells.map((c62) => `${c62.address.padEnd(addressWidth)} ${c62.label}`);
45574
+ const rows = cells.map((c65) => `${c65.address.padEnd(addressWidth)} ${c65.label}`);
44746
45575
  return { header, rows };
44747
45576
  }
44748
45577
  function formatInboxQuota(quota) {
@@ -44766,14 +45595,14 @@ function buildInboxEmailsTable(messages) {
44766
45595
  subject: sanitizeDisplay(message.subject ?? ""),
44767
45596
  unread: message.unread ? "yes" : "no"
44768
45597
  }));
44769
- const idWidth = Math.max(2, ...cells.map((c62) => c62.id.length));
44770
- const receivedWidth = Math.max(8, ...cells.map((c62) => c62.received.length));
44771
- const fromWidth = Math.max(4, ...cells.map((c62) => c62.from.length));
44772
- const toWidth = Math.max(2, ...cells.map((c62) => c62.to.length));
44773
- 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));
44774
45603
  const header = `${"ID".padEnd(idWidth)} ${"RECEIVED".padEnd(receivedWidth)} ${"FROM".padEnd(fromWidth)} ${"TO".padEnd(toWidth)} ${"SUBJECT".padEnd(subjectWidth)} UNREAD`;
44775
45604
  const rows = cells.map(
44776
- (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}`
44777
45606
  );
44778
45607
  return { header, rows };
44779
45608
  }
@@ -45548,16 +46377,16 @@ function printCredentialsTsv(creds) {
45548
46377
  }
45549
46378
  }
45550
46379
  function buildCredentialsTable(creds) {
45551
- const cells = creds.map((c62) => ({
45552
- id: c62.credentialId,
45553
- label: sanitizeDisplay(c62.label),
45554
- type: c62.credentialType
46380
+ const cells = creds.map((c65) => ({
46381
+ id: c65.credentialId,
46382
+ label: sanitizeDisplay(c65.label),
46383
+ type: c65.credentialType
45555
46384
  }));
45556
- const idWidth = Math.max(2, ...cells.map((c62) => c62.id.length));
45557
- 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));
45558
46387
  const header = `${"ID".padEnd(idWidth)} ${"LABEL".padEnd(labelWidth)} TYPE`;
45559
46388
  const rows = cells.map(
45560
- (c62) => `${c62.id.padEnd(idWidth)} ${c62.label.padEnd(labelWidth)} ${c62.type}`
46389
+ (c65) => `${c65.id.padEnd(idWidth)} ${c65.label.padEnd(labelWidth)} ${c65.type}`
45561
46390
  );
45562
46391
  return { header, rows };
45563
46392
  }
@@ -46202,6 +47031,12 @@ function failWriteOp4(action, status, body, notFoundLabel) {
46202
47031
  message ?? "This environment is frozen by an active pentest and cannot be changed."
46203
47032
  )
46204
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
+ );
46205
47040
  } else {
46206
47041
  console.error(colorError(message ?? "Conflict (status 409)."));
46207
47042
  }
@@ -46321,14 +47156,14 @@ function buildEnvironmentTable(envs, leading) {
46321
47156
  url: e.primaryUrl != null ? sanitizeDisplay(e.primaryUrl) : "\u2014"
46322
47157
  }));
46323
47158
  const leadingWidths = leading.map(
46324
- (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))
46325
47160
  );
46326
- const nameWidth = Math.max(4, ...cells.map((c62) => c62.name.length));
47161
+ const nameWidth = Math.max(4, ...cells.map((c65) => c65.name.length));
46327
47162
  const padLeading = (values) => values.map((v, i2) => v.padEnd(leadingWidths[i2] ?? 0)).join(" ");
46328
47163
  return {
46329
- 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`,
46330
47165
  rows: cells.map(
46331
- (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}`
46332
47167
  )
46333
47168
  };
46334
47169
  }
@@ -47172,6 +48007,12 @@ async function prepareUploadFile(filePath, options = {}) {
47172
48007
  }
47173
48008
 
47174
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(", ");
47175
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;
47176
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;
47177
48018
  var MAX_NOTE_LENGTH = 1e4;
@@ -47182,11 +48023,15 @@ function parseStatusUpdateTarget(raw) {
47182
48023
  error: "IN_REVIEW is not a finding status. Use IN_PROGRESS while fixing, then REMEDIATED when the fix is ready for retest."
47183
48024
  };
47184
48025
  }
47185
- if (normalized === "IN_PROGRESS" || normalized === "REMEDIATED") {
47186
- 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;
47187
48032
  }
47188
48033
  return {
47189
- error: `Invalid --status '${sanitizeDisplay(raw)}'. Use IN_PROGRESS or REMEDIATED.`
48034
+ error: `Invalid --status '${sanitizeDisplay(raw)}'. Use ${STATUS_UPDATE_TARGET_LIST}.`
47190
48035
  };
47191
48036
  }
47192
48037
  function isPentestIdentifier(value) {
@@ -47195,6 +48040,17 @@ function isPentestIdentifier(value) {
47195
48040
  function isFindingIdentifier(value) {
47196
48041
  return FINDING_IDENTIFIER_PATTERN.test(value);
47197
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
+ }
47198
48054
  function failStatusUpdate(status, body, viaApiKey) {
47199
48055
  const { message, errorCode } = readErrorFields(body);
47200
48056
  if (status === UNAUTHORIZED_STATUS2) {
@@ -47287,10 +48143,13 @@ async function runStatusUpdate(options) {
47287
48143
  }
47288
48144
  if (note !== void 0 && target === "IN_PROGRESS") {
47289
48145
  console.error(
47290
- 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
+ )
47291
48149
  );
47292
48150
  process.exit(1);
47293
48151
  }
48152
+ const rationale = target === "ACCEPTED_WITH_CONTROLS" ? requireAcceptRationale(note) : null;
47294
48153
  const viaApiKey = requireAuth().kind === "api_key";
47295
48154
  const organizationId = await resolveOrganizationId();
47296
48155
  const params = {
@@ -47303,6 +48162,8 @@ async function runStatusUpdate(options) {
47303
48162
  params,
47304
48163
  body: { status: target, ...note !== void 0 ? { note } : {} }
47305
48164
  })
48165
+ ) : rationale !== null ? await authenticatedRequest(
48166
+ (client) => client.pentestFinding.accept({ params, body: { rationale } })
47306
48167
  ) : target === "IN_PROGRESS" ? await authenticatedRequest(
47307
48168
  (client) => client.pentestFinding.startProgress({ params, body: {} })
47308
48169
  ) : await authenticatedRequest(
@@ -47323,19 +48184,24 @@ async function runStatusUpdate(options) {
47323
48184
  console.log(colorSuccess(`PTF-${displayId} is now ${status}`));
47324
48185
  }
47325
48186
  function createStatusUpdateCommand() {
47326
- 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(
47327
48188
  "--status <status>",
47328
- "IN_PROGRESS (start work) or REMEDIATED (ready for retest)"
47329
- ).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(
47330
48194
  "after",
47331
48195
  `
47332
48196
  Customer-facing status writes \u2014 the same transitions as the dashboard. An agent
47333
48197
  can mark a finding in progress when it starts the fix, then remediated when the
47334
48198
  fix is ready for Trace to re-test. Leaving the finding IN_PROGRESS (and not
47335
- 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.
47336
48202
 
47337
- IN_PROGRESS is allowed from OPEN or VERIFIED_OPEN. REMEDIATED is allowed from
47338
- 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.
47339
48205
 
47340
48206
  A signed-in session (\`tracecli auth login\`) attributes the change to you. A
47341
48207
  Trace API key works too, once Trace enables finding automation for your
@@ -47346,7 +48212,9 @@ Examples:
47346
48212
  tracecli pentest findings status-update --pentest PT-3 --finding 7 --status IN_PROGRESS
47347
48213
  tracecli pentest findings status-update --pentest PT-3 --finding PTF-7 --status REMEDIATED
47348
48214
  tracecli pentest findings status-update --pentest PT-3 --finding 7 --status REMEDIATED \\
47349
- --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"`
47350
48218
  ).action(async (options) => {
47351
48219
  await runStatusUpdate(options);
47352
48220
  });
@@ -48431,7 +49299,7 @@ function createFindingsListCommand() {
48431
49299
  (value) => value.toUpperCase()
48432
49300
  ).option(
48433
49301
  "--status <status>",
48434
- "Filter by status (OPEN, IN_PROGRESS, CONTESTED, REMEDIATED, VERIFIED_FIXED, VERIFIED_OPEN, ACCEPTED_WITH_CONTROLS, DISMISSED)",
49302
+ `Filter by status (${PentestFindingStatusValues.join(", ")})`,
48435
49303
  (value) => value.toUpperCase()
48436
49304
  ).option(
48437
49305
  "-L, --limit <n>",
@@ -48463,7 +49331,9 @@ Full detail, for feeding an agent that fixes the findings:
48463
49331
 
48464
49332
  Then mark work as it happens:
48465
49333
  tracecli pentest findings status-update --pentest PT-3 --finding 7 --status IN_PROGRESS
48466
- 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"`
48467
49337
  ).action(
48468
49338
  async (options) => {
48469
49339
  if (options.detail && options.output !== "json") {
@@ -49948,13 +50818,13 @@ function buildUploadsTable(uploads) {
49948
50818
  size: formatArchiveBytes(upload.sizeBytes),
49949
50819
  id: upload.codeUploadId
49950
50820
  }));
49951
- const nameWidth = Math.max(4, ...cells.map((c62) => c62.name.length));
49952
- const kindWidth = Math.max(4, ...cells.map((c62) => c62.kind.length));
49953
- const statusWidth = Math.max(6, ...cells.map((c62) => c62.status.length));
49954
- 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));
49955
50825
  const header = `${"NAME".padEnd(nameWidth)} ${"KIND".padEnd(kindWidth)} ${"STATUS".padEnd(statusWidth)} ${"SIZE".padEnd(sizeWidth)} ID`;
49956
50826
  const rows = cells.map(
49957
- (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}`
49958
50828
  );
49959
50829
  return { header, rows };
49960
50830
  }
@@ -50312,7 +51182,7 @@ async function runList5(options) {
50312
51182
  const output = parseOutput(options.output);
50313
51183
  if (options.web) {
50314
51184
  const slug = await resolveOrganizationSlug();
50315
- const url2 = `${getAppBaseUrl()}/dashboard/${slug}/settings/integrations/sources`;
51185
+ const url2 = `${getAppBaseUrl()}/dashboard/${slug}/settings/integrations/source-code/upload`;
50316
51186
  const opened = await openBrowser(url2);
50317
51187
  if (!opened) console.log(url2);
50318
51188
  return;