securewithtrace 0.7.1 → 0.9.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 +2 -2
  2. package/dist/index.js +1267 -282
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3410,37 +3410,110 @@ async function pollForToken(clientId, deviceCode, options = {}) {
3410
3410
  }
3411
3411
  throw new Error("Authorization timed out. Please try again.");
3412
3412
  }
3413
+ async function refreshAccessToken(clientId, refreshToken) {
3414
+ const response = await fetch(WORKOS_TOKEN_URL, {
3415
+ method: "POST",
3416
+ headers: {
3417
+ "Content-Type": "application/x-www-form-urlencoded"
3418
+ },
3419
+ body: new URLSearchParams({
3420
+ grant_type: "refresh_token",
3421
+ client_id: clientId,
3422
+ refresh_token: refreshToken
3423
+ })
3424
+ });
3425
+ if (!response.ok) {
3426
+ const text = await response.text();
3427
+ throw new Error(`Failed to refresh token: ${response.status} ${text}`);
3428
+ }
3429
+ return await response.json();
3430
+ }
3413
3431
 
3414
3432
  // src/auth/token.ts
3415
3433
  import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
3416
3434
  import { homedir } from "os";
3417
3435
  import { join } from "path";
3418
- var TRACE_DIR = join(homedir(), ".trace");
3419
- var TOKEN_PATH = join(TRACE_DIR, "token");
3436
+ var ACCESS_TOKEN_FILENAME = "token";
3437
+ var REFRESH_TOKEN_FILENAME = "refresh-token";
3438
+ function resolveTraceDir() {
3439
+ const override = process.env["TRACE_CLI_AUTH_DIR"];
3440
+ if (override && override.trim().length > 0) {
3441
+ return override;
3442
+ }
3443
+ return join(homedir(), ".trace");
3444
+ }
3445
+ function ensureTraceDir() {
3446
+ const traceDir = resolveTraceDir();
3447
+ if (!existsSync(traceDir)) {
3448
+ mkdirSync(traceDir, { recursive: true, mode: 448 });
3449
+ }
3450
+ }
3451
+ function getTokenPath() {
3452
+ return join(resolveTraceDir(), ACCESS_TOKEN_FILENAME);
3453
+ }
3454
+ function getRefreshTokenPath() {
3455
+ return join(resolveTraceDir(), REFRESH_TOKEN_FILENAME);
3456
+ }
3420
3457
  function readToken() {
3458
+ const tokenPath = getTokenPath();
3421
3459
  try {
3422
- if (!existsSync(TOKEN_PATH)) {
3460
+ if (!existsSync(tokenPath)) {
3423
3461
  return null;
3424
3462
  }
3425
- const token = readFileSync(TOKEN_PATH, "utf-8").trim();
3463
+ const token = readFileSync(tokenPath, "utf-8").trim();
3464
+ return token || null;
3465
+ } catch {
3466
+ return null;
3467
+ }
3468
+ }
3469
+ function readRefreshToken() {
3470
+ const refreshTokenPath = getRefreshTokenPath();
3471
+ try {
3472
+ if (!existsSync(refreshTokenPath)) {
3473
+ return null;
3474
+ }
3475
+ const token = readFileSync(refreshTokenPath, "utf-8").trim();
3426
3476
  return token || null;
3427
3477
  } catch {
3428
3478
  return null;
3429
3479
  }
3430
3480
  }
3431
3481
  function writeToken(token) {
3432
- if (!existsSync(TRACE_DIR)) {
3433
- mkdirSync(TRACE_DIR, { recursive: true, mode: 448 });
3482
+ ensureTraceDir();
3483
+ writeFileSync(getTokenPath(), token, { encoding: "utf-8", mode: 384 });
3484
+ }
3485
+ function writeRefreshToken(token) {
3486
+ ensureTraceDir();
3487
+ writeFileSync(getRefreshTokenPath(), token, { encoding: "utf-8", mode: 384 });
3488
+ }
3489
+ function writeTokens(accessToken, refreshToken) {
3490
+ writeToken(accessToken);
3491
+ if (refreshToken && refreshToken.trim().length > 0) {
3492
+ writeRefreshToken(refreshToken);
3493
+ return;
3434
3494
  }
3435
- writeFileSync(TOKEN_PATH, token, { encoding: "utf-8", mode: 384 });
3495
+ removeRefreshToken();
3436
3496
  }
3437
- function removeToken() {
3438
- if (!existsSync(TOKEN_PATH)) {
3497
+ function removeRefreshToken() {
3498
+ const refreshTokenPath = getRefreshTokenPath();
3499
+ if (!existsSync(refreshTokenPath)) {
3439
3500
  return false;
3440
3501
  }
3441
- rmSync(TOKEN_PATH);
3502
+ rmSync(refreshTokenPath);
3442
3503
  return true;
3443
3504
  }
3505
+ function removeToken() {
3506
+ let removed = false;
3507
+ const tokenPath = getTokenPath();
3508
+ if (existsSync(tokenPath)) {
3509
+ rmSync(tokenPath);
3510
+ removed = true;
3511
+ }
3512
+ if (removeRefreshToken()) {
3513
+ removed = true;
3514
+ }
3515
+ return removed;
3516
+ }
3444
3517
 
3445
3518
  // src/auth/commands.ts
3446
3519
  function getClientId() {
@@ -3501,12 +3574,12 @@ function createLoginCommand() {
3501
3574
  expiresIn: auth.expires_in,
3502
3575
  interval: auth.interval
3503
3576
  });
3504
- writeToken(tokenResponse.access_token);
3577
+ writeTokens(tokenResponse.access_token, tokenResponse.refresh_token);
3505
3578
  const name = [tokenResponse.user.first_name, tokenResponse.user.last_name].filter(Boolean).join(" ");
3506
3579
  const displayName = name || tokenResponse.user.email;
3507
3580
  console.log(`
3508
3581
  Authenticated as ${displayName} (${tokenResponse.user.email})`);
3509
- console.log("Token saved to ~/.trace/token");
3582
+ console.log("Tokens saved to ~/.trace");
3510
3583
  });
3511
3584
  }
3512
3585
  function createLogoutCommand() {
@@ -3522,6 +3595,7 @@ function createLogoutCommand() {
3522
3595
  function createStatusCommand() {
3523
3596
  return new Command("status").description("Show current authentication status").action(() => {
3524
3597
  const token = readToken();
3598
+ const refreshToken = readRefreshToken();
3525
3599
  if (token) {
3526
3600
  try {
3527
3601
  const parts = token.split(".");
@@ -3540,16 +3614,31 @@ function createStatusCommand() {
3540
3614
  if (expiry) {
3541
3615
  console.log(` Expires: ${expiry.toISOString()}${isExpired ? " (EXPIRED)" : ""}`);
3542
3616
  }
3617
+ console.log(
3618
+ ` Refresh: ${refreshToken ? "Available (auto-refresh enabled)" : "Not available"}`
3619
+ );
3543
3620
  if (isExpired) {
3544
- console.log(
3545
- "\nYour token has expired. Run `trace auth login` after logging out to re-authenticate."
3546
- );
3621
+ if (refreshToken) {
3622
+ console.log(
3623
+ "\nYour access token is expired, but a refresh token is available and will be used automatically."
3624
+ );
3625
+ } else {
3626
+ console.log(
3627
+ "\nYour token has expired. Run `trace auth login` after logging out to re-authenticate."
3628
+ );
3629
+ }
3547
3630
  }
3548
3631
  } else {
3549
- console.log("Logged in to Trace (token stored at ~/.trace/token)");
3632
+ console.log("Logged in to Trace (access token stored at ~/.trace/token)");
3633
+ console.log(
3634
+ ` Refresh: ${refreshToken ? "Available (auto-refresh enabled)" : "Not available"}`
3635
+ );
3550
3636
  }
3551
3637
  } catch {
3552
- console.log("Logged in to Trace (token stored at ~/.trace/token)");
3638
+ console.log("Logged in to Trace (access token stored at ~/.trace/token)");
3639
+ console.log(
3640
+ ` Refresh: ${refreshToken ? "Available (auto-refresh enabled)" : "Not available"}`
3641
+ );
3553
3642
  }
3554
3643
  } else {
3555
3644
  console.log("Not logged in. Run `trace auth login` to authenticate.");
@@ -3593,7 +3682,7 @@ function extractCommandTree(cmd) {
3593
3682
  description: o.description,
3594
3683
  takesValue: o.required || o.optional
3595
3684
  }));
3596
- const subcommands = cmd.commands.filter((c21) => !c21._hidden).map((c21) => extractCommandTree(c21));
3685
+ const subcommands = cmd.commands.filter((c24) => !c24._hidden).map((c24) => extractCommandTree(c24));
3597
3686
  return {
3598
3687
  name: cmd.name(),
3599
3688
  description: cmd.description(),
@@ -3659,7 +3748,7 @@ function generateBashCompletion(tree, binName) {
3659
3748
  }
3660
3749
  function collectBashCases(tree, prefix) {
3661
3750
  const cases = /* @__PURE__ */ new Map();
3662
- const subcommandNames = tree.subcommands.map((c21) => c21.name);
3751
+ const subcommandNames = tree.subcommands.map((c24) => c24.name);
3663
3752
  const optionNames = tree.options.flatMap((o) => o.short ? [o.long, o.short] : [o.long]);
3664
3753
  const extraOptions = prefix === "" ? ["--help", "--version"] : ["--help"];
3665
3754
  const allOptions = [.../* @__PURE__ */ new Set([...optionNames, ...extraOptions])];
@@ -3848,7 +3937,7 @@ function generateCompletion(program3, shell, binName) {
3848
3937
  import { existsSync as existsSync2, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
3849
3938
  import { homedir as homedir2 } from "os";
3850
3939
  import { join as join2 } from "path";
3851
- var TRACE_DIR2 = ".trace";
3940
+ var TRACE_DIR = ".trace";
3852
3941
  function completionFileName(shell) {
3853
3942
  switch (shell) {
3854
3943
  case "bash":
@@ -3860,7 +3949,7 @@ function completionFileName(shell) {
3860
3949
  }
3861
3950
  }
3862
3951
  function getTraceDir() {
3863
- return join2(homedir2(), TRACE_DIR2);
3952
+ return join2(homedir2(), TRACE_DIR);
3864
3953
  }
3865
3954
  function getCompletionFilePath(shell) {
3866
3955
  return join2(getTraceDir(), completionFileName(shell));
@@ -3875,7 +3964,7 @@ function writeCompletionFile(shell, script) {
3875
3964
  return filePath;
3876
3965
  }
3877
3966
  function getSetupInstructions(shell) {
3878
- const traceDir = `~/${TRACE_DIR2}`;
3967
+ const traceDir = `~/${TRACE_DIR}`;
3879
3968
  switch (shell) {
3880
3969
  case "bash":
3881
3970
  return [
@@ -3946,11 +4035,6 @@ function createCompletionCommand(program3) {
3946
4035
  });
3947
4036
  }
3948
4037
 
3949
- // src/repo/commands.ts
3950
- import { chmodSync, mkdtempSync, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
3951
- import { tmpdir } from "os";
3952
- import { join as join3 } from "path";
3953
-
3954
4038
  // ../../node_modules/.bun/@ts-rest+core@3.53.0-rc.1+f9199aabcde8d6a0/node_modules/@ts-rest/core/index.esm.mjs
3955
4039
  var util;
3956
4040
  (function(util2) {
@@ -10719,7 +10803,7 @@ var $ZodBase64 = /* @__PURE__ */ $constructor("$ZodBase64", (inst, def) => {
10719
10803
  function isValidBase64URL(data) {
10720
10804
  if (!base64url.test(data))
10721
10805
  return false;
10722
- const base643 = data.replace(/[-_]/g, (c21) => c21 === "-" ? "+" : "/");
10806
+ const base643 = data.replace(/[-_]/g, (c24) => c24 === "-" ? "+" : "/");
10723
10807
  const padded = base643.padEnd(Math.ceil(base643.length / 4) * 4, "=");
10724
10808
  return isValidBase64(padded);
10725
10809
  }
@@ -20763,9 +20847,9 @@ var ZodDate2 = /* @__PURE__ */ $constructor("ZodDate", (inst, def) => {
20763
20847
  inst._zod.processJSONSchema = (ctx, json2, params) => dateProcessor(inst, ctx, json2, params);
20764
20848
  inst.min = (value, params) => inst.check(_gte(value, params));
20765
20849
  inst.max = (value, params) => inst.check(_lte(value, params));
20766
- const c21 = inst._zod.bag;
20767
- inst.minDate = c21.minimum ? new Date(c21.minimum) : null;
20768
- inst.maxDate = c21.maximum ? new Date(c21.maximum) : null;
20850
+ const c24 = inst._zod.bag;
20851
+ inst.minDate = c24.minimum ? new Date(c24.minimum) : null;
20852
+ inst.maxDate = c24.maximum ? new Date(c24.maximum) : null;
20769
20853
  });
20770
20854
  function date3(params) {
20771
20855
  return _date(ZodDate2, params);
@@ -22887,19 +22971,51 @@ var llmProviderKeyContract = c7.router({
22887
22971
  });
22888
22972
 
22889
22973
  // ../../packages/api-contracts/src/schemas/api/v1/organization.api.ts
22974
+ var OrgCapabilityValues = [
22975
+ "PENTEST",
22976
+ "SCAN_SAST",
22977
+ "SCAN_SCA",
22978
+ "SCAN_SECRETS",
22979
+ "SCAN_DAST",
22980
+ "AUTO_PR_SCANS",
22981
+ "AUTO_PUSH_SCANS"
22982
+ ];
22890
22983
  var UpdateOrganizationRequestSchema = external_exports.object({
22891
22984
  name: external_exports.string().min(1).max(255).optional(),
22892
- logoUrl: external_exports.string().url().max(2048).nullish()
22985
+ logoUrl: external_exports.string().url().max(2048).nullish(),
22986
+ logoS3Key: external_exports.string().max(1024).nullish(),
22987
+ darkModeLogoUrl: external_exports.string().url().max(2048).nullish(),
22988
+ darkModeLogoS3Key: external_exports.string().max(1024).nullish()
22989
+ });
22990
+ var LogoUploadRequestSchema = external_exports.object({
22991
+ variant: external_exports.enum(["light", "dark"]),
22992
+ contentType: external_exports.enum(["image/png", "image/jpeg", "image/gif", "image/svg+xml", "image/webp"]),
22993
+ fileName: external_exports.string().min(1).max(255)
22994
+ });
22995
+ var LogoUploadResponseSchema = external_exports.object({
22996
+ uploadUrl: external_exports.string(),
22997
+ s3Key: external_exports.string()
22998
+ });
22999
+ var PatchCapabilitiesRequestSchema = external_exports.object({
23000
+ capabilities: external_exports.array(external_exports.enum(OrgCapabilityValues)).min(1)
23001
+ });
23002
+ var PatchCapabilitiesResponseSchema = external_exports.object({
23003
+ capabilities: external_exports.array(external_exports.enum(OrgCapabilityValues))
22893
23004
  });
22894
23005
  var OrganizationResponseSchema = external_exports.object({
22895
23006
  organizationId: external_exports.uuid(),
22896
23007
  name: external_exports.string(),
22897
23008
  slug: external_exports.string(),
22898
23009
  logoUrl: external_exports.string().nullable(),
23010
+ darkModeLogoUrl: external_exports.string().nullable(),
23011
+ capabilities: external_exports.array(external_exports.enum(OrgCapabilityValues)),
22899
23012
  createdAt: external_exports.date(),
22900
23013
  updatedAt: external_exports.date()
22901
23014
  });
22902
23015
  var ListOrganizationsResponseSchema = external_exports.array(OrganizationResponseSchema);
23016
+ var LogoDeleteRequestSchema = external_exports.object({
23017
+ variant: external_exports.enum(["light", "dark"])
23018
+ });
22903
23019
 
22904
23020
  // ../../packages/api-contracts/src/contracts/v1/organization.ts
22905
23021
  var c8 = initContract();
@@ -22951,103 +23067,167 @@ var organizationContract = c8.router({
22951
23067
  404: ErrorResponseSchema,
22952
23068
  500: ErrorResponseSchema
22953
23069
  }
23070
+ },
23071
+ patchCapabilities: {
23072
+ method: "PATCH",
23073
+ path: "/organizations/:organizationId/capabilities",
23074
+ pathParams: OrgIdParamsSchema,
23075
+ body: PatchCapabilitiesRequestSchema,
23076
+ responses: {
23077
+ 200: PatchCapabilitiesResponseSchema,
23078
+ 401: ErrorResponseSchema,
23079
+ 403: ErrorResponseSchema,
23080
+ 404: ErrorResponseSchema,
23081
+ 500: ErrorResponseSchema
23082
+ }
23083
+ },
23084
+ generateLogoUploadUrl: {
23085
+ method: "POST",
23086
+ path: "/organizations/:organizationId/logo-upload-url",
23087
+ pathParams: OrgIdParamsSchema,
23088
+ body: LogoUploadRequestSchema,
23089
+ responses: {
23090
+ 200: LogoUploadResponseSchema,
23091
+ 401: ErrorResponseSchema,
23092
+ 403: ErrorResponseSchema,
23093
+ 404: ErrorResponseSchema,
23094
+ 500: ErrorResponseSchema
23095
+ }
22954
23096
  }
22955
23097
  });
22956
23098
 
22957
- // ../../packages/api-contracts/src/schemas/api/v1/repository.api.ts
22958
- var PlatformValues = ["GITHUB", "GITLAB", "BITBUCKET"];
22959
- var RepositoryStatusValues = ["CONNECTED", "DISCONNECTED"];
22960
- var RepositoryIdParamsSchema = OrgIdParamsSchema.extend({
22961
- repositoryId: external_exports.uuid()
22962
- });
22963
- var CreateRepositoryRequestSchema = external_exports.object({
22964
- repositoryUrl: external_exports.url(),
22965
- platform: external_exports.enum(PlatformValues),
22966
- defaultBranch: external_exports.string().min(1).max(255).optional(),
22967
- status: external_exports.enum(RepositoryStatusValues).optional()
22968
- });
22969
- var UpdateRepositoryRequestSchema = external_exports.object({
22970
- repositoryUrl: external_exports.url().optional(),
22971
- platform: external_exports.enum(PlatformValues).optional(),
22972
- defaultBranch: external_exports.string().min(1).max(255).optional(),
22973
- status: external_exports.enum(RepositoryStatusValues).optional()
23099
+ // ../../packages/api-contracts/src/schemas/domain/pentest.schema.ts
23100
+ var PentestStatusValues = ["SCOPING", "IN_PROGRESS", "REMEDIATION", "CLOSED"];
23101
+ var PentestStatus = external_exports.enum(PentestStatusValues);
23102
+ var PentestFindingStatusValues = [
23103
+ "OPEN",
23104
+ "CONTESTED",
23105
+ "REMEDIATED",
23106
+ "VERIFIED_FIXED",
23107
+ "VERIFIED_OPEN"
23108
+ ];
23109
+ var PentestFindingStatus = external_exports.enum(PentestFindingStatusValues);
23110
+ var PentestFindingSeverityValues = [
23111
+ "INFORMATIONAL",
23112
+ "LOW",
23113
+ "MEDIUM",
23114
+ "HIGH",
23115
+ "CRITICAL"
23116
+ ];
23117
+ var PentestFindingSeverity = external_exports.enum(PentestFindingSeverityValues);
23118
+ var ContestReasonValues = [
23119
+ "FALSE_POSITIVE",
23120
+ "ACCEPTED_RISK",
23121
+ "MITIGATING_CONTROLS",
23122
+ "OUT_OF_SCOPE",
23123
+ "DUPLICATE",
23124
+ "OTHER"
23125
+ ];
23126
+ var ContestReason = external_exports.enum(ContestReasonValues);
23127
+ var RetestOutcomeValues = ["FIXED", "PARTIALLY_FIXED", "NOT_FIXED"];
23128
+ var RetestOutcome = external_exports.enum(RetestOutcomeValues);
23129
+
23130
+ // ../../packages/api-contracts/src/schemas/api/v1/pentest.api.ts
23131
+ var PentestIdParamsSchema = OrgIdParamsSchema.extend({
23132
+ pentestId: external_exports.uuid()
22974
23133
  });
22975
- var RepositoryResponseSchema = external_exports.object({
22976
- repositoryId: external_exports.uuid(),
23134
+ var PentestResponseSchema = external_exports.object({
23135
+ pentestId: external_exports.uuid(),
22977
23136
  organizationId: external_exports.uuid(),
22978
- repositoryUrl: external_exports.url(),
22979
- platform: external_exports.enum(PlatformValues),
22980
- status: external_exports.enum(RepositoryStatusValues),
22981
- defaultBranch: external_exports.string(),
22982
- createdAt: external_exports.date(),
22983
- updatedAt: external_exports.date()
22984
- });
22985
- var ListRepositoriesResponseSchema = external_exports.array(RepositoryResponseSchema);
22986
- var CloneTokenRequestSchema = external_exports.object({
22987
- repositoryUrl: external_exports.string().url()
23137
+ displayId: external_exports.number(),
23138
+ title: external_exports.string(),
23139
+ description: external_exports.string().nullable(),
23140
+ status: PentestStatus,
23141
+ scope: external_exports.string().nullable(),
23142
+ startedAt: external_exports.coerce.date().nullable(),
23143
+ endedAt: external_exports.coerce.date().nullable(),
23144
+ createdById: external_exports.uuid(),
23145
+ createdByName: external_exports.string(),
23146
+ createdAt: external_exports.coerce.date(),
23147
+ updatedAt: external_exports.coerce.date(),
23148
+ findingCounts: external_exports.object({
23149
+ total: external_exports.number(),
23150
+ bySeverity: external_exports.record(PentestFindingSeverity, external_exports.number()),
23151
+ byStatus: external_exports.record(PentestFindingStatus, external_exports.number())
23152
+ })
22988
23153
  });
22989
- var CloneTokenResponseSchema = external_exports.object({
22990
- token: external_exports.string(),
22991
- expiresAt: external_exports.string().datetime()
23154
+ var ListPentestsResponseSchema = external_exports.array(PentestResponseSchema);
23155
+ var CreatePentestRequestSchema = external_exports.object({
23156
+ title: external_exports.string().min(1).max(500),
23157
+ description: external_exports.string().max(1e4).optional(),
23158
+ scope: external_exports.string().max(5e4).optional(),
23159
+ status: PentestStatus.optional(),
23160
+ startedAt: external_exports.coerce.date().optional(),
23161
+ endedAt: external_exports.coerce.date().optional()
23162
+ });
23163
+ var UpdatePentestRequestSchema = external_exports.object({
23164
+ title: external_exports.string().min(1).max(500).optional(),
23165
+ description: external_exports.string().max(1e4).nullable().optional(),
23166
+ status: PentestStatus.optional(),
23167
+ scope: external_exports.string().max(5e4).nullable().optional(),
23168
+ startedAt: external_exports.coerce.date().nullable().optional(),
23169
+ endedAt: external_exports.coerce.date().nullable().optional()
22992
23170
  });
22993
23171
 
22994
- // ../../packages/api-contracts/src/contracts/v1/repository.ts
23172
+ // ../../packages/api-contracts/src/contracts/v1/pentest.ts
22995
23173
  var c9 = initContract();
22996
- var repositoryContract = c9.router({
22997
- createRepository: {
22998
- method: "POST",
22999
- path: "/organizations/:organizationId/repositories",
23174
+ var pentestContract = c9.router({
23175
+ listPentests: {
23176
+ method: "GET",
23177
+ path: "/organizations/:organizationId/pentests",
23000
23178
  pathParams: OrgIdParamsSchema,
23001
- body: CreateRepositoryRequestSchema,
23002
23179
  responses: {
23003
- 201: RepositoryResponseSchema,
23180
+ 200: ListPentestsResponseSchema,
23004
23181
  401: ErrorResponseSchema,
23005
23182
  403: ErrorResponseSchema,
23006
23183
  404: ErrorResponseSchema,
23007
23184
  500: ErrorResponseSchema
23008
23185
  }
23009
23186
  },
23010
- listRepositories: {
23011
- method: "GET",
23012
- path: "/organizations/:organizationId/repositories",
23187
+ createPentest: {
23188
+ method: "POST",
23189
+ path: "/organizations/:organizationId/pentests",
23013
23190
  pathParams: OrgIdParamsSchema,
23191
+ body: CreatePentestRequestSchema,
23014
23192
  responses: {
23015
- 200: ListRepositoriesResponseSchema,
23193
+ 201: PentestResponseSchema,
23194
+ 400: ErrorResponseSchema,
23016
23195
  401: ErrorResponseSchema,
23017
23196
  403: ErrorResponseSchema,
23018
23197
  404: ErrorResponseSchema,
23019
23198
  500: ErrorResponseSchema
23020
23199
  }
23021
23200
  },
23022
- getRepository: {
23201
+ getPentest: {
23023
23202
  method: "GET",
23024
- path: "/organizations/:organizationId/repositories/:repositoryId",
23025
- pathParams: RepositoryIdParamsSchema,
23203
+ path: "/organizations/:organizationId/pentests/:pentestId",
23204
+ pathParams: PentestIdParamsSchema,
23026
23205
  responses: {
23027
- 200: RepositoryResponseSchema,
23206
+ 200: PentestResponseSchema,
23028
23207
  401: ErrorResponseSchema,
23029
23208
  403: ErrorResponseSchema,
23030
23209
  404: ErrorResponseSchema,
23031
23210
  500: ErrorResponseSchema
23032
23211
  }
23033
23212
  },
23034
- updateRepository: {
23035
- method: "PUT",
23036
- path: "/organizations/:organizationId/repositories/:repositoryId",
23037
- pathParams: RepositoryIdParamsSchema,
23038
- body: UpdateRepositoryRequestSchema,
23213
+ updatePentest: {
23214
+ method: "PATCH",
23215
+ path: "/organizations/:organizationId/pentests/:pentestId",
23216
+ pathParams: PentestIdParamsSchema,
23217
+ body: UpdatePentestRequestSchema,
23039
23218
  responses: {
23040
- 200: RepositoryResponseSchema,
23219
+ 200: PentestResponseSchema,
23220
+ 400: ErrorResponseSchema,
23041
23221
  401: ErrorResponseSchema,
23042
23222
  403: ErrorResponseSchema,
23043
23223
  404: ErrorResponseSchema,
23044
23224
  500: ErrorResponseSchema
23045
23225
  }
23046
23226
  },
23047
- deleteRepository: {
23227
+ deletePentest: {
23048
23228
  method: "DELETE",
23049
- path: "/organizations/:organizationId/repositories/:repositoryId",
23050
- pathParams: RepositoryIdParamsSchema,
23229
+ path: "/organizations/:organizationId/pentests/:pentestId",
23230
+ pathParams: PentestIdParamsSchema,
23051
23231
  responses: {
23052
23232
  204: DeleteResponseSchema,
23053
23233
  401: ErrorResponseSchema,
@@ -23055,135 +23235,612 @@ var repositoryContract = c9.router({
23055
23235
  404: ErrorResponseSchema,
23056
23236
  500: ErrorResponseSchema
23057
23237
  }
23058
- },
23059
- getCloneToken: {
23060
- method: "POST",
23061
- path: "/organizations/:organizationId/repositories/clone-token",
23062
- pathParams: OrgIdParamsSchema,
23063
- body: CloneTokenRequestSchema,
23064
- responses: {
23065
- 200: CloneTokenResponseSchema,
23066
- 401: ErrorResponseSchema,
23067
- 403: ErrorResponseSchema,
23068
- 404: ErrorResponseSchema,
23069
- 500: ErrorResponseSchema
23070
- }
23071
23238
  }
23072
23239
  });
23073
23240
 
23074
- // ../../packages/api-contracts/src/schemas/domain/scan.schema.ts
23075
- var ScanStatusValues = [
23076
- "PENDING",
23077
- "QUEUED",
23078
- "RUNNING",
23079
- "COMPLETED",
23080
- "FAILED",
23081
- "CANCELLED"
23082
- ];
23083
- var ScanStatus = external_exports.enum(ScanStatusValues);
23084
- var ScanModeValues = ["DAST", "SAST", "SCA", "SECRETS"];
23085
- var ScanMode = external_exports.enum(ScanModeValues);
23086
- var ScanTypeValues = ["FULL", "INCREMENTAL", "RETEST"];
23087
- var ScanType = external_exports.enum(ScanTypeValues);
23088
- var CancellationReasonValues = ["USER_ABORTED", "SUPERSEDED"];
23089
- var CancellationReason = external_exports.enum(CancellationReasonValues);
23090
- var ScanTriggerTypeValues = [
23091
- "MANUAL",
23092
- "PUSH",
23093
- "PULL_REQUEST",
23094
- "RETEST",
23095
- "SCHEDULED"
23096
- ];
23097
- var ScanTriggerType = external_exports.enum(ScanTriggerTypeValues);
23098
-
23099
- // ../../packages/api-contracts/src/schemas/api/v1/scan.api.ts
23100
- var ScanIdParamsSchema = OrgIdParamsSchema.extend({
23101
- scanId: external_exports.uuid()
23102
- });
23103
- var CreateScanRequestSchema = external_exports.discriminatedUnion("scanMode", [
23104
- external_exports.object({
23105
- scanMode: external_exports.literal("DAST"),
23106
- webApplicationId: external_exports.uuid(),
23107
- targetUrl: external_exports.url(),
23108
- userProvidedContext: external_exports.string().optional(),
23109
- scanConfiguration: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
23110
- }),
23111
- external_exports.object({
23112
- scanMode: external_exports.literal("SAST"),
23113
- repositoryId: external_exports.uuid(),
23114
- branch: external_exports.string().optional(),
23115
- scanType: external_exports.enum(["FULL", "INCREMENTAL"]).optional(),
23116
- userProvidedContext: external_exports.string().optional(),
23117
- scanConfiguration: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
23118
- }),
23119
- external_exports.object({
23120
- scanMode: external_exports.literal("SCA"),
23121
- repositoryId: external_exports.uuid(),
23122
- branch: external_exports.string().optional(),
23123
- scanType: external_exports.enum(["FULL", "INCREMENTAL"]).optional(),
23124
- userProvidedContext: external_exports.string().optional(),
23125
- scanConfiguration: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
23126
- }),
23127
- external_exports.object({
23128
- scanMode: external_exports.literal("SECRETS"),
23129
- repositoryId: external_exports.uuid(),
23130
- branch: external_exports.string().optional(),
23131
- scanType: external_exports.enum(["FULL", "INCREMENTAL"]).optional(),
23132
- userProvidedContext: external_exports.string().optional(),
23133
- scanConfiguration: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
23134
- })
23135
- ]);
23136
- var ScanResponseSchema = external_exports.object({
23137
- scanId: external_exports.uuid(),
23138
- organizationId: external_exports.uuid(),
23139
- initiatedById: external_exports.uuid(),
23140
- initiatedByName: external_exports.string().nullable(),
23141
- initiatedByProfilePictureUrl: external_exports.string().nullable(),
23142
- scanMode: ScanMode,
23143
- scanType: external_exports.enum(ScanTypeValues),
23144
- webApplicationId: external_exports.uuid().nullable(),
23145
- targetUrl: external_exports.string().nullable(),
23146
- repositoryId: external_exports.uuid().nullable(),
23147
- branch: external_exports.string().nullable(),
23148
- status: external_exports.enum(ScanStatusValues),
23149
- cancellationReason: external_exports.enum(CancellationReasonValues).nullable(),
23150
- errorMessage: external_exports.string().nullable(),
23151
- userProvidedContext: external_exports.string().nullable(),
23152
- scanConfiguration: external_exports.record(external_exports.string(), external_exports.unknown()).nullable(),
23153
- triggerType: external_exports.enum(ScanTriggerTypeValues).nullable(),
23154
- triggerMetadata: external_exports.record(external_exports.string(), external_exports.unknown()).nullable(),
23155
- startedAt: external_exports.date().nullable(),
23156
- completedAt: external_exports.date().nullable(),
23157
- createdAt: external_exports.date(),
23158
- updatedAt: external_exports.date()
23241
+ // ../../packages/api-contracts/src/schemas/api/v1/pentest-finding.api.ts
23242
+ var PentestFindingParamsSchema = OrgIdParamsSchema.extend({
23243
+ pentestId: external_exports.uuid()
23159
23244
  });
23160
- var ListScansQuerySchema = external_exports.object({
23161
- status: external_exports.enum(ScanStatusValues).array().or(external_exports.enum(ScanStatusValues)).optional()
23245
+ var PentestFindingIdParamsSchema = PentestFindingParamsSchema.extend({
23246
+ pentestFindingId: external_exports.uuid()
23162
23247
  });
23163
- var ListScansResponseSchema = external_exports.array(ScanResponseSchema);
23164
- var CancelScanResponseSchema = external_exports.object({
23165
- scanId: external_exports.uuid(),
23166
- status: external_exports.literal("CANCELLED")
23248
+ var PentestFindingContestIdParamsSchema = PentestFindingIdParamsSchema.extend({
23249
+ contestId: external_exports.uuid()
23167
23250
  });
23168
-
23169
- // ../../packages/api-contracts/src/schemas/api/v1/scan-log.api.ts
23170
- var ScanLogQuerySchema = external_exports.object({
23171
- offset: external_exports.coerce.number().int().min(0).optional()
23251
+ var PentestFindingRetestIdParamsSchema = PentestFindingIdParamsSchema.extend({
23252
+ retestId: external_exports.uuid()
23172
23253
  });
23173
- var ScanLogEntrySchema = external_exports.object({
23174
- timestamp: external_exports.string(),
23175
- level: external_exports.enum(["INFO", "WARN", "ERROR"]),
23176
- message: external_exports.string(),
23177
- phase: external_exports.string().nullable()
23254
+ var PentestFindingNoteIdParamsSchema = PentestFindingIdParamsSchema.extend({
23255
+ noteId: external_exports.uuid()
23178
23256
  });
23179
- var ListScanLogsResponseSchema = external_exports.object({
23180
- logs: external_exports.array(ScanLogEntrySchema),
23181
- nextOffset: external_exports.number()
23257
+ var PentestFindingRepositorySchema = external_exports.object({
23258
+ repositoryId: external_exports.uuid(),
23259
+ repositoryName: external_exports.string(),
23260
+ commitSha: external_exports.string().nullable(),
23261
+ filePath: external_exports.string().nullable(),
23262
+ startLine: external_exports.number().nullable(),
23263
+ endLine: external_exports.number().nullable()
23182
23264
  });
23183
-
23265
+ var PentestFindingResponseSchema = external_exports.object({
23266
+ pentestFindingId: external_exports.uuid(),
23267
+ organizationId: external_exports.uuid(),
23268
+ pentestId: external_exports.uuid(),
23269
+ displayId: external_exports.number(),
23270
+ title: external_exports.string(),
23271
+ description: external_exports.string(),
23272
+ severity: PentestFindingSeverity,
23273
+ category: external_exports.string(),
23274
+ status: PentestFindingStatus,
23275
+ cweIds: external_exports.array(external_exports.string()),
23276
+ cvssVector: external_exports.string().nullable(),
23277
+ cvssScore: external_exports.number().nullable(),
23278
+ owaspCategory: external_exports.string().nullable(),
23279
+ publishedAt: external_exports.coerce.date().nullable(),
23280
+ createdById: external_exports.uuid(),
23281
+ createdByName: external_exports.string(),
23282
+ createdAt: external_exports.coerce.date(),
23283
+ updatedAt: external_exports.coerce.date(),
23284
+ repositories: external_exports.array(PentestFindingRepositorySchema)
23285
+ });
23286
+ var ListPentestFindingsResponseSchema = external_exports.array(PentestFindingResponseSchema);
23287
+ var CreatePentestFindingRequestSchema = external_exports.object({
23288
+ title: external_exports.string().min(1).max(500),
23289
+ description: external_exports.string().min(1).max(5e4),
23290
+ severity: PentestFindingSeverity,
23291
+ category: external_exports.string().min(1).max(200),
23292
+ status: PentestFindingStatus.optional(),
23293
+ cweIds: external_exports.array(external_exports.string()).optional(),
23294
+ cvssVector: external_exports.string().max(200).optional(),
23295
+ cvssScore: external_exports.number().min(0).max(10).optional(),
23296
+ owaspCategory: external_exports.string().max(200).optional(),
23297
+ repositories: external_exports.array(
23298
+ external_exports.object({
23299
+ repositoryId: external_exports.uuid(),
23300
+ commitSha: external_exports.string().optional(),
23301
+ filePath: external_exports.string().optional(),
23302
+ startLine: external_exports.number().int().optional(),
23303
+ endLine: external_exports.number().int().optional()
23304
+ })
23305
+ ).optional()
23306
+ });
23307
+ var UpdatePentestFindingRequestSchema = external_exports.object({
23308
+ title: external_exports.string().min(1).max(500).optional(),
23309
+ description: external_exports.string().min(1).max(5e4).optional(),
23310
+ severity: PentestFindingSeverity.optional(),
23311
+ category: external_exports.string().min(1).max(200).optional(),
23312
+ status: PentestFindingStatus.optional(),
23313
+ cweIds: external_exports.array(external_exports.string()).optional(),
23314
+ cvssVector: external_exports.string().max(200).nullable().optional(),
23315
+ cvssScore: external_exports.number().min(0).max(10).nullable().optional(),
23316
+ owaspCategory: external_exports.string().max(200).nullable().optional(),
23317
+ publishedAt: external_exports.coerce.date().nullable().optional(),
23318
+ repositories: external_exports.array(
23319
+ external_exports.object({
23320
+ repositoryId: external_exports.uuid(),
23321
+ commitSha: external_exports.string().optional(),
23322
+ filePath: external_exports.string().optional(),
23323
+ startLine: external_exports.number().int().optional(),
23324
+ endLine: external_exports.number().int().optional()
23325
+ })
23326
+ ).optional()
23327
+ });
23328
+ var PentestFindingContestResponseSchema = external_exports.object({
23329
+ contestId: external_exports.uuid(),
23330
+ pentestFindingId: external_exports.uuid(),
23331
+ organizationId: external_exports.uuid(),
23332
+ reason: ContestReason,
23333
+ justification: external_exports.string(),
23334
+ contestedById: external_exports.uuid(),
23335
+ contestedByName: external_exports.string(),
23336
+ contestedAt: external_exports.coerce.date(),
23337
+ resolution: external_exports.string().nullable(),
23338
+ resolvedById: external_exports.uuid().nullable(),
23339
+ resolvedByName: external_exports.string().nullable(),
23340
+ resolvedAt: external_exports.coerce.date().nullable()
23341
+ });
23342
+ var ListPentestFindingContestsResponseSchema = external_exports.array(
23343
+ PentestFindingContestResponseSchema
23344
+ );
23345
+ var CreatePentestFindingContestRequestSchema = external_exports.object({
23346
+ reason: ContestReason,
23347
+ justification: external_exports.string().min(1).max(1e4)
23348
+ });
23349
+ var ResolvePentestFindingContestRequestSchema = external_exports.object({
23350
+ resolution: external_exports.string().min(1).max(1e4)
23351
+ });
23352
+ var PentestFindingRetestResponseSchema = external_exports.object({
23353
+ retestId: external_exports.uuid(),
23354
+ pentestFindingId: external_exports.uuid(),
23355
+ organizationId: external_exports.uuid(),
23356
+ outcome: RetestOutcome,
23357
+ notes: external_exports.string().nullable(),
23358
+ testedById: external_exports.uuid(),
23359
+ testedByName: external_exports.string(),
23360
+ testedAt: external_exports.coerce.date()
23361
+ });
23362
+ var ListPentestFindingRetestsResponseSchema = external_exports.array(PentestFindingRetestResponseSchema);
23363
+ var CreatePentestFindingRetestRequestSchema = external_exports.object({
23364
+ outcome: RetestOutcome,
23365
+ notes: external_exports.string().max(1e4).optional()
23366
+ });
23367
+ var PentestFindingNoteResponseSchema = external_exports.object({
23368
+ noteId: external_exports.uuid(),
23369
+ pentestFindingId: external_exports.uuid(),
23370
+ organizationId: external_exports.uuid(),
23371
+ authorId: external_exports.uuid(),
23372
+ authorName: external_exports.string(),
23373
+ content: external_exports.string(),
23374
+ createdAt: external_exports.coerce.date(),
23375
+ updatedAt: external_exports.coerce.date()
23376
+ });
23377
+ var ListPentestFindingNotesResponseSchema = external_exports.array(PentestFindingNoteResponseSchema);
23378
+ var CreatePentestFindingNoteRequestSchema = external_exports.object({
23379
+ content: external_exports.string().min(1).max(1e4)
23380
+ });
23381
+ var UpdatePentestFindingNoteRequestSchema = external_exports.object({
23382
+ content: external_exports.string().min(1).max(1e4)
23383
+ });
23384
+ var ParseFindingMarkdownRequestSchema = external_exports.object({
23385
+ markdown: external_exports.string().min(1).max(1e5)
23386
+ });
23387
+ var ParseFindingMarkdownResponseSchema = external_exports.object({
23388
+ title: external_exports.string(),
23389
+ description: external_exports.string(),
23390
+ severity: PentestFindingSeverity,
23391
+ category: external_exports.string(),
23392
+ status: PentestFindingStatus,
23393
+ cweIds: external_exports.array(external_exports.string()),
23394
+ cvssVector: external_exports.string().nullable(),
23395
+ cvssScore: external_exports.number().nullable(),
23396
+ owaspCategory: external_exports.string().nullable()
23397
+ });
23398
+
23399
+ // ../../packages/api-contracts/src/contracts/v1/pentest-finding.ts
23400
+ var c10 = initContract();
23401
+ var pentestFindingContract = c10.router({
23402
+ // ─── Findings ───
23403
+ listFindings: {
23404
+ method: "GET",
23405
+ path: "/organizations/:organizationId/pentests/:pentestId/findings",
23406
+ pathParams: PentestFindingParamsSchema,
23407
+ responses: {
23408
+ 200: ListPentestFindingsResponseSchema,
23409
+ 401: ErrorResponseSchema,
23410
+ 403: ErrorResponseSchema,
23411
+ 404: ErrorResponseSchema,
23412
+ 500: ErrorResponseSchema
23413
+ }
23414
+ },
23415
+ createFinding: {
23416
+ method: "POST",
23417
+ path: "/organizations/:organizationId/pentests/:pentestId/findings",
23418
+ pathParams: PentestFindingParamsSchema,
23419
+ body: CreatePentestFindingRequestSchema,
23420
+ responses: {
23421
+ 201: PentestFindingResponseSchema,
23422
+ 400: ErrorResponseSchema,
23423
+ 401: ErrorResponseSchema,
23424
+ 403: ErrorResponseSchema,
23425
+ 404: ErrorResponseSchema,
23426
+ 500: ErrorResponseSchema
23427
+ }
23428
+ },
23429
+ getFinding: {
23430
+ method: "GET",
23431
+ path: "/organizations/:organizationId/pentests/:pentestId/findings/:pentestFindingId",
23432
+ pathParams: PentestFindingIdParamsSchema,
23433
+ responses: {
23434
+ 200: PentestFindingResponseSchema,
23435
+ 401: ErrorResponseSchema,
23436
+ 403: ErrorResponseSchema,
23437
+ 404: ErrorResponseSchema,
23438
+ 500: ErrorResponseSchema
23439
+ }
23440
+ },
23441
+ updateFinding: {
23442
+ method: "PATCH",
23443
+ path: "/organizations/:organizationId/pentests/:pentestId/findings/:pentestFindingId",
23444
+ pathParams: PentestFindingIdParamsSchema,
23445
+ body: UpdatePentestFindingRequestSchema,
23446
+ responses: {
23447
+ 200: PentestFindingResponseSchema,
23448
+ 400: ErrorResponseSchema,
23449
+ 401: ErrorResponseSchema,
23450
+ 403: ErrorResponseSchema,
23451
+ 404: ErrorResponseSchema,
23452
+ 500: ErrorResponseSchema
23453
+ }
23454
+ },
23455
+ deleteFinding: {
23456
+ method: "DELETE",
23457
+ path: "/organizations/:organizationId/pentests/:pentestId/findings/:pentestFindingId",
23458
+ pathParams: PentestFindingIdParamsSchema,
23459
+ responses: {
23460
+ 204: DeleteResponseSchema,
23461
+ 401: ErrorResponseSchema,
23462
+ 403: ErrorResponseSchema,
23463
+ 404: ErrorResponseSchema,
23464
+ 500: ErrorResponseSchema
23465
+ }
23466
+ },
23467
+ // ─── Contests ───
23468
+ listContests: {
23469
+ method: "GET",
23470
+ path: "/organizations/:organizationId/pentests/:pentestId/findings/:pentestFindingId/contests",
23471
+ pathParams: PentestFindingIdParamsSchema,
23472
+ responses: {
23473
+ 200: ListPentestFindingContestsResponseSchema,
23474
+ 401: ErrorResponseSchema,
23475
+ 403: ErrorResponseSchema,
23476
+ 404: ErrorResponseSchema,
23477
+ 500: ErrorResponseSchema
23478
+ }
23479
+ },
23480
+ createContest: {
23481
+ method: "POST",
23482
+ path: "/organizations/:organizationId/pentests/:pentestId/findings/:pentestFindingId/contests",
23483
+ pathParams: PentestFindingIdParamsSchema,
23484
+ body: CreatePentestFindingContestRequestSchema,
23485
+ responses: {
23486
+ 201: PentestFindingContestResponseSchema,
23487
+ 400: ErrorResponseSchema,
23488
+ 401: ErrorResponseSchema,
23489
+ 403: ErrorResponseSchema,
23490
+ 404: ErrorResponseSchema,
23491
+ 500: ErrorResponseSchema
23492
+ }
23493
+ },
23494
+ resolveContest: {
23495
+ method: "PATCH",
23496
+ path: "/organizations/:organizationId/pentests/:pentestId/findings/:pentestFindingId/contests/:contestId",
23497
+ pathParams: PentestFindingContestIdParamsSchema,
23498
+ body: ResolvePentestFindingContestRequestSchema,
23499
+ responses: {
23500
+ 200: PentestFindingContestResponseSchema,
23501
+ 400: ErrorResponseSchema,
23502
+ 401: ErrorResponseSchema,
23503
+ 403: ErrorResponseSchema,
23504
+ 404: ErrorResponseSchema,
23505
+ 500: ErrorResponseSchema
23506
+ }
23507
+ },
23508
+ // ─── Retests ───
23509
+ listRetests: {
23510
+ method: "GET",
23511
+ path: "/organizations/:organizationId/pentests/:pentestId/findings/:pentestFindingId/retests",
23512
+ pathParams: PentestFindingIdParamsSchema,
23513
+ responses: {
23514
+ 200: ListPentestFindingRetestsResponseSchema,
23515
+ 401: ErrorResponseSchema,
23516
+ 403: ErrorResponseSchema,
23517
+ 404: ErrorResponseSchema,
23518
+ 500: ErrorResponseSchema
23519
+ }
23520
+ },
23521
+ createRetest: {
23522
+ method: "POST",
23523
+ path: "/organizations/:organizationId/pentests/:pentestId/findings/:pentestFindingId/retests",
23524
+ pathParams: PentestFindingIdParamsSchema,
23525
+ body: CreatePentestFindingRetestRequestSchema,
23526
+ responses: {
23527
+ 201: PentestFindingRetestResponseSchema,
23528
+ 400: ErrorResponseSchema,
23529
+ 401: ErrorResponseSchema,
23530
+ 403: ErrorResponseSchema,
23531
+ 404: ErrorResponseSchema,
23532
+ 500: ErrorResponseSchema
23533
+ }
23534
+ },
23535
+ // ─── Notes ───
23536
+ listNotes: {
23537
+ method: "GET",
23538
+ path: "/organizations/:organizationId/pentests/:pentestId/findings/:pentestFindingId/notes",
23539
+ pathParams: PentestFindingIdParamsSchema,
23540
+ responses: {
23541
+ 200: ListPentestFindingNotesResponseSchema,
23542
+ 401: ErrorResponseSchema,
23543
+ 403: ErrorResponseSchema,
23544
+ 404: ErrorResponseSchema,
23545
+ 500: ErrorResponseSchema
23546
+ }
23547
+ },
23548
+ createNote: {
23549
+ method: "POST",
23550
+ path: "/organizations/:organizationId/pentests/:pentestId/findings/:pentestFindingId/notes",
23551
+ pathParams: PentestFindingIdParamsSchema,
23552
+ body: CreatePentestFindingNoteRequestSchema,
23553
+ responses: {
23554
+ 201: PentestFindingNoteResponseSchema,
23555
+ 400: ErrorResponseSchema,
23556
+ 401: ErrorResponseSchema,
23557
+ 403: ErrorResponseSchema,
23558
+ 404: ErrorResponseSchema,
23559
+ 500: ErrorResponseSchema
23560
+ }
23561
+ },
23562
+ updateNote: {
23563
+ method: "PATCH",
23564
+ path: "/organizations/:organizationId/pentests/:pentestId/findings/:pentestFindingId/notes/:noteId",
23565
+ pathParams: PentestFindingNoteIdParamsSchema,
23566
+ body: UpdatePentestFindingNoteRequestSchema,
23567
+ responses: {
23568
+ 200: PentestFindingNoteResponseSchema,
23569
+ 400: ErrorResponseSchema,
23570
+ 401: ErrorResponseSchema,
23571
+ 403: ErrorResponseSchema,
23572
+ 404: ErrorResponseSchema,
23573
+ 500: ErrorResponseSchema
23574
+ }
23575
+ },
23576
+ deleteNote: {
23577
+ method: "DELETE",
23578
+ path: "/organizations/:organizationId/pentests/:pentestId/findings/:pentestFindingId/notes/:noteId",
23579
+ pathParams: PentestFindingNoteIdParamsSchema,
23580
+ responses: {
23581
+ 204: DeleteResponseSchema,
23582
+ 401: ErrorResponseSchema,
23583
+ 403: ErrorResponseSchema,
23584
+ 404: ErrorResponseSchema,
23585
+ 500: ErrorResponseSchema
23586
+ }
23587
+ },
23588
+ // ─── AI parsing ───
23589
+ parseFindingMarkdown: {
23590
+ method: "POST",
23591
+ path: "/organizations/:organizationId/pentests/:pentestId/findings/parse-markdown",
23592
+ pathParams: PentestFindingParamsSchema,
23593
+ body: ParseFindingMarkdownRequestSchema,
23594
+ responses: {
23595
+ 200: ParseFindingMarkdownResponseSchema,
23596
+ 400: ErrorResponseSchema,
23597
+ 401: ErrorResponseSchema,
23598
+ 403: ErrorResponseSchema,
23599
+ 404: ErrorResponseSchema,
23600
+ 500: ErrorResponseSchema
23601
+ }
23602
+ }
23603
+ });
23604
+
23605
+ // ../../packages/api-contracts/src/schemas/api/v1/repository.api.ts
23606
+ var PlatformValues = ["GITHUB", "GITLAB", "BITBUCKET"];
23607
+ var RepositoryStatusValues = ["CONNECTED", "DISCONNECTED"];
23608
+ var RepositoryIdParamsSchema = OrgIdParamsSchema.extend({
23609
+ repositoryId: external_exports.uuid()
23610
+ });
23611
+ var CreateRepositoryRequestSchema = external_exports.object({
23612
+ repositoryUrl: external_exports.url(),
23613
+ platform: external_exports.enum(PlatformValues),
23614
+ defaultBranch: external_exports.string().min(1).max(255).optional(),
23615
+ status: external_exports.enum(RepositoryStatusValues).optional()
23616
+ });
23617
+ var UpdateRepositoryRequestSchema = external_exports.object({
23618
+ repositoryUrl: external_exports.url().optional(),
23619
+ platform: external_exports.enum(PlatformValues).optional(),
23620
+ defaultBranch: external_exports.string().min(1).max(255).optional(),
23621
+ status: external_exports.enum(RepositoryStatusValues).optional()
23622
+ });
23623
+ var RepositoryResponseSchema = external_exports.object({
23624
+ repositoryId: external_exports.uuid(),
23625
+ organizationId: external_exports.uuid(),
23626
+ repositoryUrl: external_exports.url(),
23627
+ platform: external_exports.enum(PlatformValues),
23628
+ status: external_exports.enum(RepositoryStatusValues),
23629
+ defaultBranch: external_exports.string(),
23630
+ createdAt: external_exports.date(),
23631
+ updatedAt: external_exports.date()
23632
+ });
23633
+ var ListRepositoriesResponseSchema = external_exports.array(RepositoryResponseSchema);
23634
+ var CloneTokenRequestSchema = external_exports.object({
23635
+ repositoryUrl: external_exports.string().url()
23636
+ });
23637
+ var CloneTokenResponseSchema = external_exports.object({
23638
+ token: external_exports.string(),
23639
+ expiresAt: external_exports.string().datetime()
23640
+ });
23641
+
23642
+ // ../../packages/api-contracts/src/contracts/v1/repository.ts
23643
+ var c11 = initContract();
23644
+ var repositoryContract = c11.router({
23645
+ createRepository: {
23646
+ method: "POST",
23647
+ path: "/organizations/:organizationId/repositories",
23648
+ pathParams: OrgIdParamsSchema,
23649
+ body: CreateRepositoryRequestSchema,
23650
+ responses: {
23651
+ 201: RepositoryResponseSchema,
23652
+ 401: ErrorResponseSchema,
23653
+ 403: ErrorResponseSchema,
23654
+ 404: ErrorResponseSchema,
23655
+ 500: ErrorResponseSchema
23656
+ }
23657
+ },
23658
+ listRepositories: {
23659
+ method: "GET",
23660
+ path: "/organizations/:organizationId/repositories",
23661
+ pathParams: OrgIdParamsSchema,
23662
+ responses: {
23663
+ 200: ListRepositoriesResponseSchema,
23664
+ 401: ErrorResponseSchema,
23665
+ 403: ErrorResponseSchema,
23666
+ 404: ErrorResponseSchema,
23667
+ 500: ErrorResponseSchema
23668
+ }
23669
+ },
23670
+ getRepository: {
23671
+ method: "GET",
23672
+ path: "/organizations/:organizationId/repositories/:repositoryId",
23673
+ pathParams: RepositoryIdParamsSchema,
23674
+ responses: {
23675
+ 200: RepositoryResponseSchema,
23676
+ 401: ErrorResponseSchema,
23677
+ 403: ErrorResponseSchema,
23678
+ 404: ErrorResponseSchema,
23679
+ 500: ErrorResponseSchema
23680
+ }
23681
+ },
23682
+ updateRepository: {
23683
+ method: "PUT",
23684
+ path: "/organizations/:organizationId/repositories/:repositoryId",
23685
+ pathParams: RepositoryIdParamsSchema,
23686
+ body: UpdateRepositoryRequestSchema,
23687
+ responses: {
23688
+ 200: RepositoryResponseSchema,
23689
+ 401: ErrorResponseSchema,
23690
+ 403: ErrorResponseSchema,
23691
+ 404: ErrorResponseSchema,
23692
+ 500: ErrorResponseSchema
23693
+ }
23694
+ },
23695
+ deleteRepository: {
23696
+ method: "DELETE",
23697
+ path: "/organizations/:organizationId/repositories/:repositoryId",
23698
+ pathParams: RepositoryIdParamsSchema,
23699
+ responses: {
23700
+ 204: DeleteResponseSchema,
23701
+ 401: ErrorResponseSchema,
23702
+ 403: ErrorResponseSchema,
23703
+ 404: ErrorResponseSchema,
23704
+ 500: ErrorResponseSchema
23705
+ }
23706
+ },
23707
+ getCloneToken: {
23708
+ method: "POST",
23709
+ path: "/organizations/:organizationId/repositories/clone-token",
23710
+ pathParams: OrgIdParamsSchema,
23711
+ body: CloneTokenRequestSchema,
23712
+ responses: {
23713
+ 200: CloneTokenResponseSchema,
23714
+ 401: ErrorResponseSchema,
23715
+ 403: ErrorResponseSchema,
23716
+ 404: ErrorResponseSchema,
23717
+ 500: ErrorResponseSchema
23718
+ }
23719
+ }
23720
+ });
23721
+
23722
+ // ../../packages/api-contracts/src/schemas/domain/scan.schema.ts
23723
+ var ScanStatusValues = [
23724
+ "PENDING",
23725
+ "QUEUED",
23726
+ "RUNNING",
23727
+ "COMPLETED",
23728
+ "FAILED",
23729
+ "CANCELLED"
23730
+ ];
23731
+ var ScanStatus = external_exports.enum(ScanStatusValues);
23732
+ var ScanModeValues = ["DAST", "SAST", "SCA", "SECRETS"];
23733
+ var ScanMode = external_exports.enum(ScanModeValues);
23734
+ var ScanTypeValues = ["FULL", "INCREMENTAL", "RETEST"];
23735
+ var ScanType = external_exports.enum(ScanTypeValues);
23736
+ var CancellationReasonValues = ["USER_ABORTED", "SUPERSEDED"];
23737
+ var CancellationReason = external_exports.enum(CancellationReasonValues);
23738
+ var ScanTriggerTypeValues = [
23739
+ "MANUAL",
23740
+ "PUSH",
23741
+ "PULL_REQUEST",
23742
+ "RETEST",
23743
+ "SCHEDULED"
23744
+ ];
23745
+ var ScanTriggerType = external_exports.enum(ScanTriggerTypeValues);
23746
+
23747
+ // ../../packages/api-contracts/src/schemas/api/v1/scan.api.ts
23748
+ var ScanIdParamsSchema = OrgIdParamsSchema.extend({
23749
+ scanId: external_exports.uuid()
23750
+ });
23751
+ var CreateScanRequestSchema = external_exports.discriminatedUnion("scanMode", [
23752
+ external_exports.object({
23753
+ scanMode: external_exports.literal("DAST"),
23754
+ webApplicationId: external_exports.uuid(),
23755
+ targetUrl: external_exports.url(),
23756
+ userProvidedContext: external_exports.string().optional(),
23757
+ scanConfiguration: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
23758
+ }),
23759
+ external_exports.object({
23760
+ scanMode: external_exports.literal("SAST"),
23761
+ repositoryId: external_exports.uuid(),
23762
+ branch: external_exports.string().optional(),
23763
+ scanType: external_exports.enum(["FULL", "INCREMENTAL"]).optional(),
23764
+ userProvidedContext: external_exports.string().optional(),
23765
+ scanConfiguration: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
23766
+ }),
23767
+ external_exports.object({
23768
+ scanMode: external_exports.literal("SCA"),
23769
+ repositoryId: external_exports.uuid(),
23770
+ branch: external_exports.string().optional(),
23771
+ scanType: external_exports.enum(["FULL", "INCREMENTAL"]).optional(),
23772
+ userProvidedContext: external_exports.string().optional(),
23773
+ scanConfiguration: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
23774
+ }),
23775
+ external_exports.object({
23776
+ scanMode: external_exports.literal("SECRETS"),
23777
+ repositoryId: external_exports.uuid(),
23778
+ branch: external_exports.string().optional(),
23779
+ scanType: external_exports.enum(["FULL", "INCREMENTAL"]).optional(),
23780
+ userProvidedContext: external_exports.string().optional(),
23781
+ scanConfiguration: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
23782
+ })
23783
+ ]);
23784
+ var ScanResponseSchema = external_exports.object({
23785
+ scanId: external_exports.uuid(),
23786
+ organizationId: external_exports.uuid(),
23787
+ initiatedById: external_exports.uuid(),
23788
+ initiatedByName: external_exports.string().nullable(),
23789
+ initiatedByProfilePictureUrl: external_exports.string().nullable(),
23790
+ scanMode: ScanMode,
23791
+ scanType: external_exports.enum(ScanTypeValues),
23792
+ webApplicationId: external_exports.uuid().nullable(),
23793
+ targetUrl: external_exports.string().nullable(),
23794
+ repositoryId: external_exports.uuid().nullable(),
23795
+ branch: external_exports.string().nullable(),
23796
+ status: external_exports.enum(ScanStatusValues),
23797
+ cancellationReason: external_exports.enum(CancellationReasonValues).nullable(),
23798
+ errorMessage: external_exports.string().nullable(),
23799
+ userProvidedContext: external_exports.string().nullable(),
23800
+ scanConfiguration: external_exports.record(external_exports.string(), external_exports.unknown()).nullable(),
23801
+ triggerType: external_exports.enum(ScanTriggerTypeValues).nullable(),
23802
+ triggerMetadata: external_exports.record(external_exports.string(), external_exports.unknown()).nullable(),
23803
+ startedAt: external_exports.date().nullable(),
23804
+ completedAt: external_exports.date().nullable(),
23805
+ createdAt: external_exports.date(),
23806
+ updatedAt: external_exports.date()
23807
+ });
23808
+ var ListScansQuerySchema = external_exports.object({
23809
+ status: external_exports.enum(ScanStatusValues).array().or(external_exports.enum(ScanStatusValues)).optional(),
23810
+ repositoryId: external_exports.uuid().optional(),
23811
+ page: external_exports.coerce.number().int().min(1).max(1e4).optional(),
23812
+ pageSize: external_exports.coerce.number().int().min(1).max(200).optional()
23813
+ });
23814
+ var ListScansResponseSchema = external_exports.object({
23815
+ scans: external_exports.array(ScanResponseSchema),
23816
+ total: external_exports.number(),
23817
+ page: external_exports.number(),
23818
+ pageSize: external_exports.number()
23819
+ });
23820
+ var ScanArrayResponseSchema = external_exports.array(ScanResponseSchema);
23821
+ var CancelScanResponseSchema = external_exports.object({
23822
+ scanId: external_exports.uuid(),
23823
+ status: external_exports.literal("CANCELLED")
23824
+ });
23825
+
23826
+ // ../../packages/api-contracts/src/schemas/api/v1/scan-log.api.ts
23827
+ var ScanLogQuerySchema = external_exports.object({
23828
+ offset: external_exports.coerce.number().int().min(0).optional()
23829
+ });
23830
+ var ScanLogEntrySchema = external_exports.object({
23831
+ timestamp: external_exports.string(),
23832
+ level: external_exports.enum(["INFO", "WARN", "ERROR"]),
23833
+ message: external_exports.string(),
23834
+ phase: external_exports.string().nullable()
23835
+ });
23836
+ var ListScanLogsResponseSchema = external_exports.object({
23837
+ logs: external_exports.array(ScanLogEntrySchema),
23838
+ nextOffset: external_exports.number()
23839
+ });
23840
+
23184
23841
  // ../../packages/api-contracts/src/contracts/v1/scan.ts
23185
- var c10 = initContract();
23186
- var scanContract = c10.router({
23842
+ var c12 = initContract();
23843
+ var scanContract = c12.router({
23187
23844
  createScan: {
23188
23845
  method: "POST",
23189
23846
  path: "/organizations/:organizationId/scans",
@@ -23281,14 +23938,15 @@ var UserResponseSchema = external_exports.object({
23281
23938
  lastName: external_exports.string(),
23282
23939
  email: external_exports.string(),
23283
23940
  profilePictureUrl: external_exports.string().nullable(),
23941
+ isStaff: external_exports.boolean(),
23284
23942
  createdAt: external_exports.date(),
23285
23943
  updatedAt: external_exports.date()
23286
23944
  });
23287
23945
  var ListUsersResponseSchema = external_exports.array(UserResponseSchema);
23288
23946
 
23289
23947
  // ../../packages/api-contracts/src/contracts/v1/user.ts
23290
- var c11 = initContract();
23291
- var userContract = c11.router({
23948
+ var c13 = initContract();
23949
+ var userContract = c13.router({
23292
23950
  listUsers: {
23293
23951
  method: "GET",
23294
23952
  path: "/organizations/:organizationId/users",
@@ -23360,8 +24018,8 @@ var VantaIntegrationResponseSchema = external_exports.object({
23360
24018
  });
23361
24019
 
23362
24020
  // ../../packages/api-contracts/src/contracts/v1/vanta-integration.ts
23363
- var c12 = initContract();
23364
- var vantaIntegrationContract = c12.router({
24021
+ var c14 = initContract();
24022
+ var vantaIntegrationContract = c14.router({
23365
24023
  createVantaIntegration: {
23366
24024
  method: "POST",
23367
24025
  path: "/organizations/:organizationId/vanta-integration",
@@ -23421,7 +24079,8 @@ var VulnerabilityStatusValues = [
23421
24079
  "IN_PROGRESS",
23422
24080
  "FIXED",
23423
24081
  "IGNORED",
23424
- "FALSE_POSITIVE"
24082
+ "FALSE_POSITIVE",
24083
+ "DISMISSED"
23425
24084
  ];
23426
24085
  var VulnerabilityStatus = external_exports.enum(VulnerabilityStatusValues);
23427
24086
  var VulnerabilitySeverityValues = ["LOW", "MEDIUM", "HIGH", "CRITICAL"];
@@ -23434,6 +24093,8 @@ var VulnerabilityTypeValues = [
23434
24093
  "MISCONFIGURATION"
23435
24094
  ];
23436
24095
  var VulnerabilityType = external_exports.enum(VulnerabilityTypeValues);
24096
+ var DismissReasonValues = ["ACCEPTED_RISK", "FALSE_POSITIVE", "OTHER"];
24097
+ var DismissReason = external_exports.enum(DismissReasonValues);
23437
24098
  var ScanModeValues2 = ["SAST", "DAST", "SCA", "SECRETS"];
23438
24099
  var ScanMode2 = external_exports.enum(ScanModeValues2);
23439
24100
 
@@ -23462,7 +24123,12 @@ var VulnerabilityLatestFindingSchema = external_exports.object({
23462
24123
  attackVector: external_exports.string(),
23463
24124
  exploitScenario: external_exports.string(),
23464
24125
  impact: external_exports.string(),
23465
- confidence: external_exports.number()
24126
+ confidence: external_exports.number(),
24127
+ // Threat model fields (null for findings from scans before this feature)
24128
+ classification: external_exports.enum(["vulnerability", "defense_in_depth", "context_dependent"]).nullable(),
24129
+ prerequisiteAccess: external_exports.string().nullable(),
24130
+ capabilityGain: external_exports.string().nullable(),
24131
+ technicalSeverity: VulnerabilitySeverity.nullable()
23466
24132
  });
23467
24133
  var DependencyGraphSchema = external_exports.object({
23468
24134
  vulnerablePackage: external_exports.string(),
@@ -23486,6 +24152,7 @@ var VulnerabilityResponseSchema = external_exports.object({
23486
24152
  scanMode: ScanMode2.nullable(),
23487
24153
  status: VulnerabilityStatus,
23488
24154
  statusReason: external_exports.string().nullable(),
24155
+ dismissReason: DismissReason.nullable(),
23489
24156
  cweId: external_exports.string().nullable(),
23490
24157
  source: VulnerabilitySourceSchema,
23491
24158
  introducedBy: VulnerabilityIntroducedBySchema,
@@ -23572,12 +24239,13 @@ var VulnerabilityAggregatedCountsResponseSchema = external_exports.object({
23572
24239
  });
23573
24240
  var UpdateVulnerabilityRequestSchema = external_exports.object({
23574
24241
  status: VulnerabilityStatus.optional(),
23575
- statusReason: external_exports.string().optional()
24242
+ statusReason: external_exports.string().optional(),
24243
+ dismissReason: DismissReason.optional()
23576
24244
  });
23577
24245
 
23578
24246
  // ../../packages/api-contracts/src/contracts/v1/vulnerability.ts
23579
- var c13 = initContract();
23580
- var vulnerabilityContract = c13.router({
24247
+ var c15 = initContract();
24248
+ var vulnerabilityContract = c15.router({
23581
24249
  filterVulnerabilities: {
23582
24250
  method: "POST",
23583
24251
  path: "/organizations/:organizationId/vulnerabilities/filter",
@@ -23686,7 +24354,90 @@ var vulnerabilityContract = c13.router({
23686
24354
  path: "/organizations/:organizationId/vulnerabilities/:vulnerabilityId/retests",
23687
24355
  pathParams: VulnerabilityIdParamsSchema,
23688
24356
  responses: {
23689
- 200: ListScansResponseSchema,
24357
+ 200: ScanArrayResponseSchema,
24358
+ 401: ErrorResponseSchema,
24359
+ 403: ErrorResponseSchema,
24360
+ 404: ErrorResponseSchema,
24361
+ 500: ErrorResponseSchema
24362
+ }
24363
+ }
24364
+ });
24365
+
24366
+ // ../../packages/api-contracts/src/schemas/api/v1/vulnerability-note.api.ts
24367
+ var VulnerabilityNoteParamsSchema = OrgIdParamsSchema.extend({
24368
+ vulnerabilityId: external_exports.uuid()
24369
+ });
24370
+ var VulnerabilityNoteIdParamsSchema = VulnerabilityNoteParamsSchema.extend({
24371
+ noteId: external_exports.uuid()
24372
+ });
24373
+ var VulnerabilityNoteResponseSchema = external_exports.object({
24374
+ noteId: external_exports.uuid(),
24375
+ vulnerabilityId: external_exports.uuid(),
24376
+ organizationId: external_exports.uuid(),
24377
+ authorId: external_exports.uuid(),
24378
+ authorName: external_exports.string(),
24379
+ authorProfilePictureUrl: external_exports.string().nullable(),
24380
+ content: external_exports.string(),
24381
+ createdAt: external_exports.coerce.date(),
24382
+ updatedAt: external_exports.coerce.date()
24383
+ });
24384
+ var ListVulnerabilityNotesResponseSchema = external_exports.array(VulnerabilityNoteResponseSchema);
24385
+ var CreateVulnerabilityNoteRequestSchema = external_exports.object({
24386
+ content: external_exports.string().min(1).max(1e4)
24387
+ });
24388
+ var UpdateVulnerabilityNoteRequestSchema = external_exports.object({
24389
+ content: external_exports.string().min(1).max(1e4)
24390
+ });
24391
+
24392
+ // ../../packages/api-contracts/src/contracts/v1/vulnerability-note.ts
24393
+ var c16 = initContract();
24394
+ var vulnerabilityNoteContract = c16.router({
24395
+ listNotes: {
24396
+ method: "GET",
24397
+ path: "/organizations/:organizationId/vulnerabilities/:vulnerabilityId/notes",
24398
+ pathParams: VulnerabilityNoteParamsSchema,
24399
+ responses: {
24400
+ 200: ListVulnerabilityNotesResponseSchema,
24401
+ 401: ErrorResponseSchema,
24402
+ 403: ErrorResponseSchema,
24403
+ 404: ErrorResponseSchema,
24404
+ 500: ErrorResponseSchema
24405
+ }
24406
+ },
24407
+ createNote: {
24408
+ method: "POST",
24409
+ path: "/organizations/:organizationId/vulnerabilities/:vulnerabilityId/notes",
24410
+ pathParams: VulnerabilityNoteParamsSchema,
24411
+ body: CreateVulnerabilityNoteRequestSchema,
24412
+ responses: {
24413
+ 201: VulnerabilityNoteResponseSchema,
24414
+ 400: ErrorResponseSchema,
24415
+ 401: ErrorResponseSchema,
24416
+ 403: ErrorResponseSchema,
24417
+ 404: ErrorResponseSchema,
24418
+ 500: ErrorResponseSchema
24419
+ }
24420
+ },
24421
+ updateNote: {
24422
+ method: "PATCH",
24423
+ path: "/organizations/:organizationId/vulnerabilities/:vulnerabilityId/notes/:noteId",
24424
+ pathParams: VulnerabilityNoteIdParamsSchema,
24425
+ body: UpdateVulnerabilityNoteRequestSchema,
24426
+ responses: {
24427
+ 200: VulnerabilityNoteResponseSchema,
24428
+ 400: ErrorResponseSchema,
24429
+ 401: ErrorResponseSchema,
24430
+ 403: ErrorResponseSchema,
24431
+ 404: ErrorResponseSchema,
24432
+ 500: ErrorResponseSchema
24433
+ }
24434
+ },
24435
+ deleteNote: {
24436
+ method: "DELETE",
24437
+ path: "/organizations/:organizationId/vulnerabilities/:vulnerabilityId/notes/:noteId",
24438
+ pathParams: VulnerabilityNoteIdParamsSchema,
24439
+ responses: {
24440
+ 204: DeleteResponseSchema,
23690
24441
  401: ErrorResponseSchema,
23691
24442
  403: ErrorResponseSchema,
23692
24443
  404: ErrorResponseSchema,
@@ -23712,8 +24463,8 @@ var WebApplicationResponseSchema = external_exports.object({
23712
24463
  var ListWebApplicationsResponseSchema = external_exports.array(WebApplicationResponseSchema);
23713
24464
 
23714
24465
  // ../../packages/api-contracts/src/contracts/v1/web-application.ts
23715
- var c14 = initContract();
23716
- var webApplicationContract = c14.router({
24466
+ var c17 = initContract();
24467
+ var webApplicationContract = c17.router({
23717
24468
  listWebApplications: {
23718
24469
  method: "GET",
23719
24470
  path: "/organizations/:organizationId/web-applications",
@@ -23852,8 +24603,8 @@ var ListWebhookDeliveriesResponseSchema = external_exports.object({
23852
24603
  });
23853
24604
 
23854
24605
  // ../../packages/api-contracts/src/contracts/v1/webhook-settings.ts
23855
- var c15 = initContract();
23856
- var webhookSettingsContract = c15.router({
24606
+ var c18 = initContract();
24607
+ var webhookSettingsContract = c18.router({
23857
24608
  listWebhookEndpoints: {
23858
24609
  method: "GET",
23859
24610
  path: "/organizations/:organizationId/webhook-settings/endpoints",
@@ -23991,8 +24742,8 @@ var webhookSettingsContract = c15.router({
23991
24742
  });
23992
24743
 
23993
24744
  // ../../packages/api-contracts/src/contracts/v1/index.ts
23994
- var c16 = initContract();
23995
- var v1Contract = c16.router(
24745
+ var c19 = initContract();
24746
+ var v1Contract = c19.router(
23996
24747
  {
23997
24748
  admin: adminContract,
23998
24749
  scan: scanContract,
@@ -24006,9 +24757,12 @@ var v1Contract = c16.router(
24006
24757
  knowledgeBase: knowledgeBaseContract,
24007
24758
  knowledgeDocument: knowledgeDocumentContract,
24008
24759
  vulnerability: vulnerabilityContract,
24760
+ vulnerabilityNote: vulnerabilityNoteContract,
24009
24761
  webhookSettings: webhookSettingsContract,
24010
24762
  webApplication: webApplicationContract,
24011
- chatSession: chatSessionContract
24763
+ chatSession: chatSessionContract,
24764
+ pentest: pentestContract,
24765
+ pentestFinding: pentestFindingContract
24012
24766
  },
24013
24767
  {
24014
24768
  pathPrefix: "/v1"
@@ -24016,8 +24770,8 @@ var v1Contract = c16.router(
24016
24770
  );
24017
24771
 
24018
24772
  // ../../packages/api-contracts/src/contracts/index.ts
24019
- var c17 = initContract();
24020
- var contract = c17.router({
24773
+ var c20 = initContract();
24774
+ var contract = c20.router({
24021
24775
  v1: v1Contract
24022
24776
  });
24023
24777
 
@@ -24027,8 +24781,8 @@ var GitHubWebhookResponseSchema = external_exports.object({
24027
24781
  });
24028
24782
 
24029
24783
  // ../../packages/api-contracts/src/contracts/webhooks/github.ts
24030
- var c18 = initContract();
24031
- var githubWebhookContract = c18.router(
24784
+ var c21 = initContract();
24785
+ var githubWebhookContract = c21.router(
24032
24786
  {
24033
24787
  handleWebhook: {
24034
24788
  method: "POST",
@@ -24053,8 +24807,8 @@ var HealthResponseSchema = external_exports.object({
24053
24807
  });
24054
24808
 
24055
24809
  // ../../packages/api-contracts/src/contracts/health.ts
24056
- var c19 = initContract();
24057
- var healthContract = c19.router({
24810
+ var c22 = initContract();
24811
+ var healthContract = c22.router({
24058
24812
  getHealth: {
24059
24813
  method: "GET",
24060
24814
  path: "/health",
@@ -24098,12 +24852,13 @@ var ListPrVulnerabilitiesResponseSchema = external_exports.object({
24098
24852
  });
24099
24853
  var UpdatePrVulnerabilityRequestSchema = external_exports.object({
24100
24854
  status: VulnerabilityStatus,
24101
- statusReason: external_exports.string().optional()
24855
+ statusReason: external_exports.string().optional(),
24856
+ dismissReason: DismissReason.optional()
24102
24857
  });
24103
24858
 
24104
24859
  // ../../packages/api-contracts/src/contracts/v1/pr-vulnerability.ts
24105
- var c20 = initContract();
24106
- var prVulnerabilityContract = c20.router(
24860
+ var c23 = initContract();
24861
+ var prVulnerabilityContract = c23.router(
24107
24862
  {
24108
24863
  listPrVulnerabilities: {
24109
24864
  method: "GET",
@@ -24149,6 +24904,7 @@ var FindingSchema = external_exports.object({
24149
24904
  // src/api-client.ts
24150
24905
  var readTokenSafe = readToken;
24151
24906
  var PRODUCTION_API_URL = "https://api.securewithtrace.com";
24907
+ var UNAUTHORIZED_STATUS = 401;
24152
24908
  function getApiBaseUrl() {
24153
24909
  const raw = process.env["TRACE_API_URL"];
24154
24910
  if (!raw) {
@@ -24174,14 +24930,6 @@ function getApiBaseUrl() {
24174
24930
  }
24175
24931
  return raw.replace(/\/+$/, "");
24176
24932
  }
24177
- function requireAuth() {
24178
- const token = readToken();
24179
- if (!token) {
24180
- console.error("Not logged in. Run `tracecli auth login` first.");
24181
- process.exit(1);
24182
- }
24183
- return { token };
24184
- }
24185
24933
  function createClient(token) {
24186
24934
  return initClient(v1Contract, {
24187
24935
  baseUrl: getApiBaseUrl(),
@@ -24190,9 +24938,71 @@ function createClient(token) {
24190
24938
  }
24191
24939
  });
24192
24940
  }
24941
+ function getWorkosClientId() {
24942
+ const clientId = "client_01KEZ01W5Q3107GTBY51WQ67HT";
24943
+ if (!clientId || clientId.trim().length === 0) {
24944
+ return null;
24945
+ }
24946
+ return clientId;
24947
+ }
24948
+ async function refreshStoredAccessToken() {
24949
+ const clientId = getWorkosClientId();
24950
+ const refreshToken = readRefreshToken();
24951
+ if (!clientId || !refreshToken) {
24952
+ return null;
24953
+ }
24954
+ try {
24955
+ const tokenResponse = await refreshAccessToken(clientId, refreshToken);
24956
+ const nextRefreshToken = tokenResponse.refresh_token ?? refreshToken;
24957
+ writeTokens(tokenResponse.access_token, nextRefreshToken);
24958
+ return tokenResponse.access_token;
24959
+ } catch (error48) {
24960
+ if (error48 instanceof Error && (error48.message.includes(" 400 ") || error48.message.includes(" 401 "))) {
24961
+ removeToken();
24962
+ }
24963
+ return null;
24964
+ }
24965
+ }
24966
+ async function authenticatedRequest(request) {
24967
+ const token = readToken();
24968
+ if (!token) {
24969
+ console.error("Not logged in. Run `tracecli auth login` first.");
24970
+ process.exit(1);
24971
+ }
24972
+ const firstResult = await request(createClient(token));
24973
+ if (firstResult.status !== UNAUTHORIZED_STATUS) {
24974
+ return firstResult;
24975
+ }
24976
+ const refreshedToken = await refreshStoredAccessToken();
24977
+ if (!refreshedToken) {
24978
+ return firstResult;
24979
+ }
24980
+ return request(createClient(refreshedToken));
24981
+ }
24982
+ async function authenticatedRequestSafe(request) {
24983
+ const token = readTokenSafe();
24984
+ if (!token) {
24985
+ return null;
24986
+ }
24987
+ try {
24988
+ const firstResult = await request(createClient(token));
24989
+ if (firstResult.status !== UNAUTHORIZED_STATUS) {
24990
+ return firstResult;
24991
+ }
24992
+ const refreshedToken = await refreshStoredAccessToken();
24993
+ if (!refreshedToken) {
24994
+ return firstResult;
24995
+ }
24996
+ return await request(createClient(refreshedToken));
24997
+ } catch {
24998
+ return null;
24999
+ }
25000
+ }
24193
25001
  var SAFE_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
24194
25002
  async function resolveOrganizationId(client) {
24195
- const result = await client.organization.listOrganizations();
25003
+ const result = client ? await client.organization.listOrganizations() : await authenticatedRequest(
25004
+ (authenticatedClient) => authenticatedClient.organization.listOrganizations()
25005
+ );
24196
25006
  if (result.status !== 200) {
24197
25007
  console.error(`Failed to resolve organization (status ${result.status}).`);
24198
25008
  process.exit(1);
@@ -24211,7 +25021,12 @@ async function resolveOrganizationId(client) {
24211
25021
  }
24212
25022
  async function resolveOrganizationIdSafe(client) {
24213
25023
  try {
24214
- const result = await client.organization.listOrganizations();
25024
+ const result = client ? await client.organization.listOrganizations() : await authenticatedRequestSafe(
25025
+ (authenticatedClient) => authenticatedClient.organization.listOrganizations()
25026
+ );
25027
+ if (!result) {
25028
+ return null;
25029
+ }
24215
25030
  if (result.status !== 200) {
24216
25031
  return null;
24217
25032
  }
@@ -24229,7 +25044,180 @@ async function resolveOrganizationIdSafe(client) {
24229
25044
  }
24230
25045
  }
24231
25046
 
25047
+ // src/format.ts
25048
+ var SEVERITY_ORDER = {
25049
+ CRITICAL: 0,
25050
+ HIGH: 1,
25051
+ MEDIUM: 2,
25052
+ LOW: 3,
25053
+ INFORMATIONAL: 4
25054
+ };
25055
+ function formatStatus(status) {
25056
+ return status.toLowerCase().replace("_", " ");
25057
+ }
25058
+
25059
+ // src/pentest/commands.ts
25060
+ function formatDate(date5) {
25061
+ if (!date5) {
25062
+ return "\u2014";
25063
+ }
25064
+ const d = typeof date5 === "string" ? new Date(date5) : date5;
25065
+ return d.toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric" });
25066
+ }
25067
+ function formatFindingSeverity(severity) {
25068
+ switch (severity) {
25069
+ case "CRITICAL":
25070
+ return "CRIT";
25071
+ case "HIGH":
25072
+ return "HIGH";
25073
+ case "MEDIUM":
25074
+ return "MED";
25075
+ case "LOW":
25076
+ return "LOW";
25077
+ case "INFORMATIONAL":
25078
+ return "INFO";
25079
+ default:
25080
+ return severity;
25081
+ }
25082
+ }
25083
+ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
25084
+ async function resolvePentestId(organizationId, identifier) {
25085
+ if (UUID_PATTERN.test(identifier)) {
25086
+ return identifier;
25087
+ }
25088
+ const numericMatch = identifier.match(/^(?:PT-)?(\d+)$/i);
25089
+ if (!numericMatch?.[1]) {
25090
+ console.error(
25091
+ `Invalid pentest identifier '${identifier}'. Use a display ID (e.g. PT-3) or UUID.`
25092
+ );
25093
+ process.exit(1);
25094
+ }
25095
+ const displayId = Number.parseInt(numericMatch[1], 10);
25096
+ const result = await authenticatedRequest(
25097
+ (client) => client.pentest.listPentests({
25098
+ params: { organizationId }
25099
+ })
25100
+ );
25101
+ if (result.status !== 200) {
25102
+ console.error(`Failed to list pentests (status ${result.status}).`);
25103
+ process.exit(1);
25104
+ }
25105
+ const pentest = result.body.find((p) => p.displayId === displayId);
25106
+ if (!pentest) {
25107
+ console.error(
25108
+ `Pentest with display ID ${displayId} not found.
25109
+ Run \`tracecli pentest list\` to see available pentests.`
25110
+ );
25111
+ process.exit(1);
25112
+ }
25113
+ return pentest.pentestId;
25114
+ }
25115
+ function createListCommand() {
25116
+ return new Command("list").description("List pentests for your organization").option("--json", "Output as JSON").action(async (options) => {
25117
+ const organizationId = await resolveOrganizationId();
25118
+ const result = await authenticatedRequest(
25119
+ (client) => client.pentest.listPentests({
25120
+ params: { organizationId }
25121
+ })
25122
+ );
25123
+ if (result.status !== 200) {
25124
+ console.error(`Failed to list pentests (status ${result.status}).`);
25125
+ process.exit(1);
25126
+ }
25127
+ const pentests = result.body;
25128
+ if (pentests.length === 0) {
25129
+ if (options.json) {
25130
+ console.log("[]");
25131
+ } else {
25132
+ console.log("No pentests found.");
25133
+ }
25134
+ return;
25135
+ }
25136
+ if (options.json) {
25137
+ console.log(JSON.stringify(pentests, null, 2));
25138
+ return;
25139
+ }
25140
+ console.log(`Found ${pentests.length} pentest${pentests.length === 1 ? "" : "s"}:
25141
+ `);
25142
+ for (const pt of pentests) {
25143
+ const status = formatStatus(pt.status);
25144
+ const started = formatDate(pt.startedAt);
25145
+ const ended = formatDate(pt.endedAt);
25146
+ const dateRange = pt.startedAt ? `${started} \u2013 ${ended}` : "Not started";
25147
+ const findings = pt.findingCounts.total;
25148
+ console.log(` [PT-${pt.displayId}] ${pt.title}`);
25149
+ console.log(` Status: ${status} | Findings: ${findings} | ${dateRange}`);
25150
+ if (pt.description) {
25151
+ console.log(` ${pt.description}`);
25152
+ }
25153
+ console.log("");
25154
+ }
25155
+ });
25156
+ }
25157
+ function createFindingsListCommand() {
25158
+ return new Command("list").description("List findings for a pentest").requiredOption("--pentest <id>", "Pentest display ID (e.g. PT-3) or UUID").option("--json", "Output as JSON").action(async (options) => {
25159
+ const organizationId = await resolveOrganizationId();
25160
+ const pentestId = await resolvePentestId(organizationId, options.pentest);
25161
+ const result = await authenticatedRequest(
25162
+ (client) => client.pentestFinding.listFindings({
25163
+ params: { organizationId, pentestId }
25164
+ })
25165
+ );
25166
+ if (result.status !== 200) {
25167
+ console.error(`Failed to list findings (status ${result.status}).`);
25168
+ process.exit(1);
25169
+ }
25170
+ const findings = result.body;
25171
+ if (findings.length === 0) {
25172
+ if (options.json) {
25173
+ console.log("[]");
25174
+ } else {
25175
+ console.log("No findings found for this pentest.");
25176
+ }
25177
+ return;
25178
+ }
25179
+ if (options.json) {
25180
+ console.log(JSON.stringify(findings, null, 2));
25181
+ return;
25182
+ }
25183
+ console.log(`Found ${findings.length} finding${findings.length === 1 ? "" : "s"}:
25184
+ `);
25185
+ const sorted = [...findings].sort(
25186
+ (a, b) => (SEVERITY_ORDER[a.severity] ?? 99) - (SEVERITY_ORDER[b.severity] ?? 99)
25187
+ );
25188
+ for (const finding of sorted) {
25189
+ const sev = formatFindingSeverity(finding.severity);
25190
+ const status = formatStatus(finding.status);
25191
+ const cwes = finding.cweIds.length > 0 ? ` | ${finding.cweIds.join(", ")}` : "";
25192
+ const score = finding.cvssScore != null ? ` | CVSS ${finding.cvssScore.toFixed(1)}` : "";
25193
+ console.log(` [${sev}] ${finding.title}`);
25194
+ console.log(` ${finding.category} \xB7 ${status}${cwes}${score}`);
25195
+ if (finding.repositories.length > 0) {
25196
+ for (const repo of finding.repositories) {
25197
+ const location = repo.filePath ? `${repo.repositoryName} \xB7 ${repo.filePath}${repo.startLine != null ? `:${repo.startLine}` : ""}` : repo.repositoryName;
25198
+ console.log(` ${location}`);
25199
+ }
25200
+ }
25201
+ console.log("");
25202
+ }
25203
+ });
25204
+ }
25205
+ function createFindingsCommand() {
25206
+ const findings = new Command("findings").description("Manage pentest findings");
25207
+ findings.addCommand(createFindingsListCommand());
25208
+ return findings;
25209
+ }
25210
+ function createPentestCommand() {
25211
+ const pentest = new Command("pentest").description("Manage pentests");
25212
+ pentest.addCommand(createListCommand());
25213
+ pentest.addCommand(createFindingsCommand());
25214
+ return pentest;
25215
+ }
25216
+
24232
25217
  // src/repo/commands.ts
25218
+ import { chmodSync, mkdtempSync, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
25219
+ import { tmpdir } from "os";
25220
+ import { join as join3 } from "path";
24233
25221
  function stripAnsi(str) {
24234
25222
  const ESC2 = String.fromCharCode(27);
24235
25223
  const CSI = String.fromCharCode(155);
@@ -24283,14 +25271,14 @@ function validateBranchName(branch) {
24283
25271
  }
24284
25272
  return branch;
24285
25273
  }
24286
- function createListCommand() {
25274
+ function createListCommand2() {
24287
25275
  return new Command("list").description("List repositories in your organization").action(async () => {
24288
- const { token } = requireAuth();
24289
- const client = createClient(token);
24290
- const organizationId = await resolveOrganizationId(client);
24291
- const result = await client.repository.listRepositories({
24292
- params: { organizationId }
24293
- });
25276
+ const organizationId = await resolveOrganizationId();
25277
+ const result = await authenticatedRequest(
25278
+ (client) => client.repository.listRepositories({
25279
+ params: { organizationId }
25280
+ })
25281
+ );
24294
25282
  if (result.status !== 200) {
24295
25283
  console.error(`Failed to list repositories (status ${result.status}).`);
24296
25284
  process.exit(1);
@@ -24326,20 +25314,20 @@ echo '${token.replace(/'/g, "'\\''")}'
24326
25314
  return scriptPath;
24327
25315
  }
24328
25316
  async function fetchCloneToken(repoUrl) {
24329
- const token = readTokenSafe();
24330
- if (!token) {
24331
- return null;
24332
- }
24333
25317
  try {
24334
- const client = createClient(token);
24335
- const organizationId = await resolveOrganizationIdSafe(client);
25318
+ const organizationId = await resolveOrganizationIdSafe();
24336
25319
  if (!organizationId) {
24337
25320
  return null;
24338
25321
  }
24339
- const result = await client.repository.getCloneToken({
24340
- params: { organizationId },
24341
- body: { repositoryUrl: repoUrl }
24342
- });
25322
+ const result = await authenticatedRequestSafe(
25323
+ (client) => client.repository.getCloneToken({
25324
+ params: { organizationId },
25325
+ body: { repositoryUrl: repoUrl }
25326
+ })
25327
+ );
25328
+ if (!result) {
25329
+ return null;
25330
+ }
24343
25331
  if (result.status === 200) {
24344
25332
  return result.body.token;
24345
25333
  }
@@ -24409,24 +25397,20 @@ function createCloneCommand() {
24409
25397
  }
24410
25398
  function createRepoCommand() {
24411
25399
  const repo = new Command("repo").description("Manage repositories");
24412
- repo.addCommand(createListCommand());
25400
+ repo.addCommand(createListCommand2());
24413
25401
  repo.addCommand(createCloneCommand());
24414
25402
  return repo;
24415
25403
  }
24416
25404
 
24417
25405
  // src/vulnerabilities/commands.ts
24418
25406
  import { createInterface } from "readline";
24419
- var SEVERITY_ORDER = {
24420
- CRITICAL: 0,
24421
- HIGH: 1,
24422
- MEDIUM: 2,
24423
- LOW: 3
24424
- };
24425
25407
  var DEFAULT_PAGE_SIZE = 25;
24426
- async function resolveRepositoryId(client, organizationId, repoIdentifier) {
24427
- const result = await client.repository.listRepositories({
24428
- params: { organizationId }
24429
- });
25408
+ async function resolveRepositoryIdAuthenticated(organizationId, repoIdentifier) {
25409
+ const result = await authenticatedRequest(
25410
+ (client) => client.repository.listRepositories({
25411
+ params: { organizationId }
25412
+ })
25413
+ );
24430
25414
  if (result.status !== 200) {
24431
25415
  console.error(`Failed to list repositories (status ${result.status}).`);
24432
25416
  process.exit(1);
@@ -24490,7 +25474,7 @@ function printVulnerabilities(vulnerabilities) {
24490
25474
  );
24491
25475
  for (const vuln of sorted) {
24492
25476
  const sev = formatSeverity(vuln.severity);
24493
- const status = vuln.status.toLowerCase().replace("_", " ");
25477
+ const status = formatStatus(vuln.status);
24494
25478
  const repo = vuln.repositoryName;
24495
25479
  const file2 = vuln.codeSnippet.filePath;
24496
25480
  const line = vuln.codeSnippet.startLine;
@@ -24510,7 +25494,7 @@ async function promptContinue(displayed, total) {
24510
25494
  });
24511
25495
  });
24512
25496
  }
24513
- function createListCommand2() {
25497
+ function createListCommand3() {
24514
25498
  return new Command("list").description("List vulnerabilities for your organization").option("--repo <repo>", "Filter by repository name or owner/repo").option(
24515
25499
  "--severity <severity>",
24516
25500
  "Filter by severity (CRITICAL, HIGH, MEDIUM, LOW)",
@@ -24527,12 +25511,10 @@ function createListCommand2() {
24527
25511
  return Math.min(n, 200);
24528
25512
  }).option("--json", "Output as JSON").action(
24529
25513
  async (options) => {
24530
- const { token } = requireAuth();
24531
- const client = createClient(token);
24532
- const organizationId = await resolveOrganizationId(client);
25514
+ const organizationId = await resolveOrganizationId();
24533
25515
  const conditions = [];
24534
25516
  if (options.repo) {
24535
- const repositoryId = await resolveRepositoryId(client, organizationId, options.repo);
25517
+ const repositoryId = await resolveRepositoryIdAuthenticated(organizationId, options.repo);
24536
25518
  conditions.push({ field: "repositoryId", operator: "eq", value: repositoryId });
24537
25519
  }
24538
25520
  if (options.severity) {
@@ -24553,10 +25535,12 @@ function createListCommand2() {
24553
25535
  let total = 0;
24554
25536
  const allJsonVulnerabilities = [];
24555
25537
  while (true) {
24556
- const result = await client.vulnerability.filterVulnerabilities({
24557
- params: { organizationId },
24558
- body: { ...filterBody, page, pageSize }
24559
- });
25538
+ const result = await authenticatedRequest(
25539
+ (client) => client.vulnerability.filterVulnerabilities({
25540
+ params: { organizationId },
25541
+ body: { ...filterBody, page, pageSize }
25542
+ })
25543
+ );
24560
25544
  if (result.status !== 200) {
24561
25545
  console.error(`Failed to list vulnerabilities (status ${result.status}).`);
24562
25546
  process.exit(1);
@@ -24602,7 +25586,7 @@ function createListCommand2() {
24602
25586
  }
24603
25587
  function createVulnerabilitiesCommand() {
24604
25588
  const vulnerabilities = new Command("vulnerabilities").description("Manage vulnerabilities");
24605
- vulnerabilities.addCommand(createListCommand2());
25589
+ vulnerabilities.addCommand(createListCommand3());
24606
25590
  return vulnerabilities;
24607
25591
  }
24608
25592
 
@@ -24616,5 +25600,6 @@ program2.action(() => {
24616
25600
  program2.addCommand(createAuthCommand());
24617
25601
  program2.addCommand(createRepoCommand());
24618
25602
  program2.addCommand(createVulnerabilitiesCommand());
25603
+ program2.addCommand(createPentestCommand());
24619
25604
  program2.addCommand(createCompletionCommand(program2));
24620
25605
  program2.parse();