securewithtrace 0.51.0 → 0.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/bunfig.toml +2 -0
- package/bin/tracecli +14 -4
- package/dist/index.js +1038 -233
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3427,10 +3427,11 @@ var Permission = {
|
|
|
3427
3427
|
VIEW_RESULTS: "VIEW_RESULTS",
|
|
3428
3428
|
EXPORT_ORG_DATA: "EXPORT_ORG_DATA",
|
|
3429
3429
|
DELETE_ORG_DATA: "DELETE_ORG_DATA",
|
|
3430
|
-
|
|
3430
|
+
/** Connecting and configuring third-party integrations. */
|
|
3431
|
+
MANAGE_INTEGRATIONS: "MANAGE_INTEGRATIONS",
|
|
3431
3432
|
MANAGE_INTEGRATED_REPOSITORIES: "MANAGE_INTEGRATED_REPOSITORIES",
|
|
3432
3433
|
MANAGE_USERS: "MANAGE_USERS",
|
|
3433
|
-
/** Invite or remove org members
|
|
3434
|
+
/** Invite or remove org members. Distinct from MANAGE_USERS (role changes, API keys). */
|
|
3434
3435
|
INVITE_USERS: "INVITE_USERS",
|
|
3435
3436
|
MANAGE_ORGANIZATION: "MANAGE_ORGANIZATION",
|
|
3436
3437
|
MANAGE_PENTESTS: "MANAGE_PENTESTS",
|
|
@@ -3440,16 +3441,15 @@ var Permission = {
|
|
|
3440
3441
|
// ../../packages/core/src/auth/permissions.ts
|
|
3441
3442
|
var ROLE_PERMISSIONS = {
|
|
3442
3443
|
[Role.developer]: /* @__PURE__ */ new Set([Permission.RUN_SCAN, Permission.VIEW_RESULTS]),
|
|
3444
|
+
// Shown as Manager: sets up and runs testing. Billing, people and API keys stay admin-only.
|
|
3443
3445
|
[Role.analyst]: /* @__PURE__ */ new Set([
|
|
3444
3446
|
Permission.RUN_SCAN,
|
|
3445
3447
|
Permission.VIEW_RESULTS,
|
|
3446
3448
|
Permission.EXPORT_ORG_DATA,
|
|
3447
3449
|
Permission.MANAGE_INTEGRATED_REPOSITORIES,
|
|
3448
|
-
Permission.
|
|
3449
|
-
Permission.
|
|
3450
|
-
|
|
3451
|
-
// (PR-0b-i M3 / D14). Constant stays in the enum for backward compat
|
|
3452
|
-
// until v2 cleanup; analysts no longer get it.
|
|
3450
|
+
Permission.MANAGE_INTEGRATIONS,
|
|
3451
|
+
Permission.MANAGE_APPLICATIONS,
|
|
3452
|
+
Permission.MANAGE_PENTESTS
|
|
3453
3453
|
]),
|
|
3454
3454
|
[Role.admin]: new Set(Object.values(Permission))
|
|
3455
3455
|
};
|
|
@@ -6283,7 +6283,7 @@ var $ZodBase64 = /* @__PURE__ */ $constructor("$ZodBase64", (inst, def) => {
|
|
|
6283
6283
|
function isValidBase64URL(data) {
|
|
6284
6284
|
if (!base64url.test(data))
|
|
6285
6285
|
return false;
|
|
6286
|
-
const base644 = data.replace(/[-_]/g, (
|
|
6286
|
+
const base644 = data.replace(/[-_]/g, (c86) => c86 === "-" ? "+" : "/");
|
|
6287
6287
|
const padded = base644.padEnd(Math.ceil(base644.length / 4) * 4, "=");
|
|
6288
6288
|
return isValidBase64(padded);
|
|
6289
6289
|
}
|
|
@@ -16327,9 +16327,9 @@ var ZodDate = /* @__PURE__ */ $constructor("ZodDate", (inst, def) => {
|
|
|
16327
16327
|
inst._zod.processJSONSchema = (ctx, json2, params3) => dateProcessor(inst, ctx, json2, params3);
|
|
16328
16328
|
inst.min = (value, params3) => inst.check(_gte(value, params3));
|
|
16329
16329
|
inst.max = (value, params3) => inst.check(_lte(value, params3));
|
|
16330
|
-
const
|
|
16331
|
-
inst.minDate =
|
|
16332
|
-
inst.maxDate =
|
|
16330
|
+
const c86 = inst._zod.bag;
|
|
16331
|
+
inst.minDate = c86.minimum ? new Date(c86.minimum) : null;
|
|
16332
|
+
inst.maxDate = c86.maximum ? new Date(c86.maximum) : null;
|
|
16333
16333
|
});
|
|
16334
16334
|
function date3(params3) {
|
|
16335
16335
|
return _date(ZodDate, params3);
|
|
@@ -17460,6 +17460,7 @@ config(en_default());
|
|
|
17460
17460
|
|
|
17461
17461
|
// ../../packages/core/src/text/prompt-sanitize.ts
|
|
17462
17462
|
var CREDENTIAL_KEY_SOURCE = "password|secret|token|access[_ -]?token|refresh[_ -]?token|cookie|authorization|bearer|api[_ -]?key|private[_ -]?key|session|credential|(?<![A-Za-z])(?:passwd|pwd|pass)";
|
|
17463
|
+
var PROVIDER_KEY_SOURCE = String.raw`\bsk-[A-Za-z0-9_-]{16,}\b`;
|
|
17463
17464
|
var HIGH_ENTROPY_RUN_SOURCE = String.raw`\b(sk-[A-Za-z0-9_-]{16,}|[A-Za-z0-9+/_=-]{40,})\b`;
|
|
17464
17465
|
|
|
17465
17466
|
// ../../packages/core/src/text/evidence-redact.ts
|
|
@@ -17612,14 +17613,16 @@ var SEGMENT = new RegExp(`[A-Za-z0-9_+-]{${MIN_RUN},}`, "g");
|
|
|
17612
17613
|
|
|
17613
17614
|
// ../../packages/core/src/agent-session/versions.ts
|
|
17614
17615
|
var COORDINATOR_TOOLSET_VERSION = "coordinator-tools-v4";
|
|
17615
|
-
var OPERATOR_REVIEW_PROMPT_VERSION = "operator-review-
|
|
17616
|
-
var OPERATOR_REVIEW_FALLBACK_PROMPT_VERSION = "operator-review-
|
|
17616
|
+
var OPERATOR_REVIEW_PROMPT_VERSION = "operator-review-v9";
|
|
17617
|
+
var OPERATOR_REVIEW_FALLBACK_PROMPT_VERSION = "operator-review-v10";
|
|
17617
17618
|
var OPERATOR_REVIEW_V1_PROMPT_VERSION = "operator-review-v1";
|
|
17618
17619
|
var OPERATOR_REVIEW_V2_PROMPT_VERSION = "operator-review-v2";
|
|
17619
17620
|
var OPERATOR_REVIEW_V3_PROMPT_VERSION = "operator-review-v3";
|
|
17620
17621
|
var OPERATOR_REVIEW_V4_PROMPT_VERSION = "operator-review-v4";
|
|
17621
17622
|
var OPERATOR_REVIEW_V5_PROMPT_VERSION = "operator-review-v5";
|
|
17622
17623
|
var OPERATOR_REVIEW_V6_PROMPT_VERSION = "operator-review-v6";
|
|
17624
|
+
var OPERATOR_REVIEW_V7_PROMPT_VERSION = "operator-review-v7";
|
|
17625
|
+
var OPERATOR_REVIEW_V8_PROMPT_VERSION = "operator-review-v8";
|
|
17623
17626
|
var OPERATOR_REVIEW_PROMPT_VERSIONS = [
|
|
17624
17627
|
OPERATOR_REVIEW_V1_PROMPT_VERSION,
|
|
17625
17628
|
OPERATOR_REVIEW_V2_PROMPT_VERSION,
|
|
@@ -17627,6 +17630,8 @@ var OPERATOR_REVIEW_PROMPT_VERSIONS = [
|
|
|
17627
17630
|
OPERATOR_REVIEW_V4_PROMPT_VERSION,
|
|
17628
17631
|
OPERATOR_REVIEW_V5_PROMPT_VERSION,
|
|
17629
17632
|
OPERATOR_REVIEW_V6_PROMPT_VERSION,
|
|
17633
|
+
OPERATOR_REVIEW_V7_PROMPT_VERSION,
|
|
17634
|
+
OPERATOR_REVIEW_V8_PROMPT_VERSION,
|
|
17630
17635
|
OPERATOR_REVIEW_PROMPT_VERSION,
|
|
17631
17636
|
OPERATOR_REVIEW_FALLBACK_PROMPT_VERSION
|
|
17632
17637
|
];
|
|
@@ -17707,7 +17712,14 @@ var ENVIRONMENT_AWARE_PROMPT_VERSIONS = /* @__PURE__ */ new Set([
|
|
|
17707
17712
|
"operator-openai-v26",
|
|
17708
17713
|
"operator-openai-v27",
|
|
17709
17714
|
"operator-openai-v28",
|
|
17710
|
-
"operator-openai-v29"
|
|
17715
|
+
"operator-openai-v29",
|
|
17716
|
+
// The Claude operator pins every provider launches.
|
|
17717
|
+
"operator-v30",
|
|
17718
|
+
"operator-v31",
|
|
17719
|
+
"operator-v32",
|
|
17720
|
+
"operator-v33",
|
|
17721
|
+
"operator-v34",
|
|
17722
|
+
"operator-v35"
|
|
17711
17723
|
]);
|
|
17712
17724
|
var OOB_PROFILE_SUCCESSIONS = [
|
|
17713
17725
|
{
|
|
@@ -18243,6 +18255,16 @@ var REVIEW_OOB_PROFILE_SUCCESSIONS = [
|
|
|
18243
18255
|
toolsetVersion: "operator-tools-v10"
|
|
18244
18256
|
}
|
|
18245
18257
|
},
|
|
18258
|
+
{
|
|
18259
|
+
successor: {
|
|
18260
|
+
promptVersion: OPERATOR_REVIEW_V7_PROMPT_VERSION,
|
|
18261
|
+
toolsetVersion: "operator-tools-v12"
|
|
18262
|
+
},
|
|
18263
|
+
predecessor: {
|
|
18264
|
+
promptVersion: OPERATOR_REVIEW_V8_PROMPT_VERSION,
|
|
18265
|
+
toolsetVersion: "operator-tools-v10"
|
|
18266
|
+
}
|
|
18267
|
+
},
|
|
18246
18268
|
{
|
|
18247
18269
|
successor: {
|
|
18248
18270
|
promptVersion: OPERATOR_REVIEW_PROMPT_VERSION,
|
|
@@ -18284,6 +18306,26 @@ var STAGE_RETIRED_OOB_PROFILE_SUCCESSIONS = [
|
|
|
18284
18306
|
}
|
|
18285
18307
|
}
|
|
18286
18308
|
];
|
|
18309
|
+
var ENVIRONMENT_AWARE_OPERATOR_OOB_PROFILE_SUCCESSIONS = [
|
|
18310
|
+
{
|
|
18311
|
+
successor: { promptVersion: "operator-v30", toolsetVersion: "operator-tools-v14" },
|
|
18312
|
+
predecessor: { promptVersion: "operator-v31", toolsetVersion: "operator-tools-v15" }
|
|
18313
|
+
},
|
|
18314
|
+
{
|
|
18315
|
+
successor: { promptVersion: "operator-v32", toolsetVersion: "operator-tools-v16" },
|
|
18316
|
+
predecessor: { promptVersion: "operator-v31", toolsetVersion: "operator-tools-v15" }
|
|
18317
|
+
}
|
|
18318
|
+
];
|
|
18319
|
+
var ACCOUNT_OPERATOR_OOB_PROFILE_SUCCESSIONS = [
|
|
18320
|
+
{
|
|
18321
|
+
successor: { promptVersion: "operator-v33", toolsetVersion: "operator-tools-v17" },
|
|
18322
|
+
predecessor: { promptVersion: "operator-v34", toolsetVersion: "operator-tools-v18" }
|
|
18323
|
+
},
|
|
18324
|
+
{
|
|
18325
|
+
successor: { promptVersion: "operator-v35", toolsetVersion: "operator-tools-v19" },
|
|
18326
|
+
predecessor: { promptVersion: "operator-v34", toolsetVersion: "operator-tools-v18" }
|
|
18327
|
+
}
|
|
18328
|
+
];
|
|
18287
18329
|
var ALL_OOB_PROFILE_SUCCESSIONS = [
|
|
18288
18330
|
...OOB_PROFILE_SUCCESSIONS,
|
|
18289
18331
|
...STAFF_NOTIFICATION_OOB_PROFILE_SUCCESSIONS,
|
|
@@ -18301,7 +18343,9 @@ var ALL_OOB_PROFILE_SUCCESSIONS = [
|
|
|
18301
18343
|
...VALIDATION_V40_OOB_PROFILE_SUCCESSIONS,
|
|
18302
18344
|
...WRITER_REPRO_OOB_PROFILE_SUCCESSIONS,
|
|
18303
18345
|
...RETEST_REPRO_OOB_PROFILE_SUCCESSIONS,
|
|
18304
|
-
...STAGE_RETIRED_OOB_PROFILE_SUCCESSIONS
|
|
18346
|
+
...STAGE_RETIRED_OOB_PROFILE_SUCCESSIONS,
|
|
18347
|
+
...ENVIRONMENT_AWARE_OPERATOR_OOB_PROFILE_SUCCESSIONS,
|
|
18348
|
+
...ACCOUNT_OPERATOR_OOB_PROFILE_SUCCESSIONS
|
|
18305
18349
|
];
|
|
18306
18350
|
var OOB_CAPABLE_TOOLSETS = new Set(
|
|
18307
18351
|
ALL_OOB_PROFILE_SUCCESSIONS.map(({ successor }) => successor.toolsetVersion)
|
|
@@ -18326,9 +18370,10 @@ var STAFF_NOTIFICATION_TOOLSET_VERSIONS = /* @__PURE__ */ new Set([
|
|
|
18326
18370
|
"report-tools-bsk-v3",
|
|
18327
18371
|
"report-tools-v4",
|
|
18328
18372
|
"report-tools-bsk-v4",
|
|
18329
|
-
// API_COVERAGE_TOOLSET_VERSION and its
|
|
18373
|
+
// API_COVERAGE_TOOLSET_VERSION and its predecessors, written out because they are declared below.
|
|
18330
18374
|
"api-coverage-tools-v1",
|
|
18331
18375
|
"api-coverage-tools-v2",
|
|
18376
|
+
"api-coverage-tools-v3",
|
|
18332
18377
|
// SETUP_TOOLSET_VERSION, written out for the same reason.
|
|
18333
18378
|
"setup-tools-v1",
|
|
18334
18379
|
...STAFF_NOTIFICATION_OOB_PROFILE_SUCCESSIONS.flatMap(({ successor, predecessor }) => [
|
|
@@ -18343,6 +18388,10 @@ var STAFF_NOTIFICATION_TOOLSET_VERSIONS = /* @__PURE__ */ new Set([
|
|
|
18343
18388
|
predecessor.toolsetVersion,
|
|
18344
18389
|
successor.toolsetVersion
|
|
18345
18390
|
]),
|
|
18391
|
+
...ACCOUNT_OPERATOR_OOB_PROFILE_SUCCESSIONS.flatMap(({ successor, predecessor }) => [
|
|
18392
|
+
predecessor.toolsetVersion,
|
|
18393
|
+
successor.toolsetVersion
|
|
18394
|
+
]),
|
|
18346
18395
|
...FEATURE_COVERAGE_OOB_PROFILE_SUCCESSIONS.flatMap(({ successor, predecessor }) => [
|
|
18347
18396
|
predecessor.toolsetVersion,
|
|
18348
18397
|
successor.toolsetVersion
|
|
@@ -23294,8 +23343,8 @@ var CreateAgentSessionRequestSchema = external_exports.discriminatedUnion("type"
|
|
|
23294
23343
|
codeUploadId: AndroidBuildUnderTestSchema,
|
|
23295
23344
|
/**
|
|
23296
23345
|
* REVIEW launches the review session: an operator session that premise-checks every
|
|
23297
|
-
* unpublished finding before its first turn and does not publish.
|
|
23298
|
-
*
|
|
23346
|
+
* unpublished finding before its first turn and does not publish. Its premise checks run on
|
|
23347
|
+
* the session's provider.
|
|
23299
23348
|
*/
|
|
23300
23349
|
purpose: OperatorSessionPurpose.optional()
|
|
23301
23350
|
}),
|
|
@@ -23382,6 +23431,10 @@ var ResumeAgentSessionRequestSchema = external_exports.object({
|
|
|
23382
23431
|
* keeps the row's current target. */
|
|
23383
23432
|
launchTarget: AgentSessionLaunchTarget.optional()
|
|
23384
23433
|
});
|
|
23434
|
+
var SetAgentSessionBudgetRequestSchema = external_exports.object({
|
|
23435
|
+
/** The session's new lifetime ceiling, past spend included. Must exceed recorded spend. */
|
|
23436
|
+
maxUsd: external_exports.number().positive().max(MAX_AGENT_SESSION_MAX_USD)
|
|
23437
|
+
});
|
|
23385
23438
|
var ClaimLocalLaunchResponseSchema = external_exports.object({
|
|
23386
23439
|
agentSessionId: external_exports.uuid(),
|
|
23387
23440
|
runAttemptId: external_exports.uuid(),
|
|
@@ -23592,6 +23645,20 @@ var OperatorPentestContextSchema = external_exports.object({
|
|
|
23592
23645
|
reason: external_exports.string().nullable()
|
|
23593
23646
|
})
|
|
23594
23647
|
),
|
|
23648
|
+
/**
|
|
23649
|
+
* Features excluded from this engagement, read at call time: an exclusion staff add after launch
|
|
23650
|
+
* reaches a running session here, never through its brief. `handle` is `<ordinal>/<slug>`, as
|
|
23651
|
+
* the brief's do-not-test list names it. Optional for the same host raw-cast reason as
|
|
23652
|
+
* `applications`.
|
|
23653
|
+
*/
|
|
23654
|
+
excludedFeatures: external_exports.array(
|
|
23655
|
+
external_exports.object({
|
|
23656
|
+
handle: external_exports.string(),
|
|
23657
|
+
name: external_exports.string(),
|
|
23658
|
+
reason: external_exports.string(),
|
|
23659
|
+
endpoints: external_exports.array(external_exports.string())
|
|
23660
|
+
})
|
|
23661
|
+
).optional(),
|
|
23595
23662
|
// From the session's immutable repository pins (what the agent has checked out).
|
|
23596
23663
|
repositories: external_exports.array(
|
|
23597
23664
|
external_exports.object({
|
|
@@ -23894,6 +23961,22 @@ var agentSessionContract = c2.router({
|
|
|
23894
23961
|
500: ErrorResponseSchema
|
|
23895
23962
|
}
|
|
23896
23963
|
},
|
|
23964
|
+
setBudget: {
|
|
23965
|
+
method: "POST",
|
|
23966
|
+
path: "/organizations/:organizationId/pentests/:pentestId/agent-sessions/:agentSessionId/budget",
|
|
23967
|
+
pathParams: AgentSessionIdParamsSchema,
|
|
23968
|
+
body: SetAgentSessionBudgetRequestSchema,
|
|
23969
|
+
responses: {
|
|
23970
|
+
200: AgentSessionDetailSchema,
|
|
23971
|
+
400: ErrorResponseSchema,
|
|
23972
|
+
401: ErrorResponseSchema,
|
|
23973
|
+
403: ErrorResponseSchema,
|
|
23974
|
+
404: ErrorResponseSchema,
|
|
23975
|
+
// errorCode names the refusal; SESSION_NOT_LIVE means resume with the budget instead.
|
|
23976
|
+
409: ErrorResponseSchema,
|
|
23977
|
+
500: ErrorResponseSchema
|
|
23978
|
+
}
|
|
23979
|
+
},
|
|
23897
23980
|
// The host image this environment's agent-session task definition runs. Reads
|
|
23898
23981
|
// config, mints nothing: it exists so a staff CLI can pull the image BEFORE it
|
|
23899
23982
|
// creates or resumes a LOCAL session, keeping the boot deadline off the pull.
|
|
@@ -25855,7 +25938,7 @@ var CreateLinearTicketsRequestSchema = external_exports.object({
|
|
|
25855
25938
|
findingIds: external_exports.array(external_exports.string().min(1).max(64)).min(1).max(50),
|
|
25856
25939
|
/** Single-finding requests only — a title with >1 finding is a 400. */
|
|
25857
25940
|
title: external_exports.string().min(1).max(255).optional(),
|
|
25858
|
-
/** Destination overrides
|
|
25941
|
+
/** Destination overrides need MANAGE_INTEGRATIONS; anyone else sending one gets a 403. */
|
|
25859
25942
|
teamId: linearEntityId.optional(),
|
|
25860
25943
|
projectId: linearEntityId.nullable().optional(),
|
|
25861
25944
|
labelIds: external_exports.array(linearEntityId).max(10).optional()
|
|
@@ -25913,9 +25996,9 @@ var LinearTicketContextResponseSchema = external_exports.object({
|
|
|
25913
25996
|
labelIds: external_exports.array(external_exports.string()),
|
|
25914
25997
|
labelNames: external_exports.array(external_exports.string())
|
|
25915
25998
|
}).nullable(),
|
|
25916
|
-
/** True only for
|
|
25999
|
+
/** True only for MANAGE_INTEGRATIONS callers; gates the destination picker. */
|
|
25917
26000
|
canOverrideDestination: external_exports.boolean(),
|
|
25918
|
-
/** Populated only
|
|
26001
|
+
/** Populated only when canOverrideDestination; anyone else gets the resolved defaults, not a workspace inventory. */
|
|
25919
26002
|
teams: external_exports.array(TicketContextTeam),
|
|
25920
26003
|
projects: external_exports.array(TicketContextProject),
|
|
25921
26004
|
labels: external_exports.array(TicketContextLabel)
|
|
@@ -28864,13 +28947,13 @@ var StorageStateSchema = external_exports.object({
|
|
|
28864
28947
|
} catch {
|
|
28865
28948
|
return;
|
|
28866
28949
|
}
|
|
28867
|
-
s.cookies.forEach((
|
|
28868
|
-
const d =
|
|
28950
|
+
s.cookies.forEach((c86, i2) => {
|
|
28951
|
+
const d = c86.domain.replace(/^\./, "").toLowerCase();
|
|
28869
28952
|
if (d !== host && !host.endsWith(`.${d}`)) {
|
|
28870
28953
|
ctx.addIssue({
|
|
28871
28954
|
code: "custom",
|
|
28872
28955
|
path: ["cookies", i2, "domain"],
|
|
28873
|
-
message: `cookie domain "${
|
|
28956
|
+
message: `cookie domain "${c86.domain}" is not the capture origin host "${host}" or a parent domain of it`
|
|
28874
28957
|
});
|
|
28875
28958
|
}
|
|
28876
28959
|
});
|
|
@@ -29476,7 +29559,7 @@ var AgentSessionGitSourceGrantSchema = external_exports.object({
|
|
|
29476
29559
|
ref: external_exports.string().min(1).max(255),
|
|
29477
29560
|
/** Immutable pin — the host checks out exactly this commit. */
|
|
29478
29561
|
commitSha: external_exports.string().regex(/^[a-f0-9]{40}$/i),
|
|
29479
|
-
/** Bare clone URL (no credentials — the host
|
|
29562
|
+
/** Bare clone URL (no credentials — the host supplies the token via GIT_ASKPASS). */
|
|
29480
29563
|
cloneUrl: external_exports.url(),
|
|
29481
29564
|
/**
|
|
29482
29565
|
* Short-lived scoped read token. Never logged, never placed in any environ;
|
|
@@ -29485,9 +29568,9 @@ var AgentSessionGitSourceGrantSchema = external_exports.object({
|
|
|
29485
29568
|
*/
|
|
29486
29569
|
cloneToken: external_exports.string().min(1),
|
|
29487
29570
|
/**
|
|
29488
|
-
* Git credential username for the clone
|
|
29489
|
-
*
|
|
29490
|
-
*
|
|
29571
|
+
* Git credential username for the clone: `x-access-token` (GitHub),
|
|
29572
|
+
* `x-token-auth` (Bitbucket) or `oauth2` (GitLab). The token always rides
|
|
29573
|
+
* GIT_ASKPASS, never the URL. The default keeps a pre-Bitbucket host safe — but the host
|
|
29491
29574
|
* raw-casts this response, so the load-bearing fallback is the host's
|
|
29492
29575
|
* use-site default.
|
|
29493
29576
|
*/
|
|
@@ -30435,7 +30518,12 @@ var SessionCredentialsResponseSchema = external_exports.object({
|
|
|
30435
30518
|
browserAllowedBaseUrls: external_exports.array(external_exports.string()),
|
|
30436
30519
|
browserExclusions: external_exports.array(external_exports.string()),
|
|
30437
30520
|
/** API_COVERAGE only; null otherwise. Range checks stay with the host's rate parser. */
|
|
30438
|
-
requestRate: external_exports.object({ perSec: external_exports.number(), burst: external_exports.number() }).nullable()
|
|
30521
|
+
requestRate: external_exports.object({ perSec: external_exports.number(), burst: external_exports.number() }).nullable(),
|
|
30522
|
+
/**
|
|
30523
|
+
* Labels of credentials the resolver could not include this time (a failed decrypt). A host
|
|
30524
|
+
* refreshing mid-run keeps its previous entries for these instead of reading them as deleted.
|
|
30525
|
+
*/
|
|
30526
|
+
skippedLabels: external_exports.array(external_exports.string()).default([])
|
|
30439
30527
|
});
|
|
30440
30528
|
var ConvexReconRequestSchema = external_exports.object({
|
|
30441
30529
|
runVersion: external_exports.number().int().nonnegative()
|
|
@@ -41023,7 +41111,12 @@ var CoverageGridResponseSchema = external_exports.object({
|
|
|
41023
41111
|
orphanFeatures: external_exports.array(CoverageOrphanFeatureSchema).default([]),
|
|
41024
41112
|
unplaced: external_exports.array(CoverageUnplacedRowSchema).default([]),
|
|
41025
41113
|
/** When the engagement started: a feature retired before it is not part of this engagement. */
|
|
41026
|
-
pentestStartedAt: external_exports.coerce.date().nullable().default(null)
|
|
41114
|
+
pentestStartedAt: external_exports.coerce.date().nullable().default(null),
|
|
41115
|
+
/**
|
|
41116
|
+
* When a closed engagement ended; null while it is open. A feature first recorded after it
|
|
41117
|
+
* was never part of this engagement.
|
|
41118
|
+
*/
|
|
41119
|
+
pentestClosedAt: external_exports.coerce.date().nullable().default(null)
|
|
41027
41120
|
});
|
|
41028
41121
|
|
|
41029
41122
|
// ../../packages/api-contracts/src/contracts/v1/pentest-coverage.ts
|
|
@@ -43623,6 +43716,26 @@ var SetStaffOrganizationPentestCustomerVisibilityRequestSchema = external_export
|
|
|
43623
43716
|
var RenameStaffOrganizationPentestRequestSchema = external_exports.object({
|
|
43624
43717
|
title: external_exports.string().trim().min(1, "Title is required").max(500, "Title must be 500 characters or fewer")
|
|
43625
43718
|
}).strict();
|
|
43719
|
+
var SetStaffOrganizationPentestStatusRequestSchema = external_exports.object({
|
|
43720
|
+
status: PentestStatus,
|
|
43721
|
+
reason: external_exports.string().trim().min(1, "Reason cannot be blank").max(2e3, "Reason must be 2000 characters or fewer").optional()
|
|
43722
|
+
}).strict();
|
|
43723
|
+
var CreateStaffPocDraftRequestSchema = external_exports.object({
|
|
43724
|
+
homepageUrl: external_exports.url({ protocol: /^https?$/ }).max(2048).optional()
|
|
43725
|
+
}).strict();
|
|
43726
|
+
var LaunchStaffPocSetupRequestSchema = external_exports.object({
|
|
43727
|
+
notes: external_exports.string().trim().min(1).max(MAX_SETUP_NOTES_CHARS).optional()
|
|
43728
|
+
}).strict();
|
|
43729
|
+
var LaunchStaffPocSetupResponseSchema = external_exports.object({
|
|
43730
|
+
agentSessionId: external_exports.uuid(),
|
|
43731
|
+
/** Null when Slack is not configured in this environment. */
|
|
43732
|
+
slack: external_exports.object({
|
|
43733
|
+
channelId: external_exports.string(),
|
|
43734
|
+
/** Null when Slack did not return the channel's name. */
|
|
43735
|
+
channelName: external_exports.string().nullable(),
|
|
43736
|
+
url: external_exports.url()
|
|
43737
|
+
}).strict().nullable()
|
|
43738
|
+
}).strict();
|
|
43626
43739
|
|
|
43627
43740
|
// ../../packages/api-contracts/src/contracts/v1/staff-pentests.ts
|
|
43628
43741
|
var c58 = initContract();
|
|
@@ -43683,6 +43796,161 @@ var staffPentestsContract = c58.router({
|
|
|
43683
43796
|
500: ErrorResponseSchema
|
|
43684
43797
|
},
|
|
43685
43798
|
summary: "Hide a pentest from the customer or show it again (Trace staff only)"
|
|
43799
|
+
},
|
|
43800
|
+
setStaffOrganizationPentestStatus: {
|
|
43801
|
+
method: "POST",
|
|
43802
|
+
path: "/organizations/:organizationId/staff/pentests/:pentestId/status",
|
|
43803
|
+
pathParams: StaffOrganizationPentestParamsSchema,
|
|
43804
|
+
body: SetStaffOrganizationPentestStatusRequestSchema,
|
|
43805
|
+
responses: {
|
|
43806
|
+
200: StaffOrganizationPentestSummarySchema,
|
|
43807
|
+
400: ErrorResponseSchema,
|
|
43808
|
+
401: ErrorResponseSchema,
|
|
43809
|
+
403: ErrorResponseSchema,
|
|
43810
|
+
404: ErrorResponseSchema,
|
|
43811
|
+
// A lifecycle rule refused the move; the rules and their codes live in
|
|
43812
|
+
// `PentestService.update`.
|
|
43813
|
+
409: ErrorResponseSchema,
|
|
43814
|
+
500: ErrorResponseSchema
|
|
43815
|
+
},
|
|
43816
|
+
summary: "Set a pentest\u2019s lifecycle status from the admin console (Trace staff only)"
|
|
43817
|
+
},
|
|
43818
|
+
createStaffPocDraft: {
|
|
43819
|
+
method: "POST",
|
|
43820
|
+
path: "/organizations/:organizationId/staff/pentests/poc",
|
|
43821
|
+
pathParams: OrgIdParamsSchema,
|
|
43822
|
+
body: CreateStaffPocDraftRequestSchema,
|
|
43823
|
+
// Error codes: StaffPocErrorCodes (staff-pentests.api.ts).
|
|
43824
|
+
responses: {
|
|
43825
|
+
201: StaffOrganizationPentestSummarySchema,
|
|
43826
|
+
400: ErrorResponseSchema,
|
|
43827
|
+
401: ErrorResponseSchema,
|
|
43828
|
+
403: ErrorResponseSchema,
|
|
43829
|
+
404: ErrorResponseSchema,
|
|
43830
|
+
409: ErrorResponseSchema,
|
|
43831
|
+
500: ErrorResponseSchema
|
|
43832
|
+
},
|
|
43833
|
+
summary: "Create a hidden PoC draft engagement (Trace staff only)"
|
|
43834
|
+
},
|
|
43835
|
+
launchStaffPocSetup: {
|
|
43836
|
+
method: "POST",
|
|
43837
|
+
path: "/organizations/:organizationId/staff/pentests/:pentestId/setup-session",
|
|
43838
|
+
pathParams: StaffOrganizationPentestParamsSchema,
|
|
43839
|
+
body: LaunchStaffPocSetupRequestSchema,
|
|
43840
|
+
// Error codes: StaffPocErrorCodes (staff-pentests.api.ts), plus the SETUP launch refusals
|
|
43841
|
+
// (SETUP_REQUIRES_SCOPING, SETUP_AFTER_TESTING_STARTED) and a 429 at the session cap.
|
|
43842
|
+
responses: {
|
|
43843
|
+
201: LaunchStaffPocSetupResponseSchema,
|
|
43844
|
+
400: ErrorResponseSchema,
|
|
43845
|
+
401: ErrorResponseSchema,
|
|
43846
|
+
403: ErrorResponseSchema,
|
|
43847
|
+
404: ErrorResponseSchema,
|
|
43848
|
+
409: ErrorResponseSchema,
|
|
43849
|
+
429: ErrorResponseSchema,
|
|
43850
|
+
500: ErrorResponseSchema,
|
|
43851
|
+
503: ErrorResponseSchema
|
|
43852
|
+
},
|
|
43853
|
+
summary: "Bind a PoC engagement's Slack and launch its SETUP session (Trace staff only)"
|
|
43854
|
+
}
|
|
43855
|
+
});
|
|
43856
|
+
|
|
43857
|
+
// ../../packages/api-contracts/src/schemas/api/v1/staff-products.api.ts
|
|
43858
|
+
var StaffProductParamsSchema = OrgIdParamsSchema.extend({
|
|
43859
|
+
productGroupId: external_exports.uuid()
|
|
43860
|
+
});
|
|
43861
|
+
var StaffProductApplicationParamsSchema = OrgIdParamsSchema.extend({
|
|
43862
|
+
applicationId: external_exports.uuid()
|
|
43863
|
+
});
|
|
43864
|
+
var PRODUCT_NAME_MAX_CHARS = 200;
|
|
43865
|
+
var ProductNameSchema = external_exports.string().trim().min(1).max(PRODUCT_NAME_MAX_CHARS);
|
|
43866
|
+
var StaffProductApplicationSchema = external_exports.object({
|
|
43867
|
+
applicationId: external_exports.uuid(),
|
|
43868
|
+
name: external_exports.string(),
|
|
43869
|
+
type: external_exports.enum(ApplicationTypeValues),
|
|
43870
|
+
/** Tells same-named applications apart; null for types without a URL. */
|
|
43871
|
+
applicationUrl: external_exports.string().nullable(),
|
|
43872
|
+
/** Applications this one uses, sorted by their name. */
|
|
43873
|
+
uses: external_exports.array(external_exports.uuid())
|
|
43874
|
+
}).strict();
|
|
43875
|
+
var StaffProductSchema = external_exports.object({
|
|
43876
|
+
productGroupId: external_exports.uuid(),
|
|
43877
|
+
name: external_exports.string(),
|
|
43878
|
+
applications: external_exports.array(StaffProductApplicationSchema)
|
|
43879
|
+
}).strict();
|
|
43880
|
+
var StaffProductsResponseSchema = external_exports.object({
|
|
43881
|
+
products: external_exports.array(StaffProductSchema)
|
|
43882
|
+
}).strict();
|
|
43883
|
+
var RenameStaffProductRequestSchema = external_exports.object({ name: ProductNameSchema }).strict();
|
|
43884
|
+
var MoveStaffApplicationRequestSchema = external_exports.union([
|
|
43885
|
+
external_exports.object({ productGroupId: external_exports.uuid() }).strict(),
|
|
43886
|
+
external_exports.object({ newProductName: ProductNameSchema }).strict()
|
|
43887
|
+
]);
|
|
43888
|
+
var SetStaffApplicationDependenciesRequestSchema = external_exports.object({
|
|
43889
|
+
toApplicationIds: external_exports.array(external_exports.uuid()).max(100).refine((ids) => new Set(ids).size === ids.length, {
|
|
43890
|
+
message: "Application ids must be unique"
|
|
43891
|
+
})
|
|
43892
|
+
}).strict();
|
|
43893
|
+
|
|
43894
|
+
// ../../packages/api-contracts/src/contracts/v1/staff-products.ts
|
|
43895
|
+
var c59 = initContract();
|
|
43896
|
+
var staffProductsContract = c59.router({
|
|
43897
|
+
listStaffProducts: {
|
|
43898
|
+
method: "GET",
|
|
43899
|
+
path: "/organizations/:organizationId/staff/products",
|
|
43900
|
+
pathParams: OrgIdParamsSchema,
|
|
43901
|
+
responses: {
|
|
43902
|
+
200: StaffProductsResponseSchema,
|
|
43903
|
+
401: ErrorResponseSchema,
|
|
43904
|
+
403: ErrorResponseSchema,
|
|
43905
|
+
404: ErrorResponseSchema,
|
|
43906
|
+
500: ErrorResponseSchema
|
|
43907
|
+
},
|
|
43908
|
+
summary: "List an organization\u2019s products and their applications (Trace staff only)"
|
|
43909
|
+
},
|
|
43910
|
+
renameStaffProduct: {
|
|
43911
|
+
method: "PATCH",
|
|
43912
|
+
path: "/organizations/:organizationId/staff/products/:productGroupId",
|
|
43913
|
+
pathParams: StaffProductParamsSchema,
|
|
43914
|
+
body: RenameStaffProductRequestSchema,
|
|
43915
|
+
responses: {
|
|
43916
|
+
200: StaffProductsResponseSchema,
|
|
43917
|
+
400: ErrorResponseSchema,
|
|
43918
|
+
401: ErrorResponseSchema,
|
|
43919
|
+
403: ErrorResponseSchema,
|
|
43920
|
+
404: ErrorResponseSchema,
|
|
43921
|
+
500: ErrorResponseSchema
|
|
43922
|
+
},
|
|
43923
|
+
summary: "Rename a product (Trace staff only)"
|
|
43924
|
+
},
|
|
43925
|
+
moveStaffApplication: {
|
|
43926
|
+
method: "PUT",
|
|
43927
|
+
path: "/organizations/:organizationId/staff/applications/:applicationId/product",
|
|
43928
|
+
pathParams: StaffProductApplicationParamsSchema,
|
|
43929
|
+
body: MoveStaffApplicationRequestSchema,
|
|
43930
|
+
responses: {
|
|
43931
|
+
200: StaffProductsResponseSchema,
|
|
43932
|
+
400: ErrorResponseSchema,
|
|
43933
|
+
401: ErrorResponseSchema,
|
|
43934
|
+
403: ErrorResponseSchema,
|
|
43935
|
+
404: ErrorResponseSchema,
|
|
43936
|
+
500: ErrorResponseSchema
|
|
43937
|
+
},
|
|
43938
|
+
summary: "Move an application into another or a new product (Trace staff only)"
|
|
43939
|
+
},
|
|
43940
|
+
setStaffApplicationDependencies: {
|
|
43941
|
+
method: "PUT",
|
|
43942
|
+
path: "/organizations/:organizationId/staff/applications/:applicationId/dependencies",
|
|
43943
|
+
pathParams: StaffProductApplicationParamsSchema,
|
|
43944
|
+
body: SetStaffApplicationDependenciesRequestSchema,
|
|
43945
|
+
responses: {
|
|
43946
|
+
200: StaffProductsResponseSchema,
|
|
43947
|
+
400: ErrorResponseSchema,
|
|
43948
|
+
401: ErrorResponseSchema,
|
|
43949
|
+
403: ErrorResponseSchema,
|
|
43950
|
+
404: ErrorResponseSchema,
|
|
43951
|
+
500: ErrorResponseSchema
|
|
43952
|
+
},
|
|
43953
|
+
summary: "Replace the applications an application uses (Trace staff only)"
|
|
43686
43954
|
}
|
|
43687
43955
|
});
|
|
43688
43956
|
|
|
@@ -43793,8 +44061,8 @@ var StaffQueueResponseSchema = external_exports.object({
|
|
|
43793
44061
|
}).strict();
|
|
43794
44062
|
|
|
43795
44063
|
// ../../packages/api-contracts/src/contracts/v1/staff-queue.ts
|
|
43796
|
-
var
|
|
43797
|
-
var staffQueueContract =
|
|
44064
|
+
var c60 = initContract();
|
|
44065
|
+
var staffQueueContract = c60.router({
|
|
43798
44066
|
getStaffQueue: {
|
|
43799
44067
|
method: "GET",
|
|
43800
44068
|
path: "/staff/queue",
|
|
@@ -43858,8 +44126,8 @@ var UpdateTestIntegrationRequestSchema = external_exports.object({
|
|
|
43858
44126
|
}).strict();
|
|
43859
44127
|
|
|
43860
44128
|
// ../../packages/api-contracts/src/contracts/v1/test-integration.ts
|
|
43861
|
-
var
|
|
43862
|
-
var testIntegrationContract =
|
|
44129
|
+
var c61 = initContract();
|
|
44130
|
+
var testIntegrationContract = c61.router({
|
|
43863
44131
|
// -- Fixture CRUD (org-less, staff-only) ----------------------------------
|
|
43864
44132
|
listTestIntegrations: {
|
|
43865
44133
|
method: "GET",
|
|
@@ -43939,7 +44207,7 @@ var testIntegrationContract = c60.router({
|
|
|
43939
44207
|
method: "POST",
|
|
43940
44208
|
path: "/staff/test-integrations/:testIntegrationId/mfa/code",
|
|
43941
44209
|
pathParams: TestIntegrationIdParamsSchema,
|
|
43942
|
-
body:
|
|
44210
|
+
body: c61.noBody(),
|
|
43943
44211
|
responses: {
|
|
43944
44212
|
200: CredentialMfaCodeResponseSchema,
|
|
43945
44213
|
401: ErrorResponseSchema,
|
|
@@ -44050,8 +44318,8 @@ var MyContextResponseSchema = external_exports.object({
|
|
|
44050
44318
|
});
|
|
44051
44319
|
|
|
44052
44320
|
// ../../packages/api-contracts/src/contracts/v1/user.ts
|
|
44053
|
-
var
|
|
44054
|
-
var userContract =
|
|
44321
|
+
var c62 = initContract();
|
|
44322
|
+
var userContract = c62.router({
|
|
44055
44323
|
getStaffProfile: {
|
|
44056
44324
|
method: "GET",
|
|
44057
44325
|
path: "/staff/profile",
|
|
@@ -44166,8 +44434,8 @@ var VantaIntegrationResponseSchema = external_exports.object({
|
|
|
44166
44434
|
});
|
|
44167
44435
|
|
|
44168
44436
|
// ../../packages/api-contracts/src/contracts/v1/vanta-integration.ts
|
|
44169
|
-
var
|
|
44170
|
-
var vantaIntegrationContract =
|
|
44437
|
+
var c63 = initContract();
|
|
44438
|
+
var vantaIntegrationContract = c63.router({
|
|
44171
44439
|
createVantaIntegration: {
|
|
44172
44440
|
method: "POST",
|
|
44173
44441
|
path: "/organizations/:organizationId/vanta-integration",
|
|
@@ -44528,8 +44796,8 @@ var VerifySharedVulnerabilityEmailCodeResponseSchema = external_exports.object({
|
|
|
44528
44796
|
});
|
|
44529
44797
|
|
|
44530
44798
|
// ../../packages/api-contracts/src/contracts/v1/vulnerability.ts
|
|
44531
|
-
var
|
|
44532
|
-
var vulnerabilityContract =
|
|
44799
|
+
var c64 = initContract();
|
|
44800
|
+
var vulnerabilityContract = c64.router({
|
|
44533
44801
|
filterVulnerabilities: {
|
|
44534
44802
|
method: "POST",
|
|
44535
44803
|
path: "/organizations/:organizationId/vulnerabilities/filter",
|
|
@@ -44754,8 +45022,8 @@ var UpdateVulnerabilityNoteRequestSchema = external_exports.object({
|
|
|
44754
45022
|
});
|
|
44755
45023
|
|
|
44756
45024
|
// ../../packages/api-contracts/src/contracts/v1/vulnerability-note.ts
|
|
44757
|
-
var
|
|
44758
|
-
var vulnerabilityNoteContract =
|
|
45025
|
+
var c65 = initContract();
|
|
45026
|
+
var vulnerabilityNoteContract = c65.router({
|
|
44759
45027
|
listNotes: {
|
|
44760
45028
|
method: "GET",
|
|
44761
45029
|
path: "/organizations/:organizationId/vulnerabilities/:vulnerabilityId/notes",
|
|
@@ -44936,8 +45204,8 @@ var ListWebhookDeliveriesResponseSchema = external_exports.object({
|
|
|
44936
45204
|
});
|
|
44937
45205
|
|
|
44938
45206
|
// ../../packages/api-contracts/src/contracts/v1/webhook-settings.ts
|
|
44939
|
-
var
|
|
44940
|
-
var webhookSettingsContract =
|
|
45207
|
+
var c66 = initContract();
|
|
45208
|
+
var webhookSettingsContract = c66.router({
|
|
44941
45209
|
listWebhookEndpoints: {
|
|
44942
45210
|
method: "GET",
|
|
44943
45211
|
path: "/organizations/:organizationId/webhook-settings/endpoints",
|
|
@@ -45074,9 +45342,31 @@ var webhookSettingsContract = c65.router({
|
|
|
45074
45342
|
}
|
|
45075
45343
|
});
|
|
45076
45344
|
|
|
45345
|
+
// ../../packages/api-contracts/src/contracts/v1/ws.ts
|
|
45346
|
+
var c67 = initContract();
|
|
45347
|
+
var WsTicketResponseSchema = external_exports.object({
|
|
45348
|
+
/** Opaque, single-use, bound to the caller and the request's organization. */
|
|
45349
|
+
ticket: external_exports.string(),
|
|
45350
|
+
expiresInSeconds: external_exports.number().int().positive()
|
|
45351
|
+
});
|
|
45352
|
+
var wsContract = c67.router({
|
|
45353
|
+
createTicket: {
|
|
45354
|
+
method: "POST",
|
|
45355
|
+
path: "/ws/ticket",
|
|
45356
|
+
body: c67.noBody(),
|
|
45357
|
+
responses: {
|
|
45358
|
+
200: WsTicketResponseSchema,
|
|
45359
|
+
401: ErrorResponseSchema,
|
|
45360
|
+
403: ErrorResponseSchema,
|
|
45361
|
+
503: ErrorResponseSchema
|
|
45362
|
+
},
|
|
45363
|
+
summary: "Mint a short-lived, single-use ticket that opens the scan-updates WebSocket"
|
|
45364
|
+
}
|
|
45365
|
+
});
|
|
45366
|
+
|
|
45077
45367
|
// ../../packages/api-contracts/src/contracts/v1/index.ts
|
|
45078
|
-
var
|
|
45079
|
-
var v1Contract =
|
|
45368
|
+
var c68 = initContract();
|
|
45369
|
+
var v1Contract = c68.router(
|
|
45080
45370
|
{
|
|
45081
45371
|
admin: adminContract,
|
|
45082
45372
|
cloudIntegration: cloudIntegrationContract,
|
|
@@ -45086,6 +45376,7 @@ var v1Contract = c66.router(
|
|
|
45086
45376
|
organization: organizationContract,
|
|
45087
45377
|
oobListener: oobListenerContract,
|
|
45088
45378
|
user: userContract,
|
|
45379
|
+
ws: wsContract,
|
|
45089
45380
|
repository: repositoryContract,
|
|
45090
45381
|
github: githubContract,
|
|
45091
45382
|
staffGithub: staffGithubContract,
|
|
@@ -45141,6 +45432,7 @@ var v1Contract = c66.router(
|
|
|
45141
45432
|
staffPentestStats: staffPentestStatsContract,
|
|
45142
45433
|
staffKnowledgeFacts: staffKnowledgeFactsContract,
|
|
45143
45434
|
staffPentests: staffPentestsContract,
|
|
45435
|
+
staffProducts: staffProductsContract,
|
|
45144
45436
|
staffQueue: staffQueueContract,
|
|
45145
45437
|
organizationDisposal: organizationDisposalContract
|
|
45146
45438
|
},
|
|
@@ -45150,13 +45442,13 @@ var v1Contract = c66.router(
|
|
|
45150
45442
|
);
|
|
45151
45443
|
|
|
45152
45444
|
// ../../packages/api-contracts/src/contracts/index.ts
|
|
45153
|
-
var
|
|
45154
|
-
var contract =
|
|
45445
|
+
var c69 = initContract();
|
|
45446
|
+
var contract = c69.router({
|
|
45155
45447
|
v1: v1Contract
|
|
45156
45448
|
});
|
|
45157
45449
|
|
|
45158
45450
|
// ../../packages/api-contracts/src/contracts/v1/desktop-host-internal.ts
|
|
45159
|
-
var
|
|
45451
|
+
var c70 = initContract();
|
|
45160
45452
|
var MAX_VMS_PER_SYNC = 16;
|
|
45161
45453
|
var DesktopHostSyncRequestSchema = external_exports.object({
|
|
45162
45454
|
/** Integer protocol the runner speaks. Below the api's minimum, the host gets
|
|
@@ -45181,7 +45473,7 @@ var DesktopHostSyncResponseSchema = external_exports.object({
|
|
|
45181
45473
|
* id not listed here is deleted. */
|
|
45182
45474
|
targets: external_exports.array(DesktopHostSyncTargetSchema).max(MAX_VMS_PER_SYNC)
|
|
45183
45475
|
});
|
|
45184
|
-
var desktopHostInternalContract =
|
|
45476
|
+
var desktopHostInternalContract = c70.router({
|
|
45185
45477
|
sync: {
|
|
45186
45478
|
method: "POST",
|
|
45187
45479
|
path: "/internal/v1/desktop-hosts/sync",
|
|
@@ -45204,7 +45496,10 @@ var OPENAI_SESSION_TYPES = [
|
|
|
45204
45496
|
"RETEST",
|
|
45205
45497
|
"REPORT",
|
|
45206
45498
|
"RECON",
|
|
45207
|
-
"API_COVERAGE"
|
|
45499
|
+
"API_COVERAGE",
|
|
45500
|
+
"PRODUCT_RECON",
|
|
45501
|
+
"CODE_REVIEW",
|
|
45502
|
+
"REMEDIATION"
|
|
45208
45503
|
];
|
|
45209
45504
|
var AGENT_SESSION_MODELS = [
|
|
45210
45505
|
{
|
|
@@ -45278,8 +45573,8 @@ var GitHubWebhookResponseSchema = external_exports.object({
|
|
|
45278
45573
|
});
|
|
45279
45574
|
|
|
45280
45575
|
// ../../packages/api-contracts/src/contracts/webhooks/github.ts
|
|
45281
|
-
var
|
|
45282
|
-
var githubWebhookContract =
|
|
45576
|
+
var c71 = initContract();
|
|
45577
|
+
var githubWebhookContract = c71.router(
|
|
45283
45578
|
{
|
|
45284
45579
|
handleWebhook: {
|
|
45285
45580
|
method: "POST",
|
|
@@ -45297,7 +45592,7 @@ var githubWebhookContract = c69.router(
|
|
|
45297
45592
|
pathPrefix: "/webhooks"
|
|
45298
45593
|
}
|
|
45299
45594
|
);
|
|
45300
|
-
var githubReadonlyWebhookContract =
|
|
45595
|
+
var githubReadonlyWebhookContract = c71.router(
|
|
45301
45596
|
{
|
|
45302
45597
|
handleWebhook: {
|
|
45303
45598
|
method: "POST",
|
|
@@ -45317,9 +45612,9 @@ var githubReadonlyWebhookContract = c69.router(
|
|
|
45317
45612
|
);
|
|
45318
45613
|
|
|
45319
45614
|
// ../../packages/api-contracts/src/contracts/webhooks/linear.ts
|
|
45320
|
-
var
|
|
45615
|
+
var c72 = initContract();
|
|
45321
45616
|
var LinearWebhookResponseSchema = external_exports.object({ ok: external_exports.boolean() });
|
|
45322
|
-
var linearWebhookContract =
|
|
45617
|
+
var linearWebhookContract = c72.router(
|
|
45323
45618
|
{
|
|
45324
45619
|
handleWebhook: {
|
|
45325
45620
|
method: "POST",
|
|
@@ -45339,7 +45634,7 @@ var linearWebhookContract = c70.router(
|
|
|
45339
45634
|
);
|
|
45340
45635
|
|
|
45341
45636
|
// ../../packages/api-contracts/src/contracts/forge/bitbucket.ts
|
|
45342
|
-
var
|
|
45637
|
+
var c73 = initContract();
|
|
45343
45638
|
var InstallEventSchema = external_exports.object({
|
|
45344
45639
|
eventType: external_exports.enum(["avi:forge:installed:app", "avi:forge:upgraded:app"]),
|
|
45345
45640
|
context: external_exports.object({ cloudId: external_exports.string().min(1) }).loose(),
|
|
@@ -45368,7 +45663,7 @@ var ForgePairingCodeResponseSchema = external_exports.discriminatedUnion("state"
|
|
|
45368
45663
|
expiresInSeconds: external_exports.number().int()
|
|
45369
45664
|
})
|
|
45370
45665
|
]);
|
|
45371
|
-
var forgeBitbucketContract =
|
|
45666
|
+
var forgeBitbucketContract = c73.router(
|
|
45372
45667
|
{
|
|
45373
45668
|
lifecycle: {
|
|
45374
45669
|
method: "POST",
|
|
@@ -45415,8 +45710,8 @@ var HealthResponseSchema = external_exports.object({
|
|
|
45415
45710
|
});
|
|
45416
45711
|
|
|
45417
45712
|
// ../../packages/api-contracts/src/contracts/health.ts
|
|
45418
|
-
var
|
|
45419
|
-
var healthContract =
|
|
45713
|
+
var c74 = initContract();
|
|
45714
|
+
var healthContract = c74.router({
|
|
45420
45715
|
getHealth: {
|
|
45421
45716
|
method: "GET",
|
|
45422
45717
|
path: "/health",
|
|
@@ -45428,8 +45723,8 @@ var healthContract = c72.router({
|
|
|
45428
45723
|
});
|
|
45429
45724
|
|
|
45430
45725
|
// ../../packages/api-contracts/src/contracts/v1/vulnerability-share.ts
|
|
45431
|
-
var
|
|
45432
|
-
var vulnerabilityShareContract =
|
|
45726
|
+
var c75 = initContract();
|
|
45727
|
+
var vulnerabilityShareContract = c75.router(
|
|
45433
45728
|
{
|
|
45434
45729
|
resolveShareLink: {
|
|
45435
45730
|
method: "GET",
|
|
@@ -45455,7 +45750,8 @@ var vulnerabilityShareContract = c73.router(
|
|
|
45455
45750
|
401: ErrorResponseSchema,
|
|
45456
45751
|
403: ErrorResponseSchema,
|
|
45457
45752
|
404: ErrorResponseSchema,
|
|
45458
|
-
500: ErrorResponseSchema
|
|
45753
|
+
500: ErrorResponseSchema,
|
|
45754
|
+
503: ErrorResponseSchema
|
|
45459
45755
|
}
|
|
45460
45756
|
},
|
|
45461
45757
|
verifyShareEmailCode: {
|
|
@@ -45479,8 +45775,8 @@ var vulnerabilityShareContract = c73.router(
|
|
|
45479
45775
|
);
|
|
45480
45776
|
|
|
45481
45777
|
// ../../packages/api-contracts/src/contracts/v1/attestation-verify.ts
|
|
45482
|
-
var
|
|
45483
|
-
var attestationVerifyContract =
|
|
45778
|
+
var c76 = initContract();
|
|
45779
|
+
var attestationVerifyContract = c76.router(
|
|
45484
45780
|
{
|
|
45485
45781
|
verifyAttestation: {
|
|
45486
45782
|
method: "GET",
|
|
@@ -45536,8 +45832,8 @@ var UpdatePrVulnerabilityRequestSchema = external_exports.object({
|
|
|
45536
45832
|
});
|
|
45537
45833
|
|
|
45538
45834
|
// ../../packages/api-contracts/src/contracts/v1/pr-vulnerability.ts
|
|
45539
|
-
var
|
|
45540
|
-
var prVulnerabilityContract =
|
|
45835
|
+
var c77 = initContract();
|
|
45836
|
+
var prVulnerabilityContract = c77.router(
|
|
45541
45837
|
{
|
|
45542
45838
|
listPrVulnerabilities: {
|
|
45543
45839
|
method: "GET",
|
|
@@ -45701,8 +45997,8 @@ var CoordinatorSessionSearchResponseSchema = external_exports.strictObject({
|
|
|
45701
45997
|
});
|
|
45702
45998
|
|
|
45703
45999
|
// ../../packages/api-contracts/src/contracts/v1/coordinator-inspection.ts
|
|
45704
|
-
var
|
|
45705
|
-
var coordinatorInspectionContract =
|
|
46000
|
+
var c78 = initContract();
|
|
46001
|
+
var coordinatorInspectionContract = c78.router({
|
|
45706
46002
|
sessionWindow: {
|
|
45707
46003
|
method: "POST",
|
|
45708
46004
|
path: "/internal/v1/agent-sessions/:agentSessionId/coordinator/session-window",
|
|
@@ -45744,7 +46040,7 @@ var coordinatorInspectionContract = c76.router({
|
|
|
45744
46040
|
});
|
|
45745
46041
|
|
|
45746
46042
|
// ../../packages/api-contracts/src/contracts/v1/pentest-coordinator-internal.ts
|
|
45747
|
-
var
|
|
46043
|
+
var c79 = initContract();
|
|
45748
46044
|
var params2 = external_exports.strictObject({ agentSessionId: external_exports.uuid() });
|
|
45749
46045
|
var errors3 = {
|
|
45750
46046
|
400: ErrorResponseSchema,
|
|
@@ -45757,7 +46053,7 @@ var errors3 = {
|
|
|
45757
46053
|
500: ErrorResponseSchema,
|
|
45758
46054
|
503: ErrorResponseSchema
|
|
45759
46055
|
};
|
|
45760
|
-
var pentestCoordinatorInternalContract =
|
|
46056
|
+
var pentestCoordinatorInternalContract = c79.router({
|
|
45761
46057
|
state: {
|
|
45762
46058
|
method: "POST",
|
|
45763
46059
|
path: "/internal/v1/agent-sessions/:agentSessionId/coordinator/state",
|
|
@@ -46004,8 +46300,8 @@ var CoordinatorCoverageResponseSchema = external_exports.strictObject({
|
|
|
46004
46300
|
);
|
|
46005
46301
|
|
|
46006
46302
|
// ../../packages/api-contracts/src/contracts/v1/coordinator-domain-read.ts
|
|
46007
|
-
var
|
|
46008
|
-
var coordinatorDomainReadContract =
|
|
46303
|
+
var c80 = initContract();
|
|
46304
|
+
var coordinatorDomainReadContract = c80.router({
|
|
46009
46305
|
coverage: {
|
|
46010
46306
|
method: "POST",
|
|
46011
46307
|
path: "/internal/v1/agent-sessions/:agentSessionId/coordinator/coverage",
|
|
@@ -46210,7 +46506,7 @@ var CoordinatorPublicDocumentationResponseSchema = CoordinatorContextTextReadRes
|
|
|
46210
46506
|
var CoordinatorCustomerDocumentResponseSchema = CoordinatorContextTextReadResponseSchema;
|
|
46211
46507
|
|
|
46212
46508
|
// ../../packages/api-contracts/src/contracts/v1/coordinator-context-read.ts
|
|
46213
|
-
var
|
|
46509
|
+
var c81 = initContract();
|
|
46214
46510
|
var errors4 = {
|
|
46215
46511
|
400: ErrorResponseSchema,
|
|
46216
46512
|
401: ErrorResponseSchema,
|
|
@@ -46222,7 +46518,7 @@ var errors4 = {
|
|
|
46222
46518
|
500: ErrorResponseSchema,
|
|
46223
46519
|
503: ErrorResponseSchema
|
|
46224
46520
|
};
|
|
46225
|
-
var coordinatorContextReadContract =
|
|
46521
|
+
var coordinatorContextReadContract = c81.router({
|
|
46226
46522
|
contextSources: {
|
|
46227
46523
|
method: "POST",
|
|
46228
46524
|
path: "/internal/v1/agent-sessions/:agentSessionId/coordinator/context-sources",
|
|
@@ -46456,19 +46752,19 @@ var COVERAGE_CLASSES = [
|
|
|
46456
46752
|
},
|
|
46457
46753
|
{ taxonomy: "RECON", id: "RECON-15", name: "Deployment-platform config", shortLabel: "Deploy" }
|
|
46458
46754
|
];
|
|
46459
|
-
var BY_ID = new Map(COVERAGE_CLASSES.map((
|
|
46755
|
+
var BY_ID = new Map(COVERAGE_CLASSES.map((c86) => [c86.id, c86]));
|
|
46460
46756
|
function idsWhere(keep) {
|
|
46461
|
-
return [OTHER_CLASS_ID, ...COVERAGE_CLASSES.filter(keep).map((
|
|
46757
|
+
return [OTHER_CLASS_ID, ...COVERAGE_CLASSES.filter(keep).map((c86) => c86.id)];
|
|
46462
46758
|
}
|
|
46463
|
-
var HUNTING_CLASS_IDS = idsWhere((
|
|
46464
|
-
var RECON_CLASS_IDS = idsWhere((
|
|
46759
|
+
var HUNTING_CLASS_IDS = idsWhere((c86) => c86.taxonomy !== "RECON");
|
|
46760
|
+
var RECON_CLASS_IDS = idsWhere((c86) => c86.taxonomy === "RECON");
|
|
46465
46761
|
var HUNTING_ID_SET = new Set(HUNTING_CLASS_IDS);
|
|
46466
46762
|
var RECON_ID_SET = new Set(RECON_CLASS_IDS);
|
|
46467
46763
|
var TAXONOMY_ORDER = new Map(CoverageTaxonomyValues.map((t2, i2) => [t2, i2]));
|
|
46468
|
-
var CLASS_ORDER = new Map(COVERAGE_CLASSES.map((
|
|
46764
|
+
var CLASS_ORDER = new Map(COVERAGE_CLASSES.map((c86, i2) => [c86.id, i2]));
|
|
46469
46765
|
|
|
46470
46766
|
// ../../packages/api-contracts/src/contracts/v1/api-coverage-internal.ts
|
|
46471
|
-
var
|
|
46767
|
+
var c82 = initContract();
|
|
46472
46768
|
var pathParams = external_exports.strictObject({ agentSessionId: external_exports.uuid() });
|
|
46473
46769
|
var errors5 = {
|
|
46474
46770
|
400: ErrorResponseSchema,
|
|
@@ -46478,7 +46774,7 @@ var errors5 = {
|
|
|
46478
46774
|
500: ErrorResponseSchema
|
|
46479
46775
|
};
|
|
46480
46776
|
var base = "/internal/v1/agent-sessions/:agentSessionId/api-coverage";
|
|
46481
|
-
var apiCoverageInternalContract =
|
|
46777
|
+
var apiCoverageInternalContract = c82.router({
|
|
46482
46778
|
upsertApiOperations: {
|
|
46483
46779
|
method: "POST",
|
|
46484
46780
|
path: `${base}/operations`,
|
|
@@ -46617,7 +46913,7 @@ var SetupNotesRequestSchema = external_exports.object({ runVersion: RunVersionSc
|
|
|
46617
46913
|
var SetupNotesResponseSchema = external_exports.object({ notes: external_exports.string().nullable() });
|
|
46618
46914
|
|
|
46619
46915
|
// ../../packages/api-contracts/src/contracts/v1/setup-session-internal.ts
|
|
46620
|
-
var
|
|
46916
|
+
var c83 = initContract();
|
|
46621
46917
|
var pathParams2 = external_exports.strictObject({ agentSessionId: external_exports.uuid() });
|
|
46622
46918
|
var errors6 = {
|
|
46623
46919
|
400: ErrorResponseSchema,
|
|
@@ -46629,7 +46925,7 @@ var errors6 = {
|
|
|
46629
46925
|
503: ErrorResponseSchema
|
|
46630
46926
|
};
|
|
46631
46927
|
var base2 = "/internal/v1/agent-sessions/:agentSessionId/setup";
|
|
46632
|
-
var setupSessionInternalContract =
|
|
46928
|
+
var setupSessionInternalContract = c83.router({
|
|
46633
46929
|
addSetupTarget: {
|
|
46634
46930
|
method: "POST",
|
|
46635
46931
|
path: `${base2}/target`,
|
|
@@ -46756,8 +47052,8 @@ var ListReviewPremiseChecksResponseSchema = external_exports.object({
|
|
|
46756
47052
|
});
|
|
46757
47053
|
|
|
46758
47054
|
// ../../packages/api-contracts/src/contracts/v1/premise-check-internal.ts
|
|
46759
|
-
var
|
|
46760
|
-
var premiseCheckInternalContract =
|
|
47055
|
+
var c84 = initContract();
|
|
47056
|
+
var premiseCheckInternalContract = c84.router({
|
|
46761
47057
|
listReviewPremiseChecks: {
|
|
46762
47058
|
method: "POST",
|
|
46763
47059
|
path: "/internal/v1/agent-sessions/:agentSessionId/premise-checks/list",
|
|
@@ -47581,6 +47877,7 @@ var PRODUCTION_API_URL = "https://api.securewithtrace.com";
|
|
|
47581
47877
|
var UNAUTHORIZED_STATUS = 401;
|
|
47582
47878
|
var REFRESH_AUTH_FAILURE_STATUS_CODES = /* @__PURE__ */ new Set([400, 401]);
|
|
47583
47879
|
var MAX_REFRESH_ROTATION_RETRIES = 3;
|
|
47880
|
+
var TRACE_API_HOST_SUFFIX = ".securewithtrace.com";
|
|
47584
47881
|
function getApiBaseUrl() {
|
|
47585
47882
|
const raw = process.env["TRACE_API_URL"];
|
|
47586
47883
|
if (!raw) {
|
|
@@ -47599,16 +47896,15 @@ function getApiBaseUrl() {
|
|
|
47599
47896
|
console.error(colorWarning("Invalid TRACE_API_URL: only https:// is allowed. Using default."));
|
|
47600
47897
|
return PRODUCTION_API_URL;
|
|
47601
47898
|
}
|
|
47602
|
-
|
|
47603
|
-
if (hostname3 === "localhost" || hostname3 === "127.0.0.1" || hostname3 === "0.0.0.0" || hostname3 === "::1" || hostname3.startsWith("10.") || hostname3.startsWith("192.168.") || /^172\.(1[6-9]|2[0-9]|3[01])\./.test(hostname3)) {
|
|
47899
|
+
if (!parsed.hostname.endsWith(TRACE_API_HOST_SUFFIX)) {
|
|
47604
47900
|
console.error(
|
|
47605
47901
|
colorWarning(
|
|
47606
|
-
|
|
47902
|
+
`Ignoring TRACE_API_URL: '${parsed.hostname}' is not a Trace API host (*${TRACE_API_HOST_SUFFIX}). Using default.`
|
|
47607
47903
|
)
|
|
47608
47904
|
);
|
|
47609
47905
|
return PRODUCTION_API_URL;
|
|
47610
47906
|
}
|
|
47611
|
-
return
|
|
47907
|
+
return `${parsed.origin}${parsed.pathname}`.replace(/\/+$/, "");
|
|
47612
47908
|
}
|
|
47613
47909
|
function requireAuth() {
|
|
47614
47910
|
const credential = loadCredentialOrExit();
|
|
@@ -47692,6 +47988,60 @@ function exitHumanPrincipalRequired() {
|
|
|
47692
47988
|
console.error(colorError("This command requires a human login; run `tracecli auth login`."));
|
|
47693
47989
|
process.exit(1);
|
|
47694
47990
|
}
|
|
47991
|
+
function transportErrorCode(error48) {
|
|
47992
|
+
if (!(error48 instanceof Error)) {
|
|
47993
|
+
return null;
|
|
47994
|
+
}
|
|
47995
|
+
const codeOf = (value) => {
|
|
47996
|
+
if (typeof value !== "object" || value === null || !("code" in value)) {
|
|
47997
|
+
return null;
|
|
47998
|
+
}
|
|
47999
|
+
return typeof value.code === "string" && value.code.length > 0 ? value.code : null;
|
|
48000
|
+
};
|
|
48001
|
+
const code = codeOf(error48) ?? codeOf(error48.cause);
|
|
48002
|
+
if (code !== null) {
|
|
48003
|
+
return code;
|
|
48004
|
+
}
|
|
48005
|
+
return error48.name === "TypeError" && /^fetch failed/i.test(error48.message) ? "FETCH_FAILED" : null;
|
|
48006
|
+
}
|
|
48007
|
+
var TRANSPORT_ERROR_HINTS = {
|
|
48008
|
+
ENOTFOUND: "DNS lookup failed",
|
|
48009
|
+
EAI_AGAIN: "DNS lookup timed out",
|
|
48010
|
+
ECONNREFUSED: "connection refused",
|
|
48011
|
+
ECONNRESET: "connection reset",
|
|
48012
|
+
ETIMEDOUT: "connection timed out",
|
|
48013
|
+
ConnectionRefused: "connection refused",
|
|
48014
|
+
ConnectionClosed: "connection closed before a response arrived",
|
|
48015
|
+
FailedToOpenSocket: "could not open a socket",
|
|
48016
|
+
CERT_HAS_EXPIRED: "the server certificate has expired",
|
|
48017
|
+
UNABLE_TO_VERIFY_LEAF_SIGNATURE: "the server certificate could not be verified",
|
|
48018
|
+
DEPTH_ZERO_SELF_SIGNED_CERT: "the server presented a self-signed certificate",
|
|
48019
|
+
FETCH_FAILED: "the request never received a response"
|
|
48020
|
+
};
|
|
48021
|
+
function unreachableApiMessage(baseUrl, code) {
|
|
48022
|
+
const host = new URL(baseUrl).host;
|
|
48023
|
+
const detail = TRANSPORT_ERROR_HINTS[code] ?? "the request failed";
|
|
48024
|
+
return [
|
|
48025
|
+
`Couldn't reach the Trace API at ${host}: ${detail} (${code}).`,
|
|
48026
|
+
"Check that this machine can reach the internet. Sandboxed agents and CI runners often block",
|
|
48027
|
+
`outbound network access; allow ${host} and retry.`
|
|
48028
|
+
].join("\n");
|
|
48029
|
+
}
|
|
48030
|
+
function exitUnreachableApi(code) {
|
|
48031
|
+
console.error(colorError(unreachableApiMessage(getApiBaseUrl(), code)));
|
|
48032
|
+
process.exit(1);
|
|
48033
|
+
}
|
|
48034
|
+
async function requestOrExit(request, token) {
|
|
48035
|
+
try {
|
|
48036
|
+
return await request(createClient(token));
|
|
48037
|
+
} catch (error48) {
|
|
48038
|
+
const code = transportErrorCode(error48);
|
|
48039
|
+
if (code !== null) {
|
|
48040
|
+
exitUnreachableApi(code);
|
|
48041
|
+
}
|
|
48042
|
+
throw error48;
|
|
48043
|
+
}
|
|
48044
|
+
}
|
|
47695
48045
|
function createClient(token) {
|
|
47696
48046
|
return initClient(v1Contract, {
|
|
47697
48047
|
baseUrl: getApiBaseUrl(),
|
|
@@ -47819,7 +48169,7 @@ async function refreshStoredAccessTokenForOrganization(workosOrganizationId) {
|
|
|
47819
48169
|
}
|
|
47820
48170
|
async function authenticatedRequest(request) {
|
|
47821
48171
|
const credential = loadCredentialOrExit();
|
|
47822
|
-
const firstResult = await request
|
|
48172
|
+
const firstResult = await requestOrExit(request, credential.token);
|
|
47823
48173
|
if (credential.kind === "api_key") {
|
|
47824
48174
|
if (firstResult.status === UNAUTHORIZED_STATUS) {
|
|
47825
48175
|
exitApiKeyUnauthorized();
|
|
@@ -47836,7 +48186,7 @@ async function authenticatedRequest(request) {
|
|
|
47836
48186
|
if (!refreshedToken) {
|
|
47837
48187
|
return firstResult;
|
|
47838
48188
|
}
|
|
47839
|
-
return request
|
|
48189
|
+
return requestOrExit(request, refreshedToken);
|
|
47840
48190
|
}
|
|
47841
48191
|
async function authenticatedRequestSafe(request) {
|
|
47842
48192
|
let credential;
|
|
@@ -49259,7 +49609,7 @@ function createSetScanningBranchCommand() {
|
|
|
49259
49609
|
return new Command("set-scanning-branch").description("Switch the scanning branch for one or every repository in the org").argument(
|
|
49260
49610
|
"[repositoryUrl]",
|
|
49261
49611
|
"Repository URL (omit when using --all-repos to switch every repo)"
|
|
49262
|
-
).requiredOption("--branch <name>", "New scanning branch name").option("--all-repos", "Apply the switch to every
|
|
49612
|
+
).requiredOption("--branch <name>", "New scanning branch name").option("--all-repos", "Apply the switch to every GitHub repository in the organization").option(
|
|
49263
49613
|
"--migrate-open-vulns",
|
|
49264
49614
|
"Relabel open vulnerabilities from the previous branch to the new branch"
|
|
49265
49615
|
).option("-o, --output <format>", "Output format: table (default), json", "table").addHelpText(
|
|
@@ -49580,6 +49930,62 @@ function resolveClearableUrl(value, clear, flag) {
|
|
|
49580
49930
|
}
|
|
49581
49931
|
return { value };
|
|
49582
49932
|
}
|
|
49933
|
+
function normalizeRepositoryRole(input) {
|
|
49934
|
+
const candidate = input.trim().toUpperCase().replace(/-/g, "_");
|
|
49935
|
+
return ApplicationRepositoryRoleValues.find((role) => role === candidate) ?? null;
|
|
49936
|
+
}
|
|
49937
|
+
var REPOSITORY_ROLE_INPUTS = ApplicationRepositoryRoleValues.map(
|
|
49938
|
+
(role) => role.toLowerCase().replace(/_/g, "-")
|
|
49939
|
+
);
|
|
49940
|
+
function parseRepositoryRoles(inputs) {
|
|
49941
|
+
const picked = /* @__PURE__ */ new Set();
|
|
49942
|
+
for (const input of inputs) {
|
|
49943
|
+
const role = normalizeRepositoryRole(input);
|
|
49944
|
+
if (role === null) {
|
|
49945
|
+
return {
|
|
49946
|
+
error: `Invalid --role '${input}'. Use one of: ${REPOSITORY_ROLE_INPUTS.join(", ")}.`
|
|
49947
|
+
};
|
|
49948
|
+
}
|
|
49949
|
+
picked.add(role);
|
|
49950
|
+
}
|
|
49951
|
+
return { roles: ApplicationRepositoryRoleValues.filter((role) => picked.has(role)) };
|
|
49952
|
+
}
|
|
49953
|
+
function buildLinkRepositoryBody(input) {
|
|
49954
|
+
return {
|
|
49955
|
+
repositoryId: input.repositoryId,
|
|
49956
|
+
...input.roles !== void 0 && input.roles.length > 0 ? { roles: [...input.roles] } : {},
|
|
49957
|
+
...input.roleLabel !== void 0 ? { roleLabel: input.roleLabel } : {},
|
|
49958
|
+
...input.repositoryPath !== void 0 ? { repositoryPath: input.repositoryPath } : {},
|
|
49959
|
+
...input.scanEnabled !== void 0 ? { scanEnabled: input.scanEnabled } : {}
|
|
49960
|
+
};
|
|
49961
|
+
}
|
|
49962
|
+
function buildUpdateLinkBody(input) {
|
|
49963
|
+
return {
|
|
49964
|
+
...input.roles !== void 0 ? { roles: [...input.roles] } : {},
|
|
49965
|
+
...input.roleLabel !== void 0 ? { roleLabel: input.roleLabel } : {},
|
|
49966
|
+
...input.repositoryPath !== void 0 ? { repositoryPath: input.repositoryPath } : {},
|
|
49967
|
+
...input.scanEnabled !== void 0 ? { scanEnabled: input.scanEnabled } : {}
|
|
49968
|
+
};
|
|
49969
|
+
}
|
|
49970
|
+
function isEmptyLinkUpdate(body) {
|
|
49971
|
+
return Object.keys(body).length === 0;
|
|
49972
|
+
}
|
|
49973
|
+
function validateRoleLabel(roles, roleLabel) {
|
|
49974
|
+
if (roles === void 0 || roleLabel === void 0 || roleLabel === null) {
|
|
49975
|
+
return null;
|
|
49976
|
+
}
|
|
49977
|
+
return roles.includes("OTHER") ? null : "--role-label requires --role other.";
|
|
49978
|
+
}
|
|
49979
|
+
function findLinkForRepo(links, input) {
|
|
49980
|
+
if (isUuid(input)) {
|
|
49981
|
+
const id = input.toLowerCase();
|
|
49982
|
+
return links.find(
|
|
49983
|
+
(link) => link.applicationRepositoryId?.toLowerCase() === id || link.repositoryId.toLowerCase() === id
|
|
49984
|
+
) ?? null;
|
|
49985
|
+
}
|
|
49986
|
+
const target = normalizeRepoUrlForMatch(resolveRepoUrl(input));
|
|
49987
|
+
return links.find((link) => normalizeRepoUrlForMatch(link.repositoryUrl) === target) ?? null;
|
|
49988
|
+
}
|
|
49583
49989
|
function failWriteOp(action, status, body, notFoundLabel) {
|
|
49584
49990
|
const { message, errorCode } = readErrorFields(body);
|
|
49585
49991
|
if (status === UNAUTHORIZED_STATUS2) {
|
|
@@ -49620,6 +50026,28 @@ function failWriteOp(action, status, body, notFoundLabel) {
|
|
|
49620
50026
|
);
|
|
49621
50027
|
process.exit(1);
|
|
49622
50028
|
}
|
|
50029
|
+
function failLinkOp(action, status, body) {
|
|
50030
|
+
const { message } = readErrorFields(body);
|
|
50031
|
+
if (status === UNAUTHORIZED_STATUS2) {
|
|
50032
|
+
exitAuthFailed();
|
|
50033
|
+
}
|
|
50034
|
+
if (status === 403) {
|
|
50035
|
+
console.error(
|
|
50036
|
+
colorError(
|
|
50037
|
+
"Repository links require an organization admin or Trace staff on a pentest-enabled organization, signed in with a browser session (API keys are rejected)."
|
|
50038
|
+
)
|
|
50039
|
+
);
|
|
50040
|
+
process.exit(1);
|
|
50041
|
+
}
|
|
50042
|
+
if (status === 404 || status === 409 || status === 400) {
|
|
50043
|
+
console.error(colorError(message ?? `Failed to ${action} (status ${status}).`));
|
|
50044
|
+
process.exit(1);
|
|
50045
|
+
}
|
|
50046
|
+
console.error(
|
|
50047
|
+
colorError(`Failed to ${action} repository (status ${status})${message ? `: ${message}` : "."}`)
|
|
50048
|
+
);
|
|
50049
|
+
process.exit(1);
|
|
50050
|
+
}
|
|
49623
50051
|
function failReadOp(action, status, body, notFoundLabel) {
|
|
49624
50052
|
const { message } = readErrorFields(body);
|
|
49625
50053
|
if (status === UNAUTHORIZED_STATUS2) {
|
|
@@ -49681,12 +50109,12 @@ function buildApplicationsTable(apps) {
|
|
|
49681
50109
|
repos: String(a2.repositories.length),
|
|
49682
50110
|
url: a2.applicationUrl ? sanitizeDisplay(a2.applicationUrl) : "\u2014"
|
|
49683
50111
|
}));
|
|
49684
|
-
const idWidth = Math.max(2, ...cells.map((
|
|
49685
|
-
const nameWidth = Math.max(4, ...cells.map((
|
|
49686
|
-
const typeWidth = Math.max(4, ...cells.map((
|
|
50112
|
+
const idWidth = Math.max(2, ...cells.map((c86) => c86.id.length));
|
|
50113
|
+
const nameWidth = Math.max(4, ...cells.map((c86) => c86.name.length));
|
|
50114
|
+
const typeWidth = Math.max(4, ...cells.map((c86) => c86.type.length));
|
|
49687
50115
|
const header = `${"ID".padEnd(idWidth)} ${"NAME".padEnd(nameWidth)} ${"TYPE".padEnd(typeWidth)} REPOS URL`;
|
|
49688
50116
|
const rows = cells.map(
|
|
49689
|
-
(
|
|
50117
|
+
(c86) => `${c86.id.padEnd(idWidth)} ${c86.name.padEnd(nameWidth)} ${c86.type.padEnd(typeWidth)} ${c86.repos.padStart(5)} ${c86.url}`
|
|
49690
50118
|
);
|
|
49691
50119
|
return { header, rows };
|
|
49692
50120
|
}
|
|
@@ -49706,12 +50134,12 @@ function buildApplicationRepositoriesTable(links) {
|
|
|
49706
50134
|
path: l2.repositoryPath ? sanitizeDisplay(l2.repositoryPath) : "\u2014",
|
|
49707
50135
|
status: formatStatus(l2.repositoryStatus)
|
|
49708
50136
|
}));
|
|
49709
|
-
const nameWidth = Math.max(10, ...cells.map((
|
|
49710
|
-
const roleWidth = Math.max(4, ...cells.map((
|
|
49711
|
-
const pathWidth = Math.max(4, ...cells.map((
|
|
50137
|
+
const nameWidth = Math.max(10, ...cells.map((c86) => c86.name.length));
|
|
50138
|
+
const roleWidth = Math.max(4, ...cells.map((c86) => c86.role.length));
|
|
50139
|
+
const pathWidth = Math.max(4, ...cells.map((c86) => c86.path.length));
|
|
49712
50140
|
const header = `${"REPOSITORY".padEnd(nameWidth)} SCAN ${"ROLE".padEnd(roleWidth)} ${"PATH".padEnd(pathWidth)} STATUS`;
|
|
49713
50141
|
const rows = cells.map(
|
|
49714
|
-
(
|
|
50142
|
+
(c86) => `${c86.name.padEnd(nameWidth)} ${c86.scan.padEnd(4)} ${c86.role.padEnd(roleWidth)} ${c86.path.padEnd(pathWidth)} ${c86.status}`
|
|
49715
50143
|
);
|
|
49716
50144
|
return { header, rows };
|
|
49717
50145
|
}
|
|
@@ -49974,6 +50402,205 @@ async function runDelete(applicationId, options) {
|
|
|
49974
50402
|
}
|
|
49975
50403
|
console.log(colorSuccess(`Deleted application ${applicationId}`));
|
|
49976
50404
|
}
|
|
50405
|
+
function renderLinkDetail(link) {
|
|
50406
|
+
const pad = 11;
|
|
50407
|
+
return [
|
|
50408
|
+
`${"Link ID:".padEnd(pad)} ${link.applicationRepositoryId ?? "\u2014"}`,
|
|
50409
|
+
`${"Repository:".padEnd(pad)} ${sanitizeDisplay(link.repositoryName)} (${link.repositoryId})`,
|
|
50410
|
+
`${"URL:".padEnd(pad)} ${sanitizeDisplay(link.repositoryUrl)}`,
|
|
50411
|
+
`${"Scan:".padEnd(pad)} ${link.scanEnabled ? "yes" : "no"}`,
|
|
50412
|
+
`${"Role:".padEnd(pad)} ${sanitizeDisplay(formatLinkRole(link.role, link.roleLabel, link.roles))}`,
|
|
50413
|
+
`${"Path:".padEnd(pad)} ${link.repositoryPath ? sanitizeDisplay(link.repositoryPath) : "\u2014"}`,
|
|
50414
|
+
`${"Status:".padEnd(pad)} ${formatStatus(link.repositoryStatus)}`
|
|
50415
|
+
].join("\n");
|
|
50416
|
+
}
|
|
50417
|
+
function outputLink(link, output) {
|
|
50418
|
+
if (output === "json") {
|
|
50419
|
+
printJson(link);
|
|
50420
|
+
return;
|
|
50421
|
+
}
|
|
50422
|
+
if (output === "tsv") {
|
|
50423
|
+
printApplicationRepositoriesTsv([link]);
|
|
50424
|
+
return;
|
|
50425
|
+
}
|
|
50426
|
+
console.log(renderLinkDetail(link));
|
|
50427
|
+
}
|
|
50428
|
+
function exitInvalidApplicationId(applicationId) {
|
|
50429
|
+
console.error(colorError(`Invalid application id '${applicationId}'. Expected a UUID.`));
|
|
50430
|
+
process.exit(1);
|
|
50431
|
+
}
|
|
50432
|
+
async function resolveExistingLink(organizationId, applicationId, repoInput) {
|
|
50433
|
+
const result = await authenticatedRequest(
|
|
50434
|
+
(client) => client.application.listApplicationRepositories({ params: { organizationId, applicationId } })
|
|
50435
|
+
);
|
|
50436
|
+
if (result.status !== SUCCESS_STATUS) {
|
|
50437
|
+
failReadOp("list application repositories", result.status, result.body, applicationId);
|
|
50438
|
+
}
|
|
50439
|
+
const link = findLinkForRepo(result.body, repoInput);
|
|
50440
|
+
if (!link) {
|
|
50441
|
+
console.error(
|
|
50442
|
+
colorError(
|
|
50443
|
+
`Repository ${repoInput} is not linked to application ${applicationId}. Run \`tracecli application repos ${applicationId}\` to see its links.`
|
|
50444
|
+
)
|
|
50445
|
+
);
|
|
50446
|
+
process.exit(1);
|
|
50447
|
+
}
|
|
50448
|
+
if (link.applicationRepositoryId === null) {
|
|
50449
|
+
console.error(
|
|
50450
|
+
colorError(
|
|
50451
|
+
`Repository ${repoInput} is linked without a link id, so it can't be changed from the CLI. Edit it in the dashboard.`
|
|
50452
|
+
)
|
|
50453
|
+
);
|
|
50454
|
+
process.exit(1);
|
|
50455
|
+
}
|
|
50456
|
+
return { ...link, applicationRepositoryId: link.applicationRepositoryId };
|
|
50457
|
+
}
|
|
50458
|
+
async function runLink(applicationId, options) {
|
|
50459
|
+
const output = parseOutput(options.output);
|
|
50460
|
+
if (!isUuid(applicationId)) {
|
|
50461
|
+
exitInvalidApplicationId(applicationId);
|
|
50462
|
+
}
|
|
50463
|
+
const parsedRoles = parseRepositoryRoles(options.role ?? []);
|
|
50464
|
+
if ("error" in parsedRoles) {
|
|
50465
|
+
console.error(colorError(parsedRoles.error));
|
|
50466
|
+
process.exit(1);
|
|
50467
|
+
}
|
|
50468
|
+
const roles = options.role !== void 0 ? parsedRoles.roles : void 0;
|
|
50469
|
+
const labelError = validateRoleLabel(roles ?? [], options.roleLabel);
|
|
50470
|
+
if (labelError) {
|
|
50471
|
+
console.error(colorError(labelError));
|
|
50472
|
+
process.exit(1);
|
|
50473
|
+
}
|
|
50474
|
+
const organizationId = await resolveOrganizationId();
|
|
50475
|
+
const repositoryId = await resolveRepositoryId(organizationId, options.repo);
|
|
50476
|
+
const body = buildLinkRepositoryBody({
|
|
50477
|
+
repositoryId,
|
|
50478
|
+
roles,
|
|
50479
|
+
roleLabel: options.roleLabel,
|
|
50480
|
+
repositoryPath: options.repoPath,
|
|
50481
|
+
// Commander defaults a lone `--no-scan` to true; only an explicit opt-out
|
|
50482
|
+
// goes on the wire so the API's own default applies otherwise.
|
|
50483
|
+
scanEnabled: options.scan === false ? false : void 0
|
|
50484
|
+
});
|
|
50485
|
+
const result = await authenticatedRequest(
|
|
50486
|
+
(client) => client.application.createApplicationRepository({
|
|
50487
|
+
params: { organizationId, applicationId },
|
|
50488
|
+
body
|
|
50489
|
+
})
|
|
50490
|
+
);
|
|
50491
|
+
if (result.status !== CREATED_STATUS) {
|
|
50492
|
+
failLinkOp("link", result.status, result.body);
|
|
50493
|
+
}
|
|
50494
|
+
if (output === "table") {
|
|
50495
|
+
console.log(
|
|
50496
|
+
colorSuccess(
|
|
50497
|
+
`Linked ${sanitizeDisplay(result.body.repositoryName)} to application ${applicationId}`
|
|
50498
|
+
)
|
|
50499
|
+
);
|
|
50500
|
+
}
|
|
50501
|
+
outputLink(result.body, output);
|
|
50502
|
+
}
|
|
50503
|
+
var UPDATE_LINK_FLAGS = "--role, --clear-roles, --role-label, --clear-role-label, --repo-path, --clear-repo-path, --scan, --no-scan";
|
|
50504
|
+
async function runUpdateLink(applicationId, options) {
|
|
50505
|
+
const output = parseOutput(options.output);
|
|
50506
|
+
if (!isUuid(applicationId)) {
|
|
50507
|
+
exitInvalidApplicationId(applicationId);
|
|
50508
|
+
}
|
|
50509
|
+
if (options.role !== void 0 && options.clearRoles) {
|
|
50510
|
+
console.error(colorError("Pass only one of --role / --clear-roles."));
|
|
50511
|
+
process.exit(1);
|
|
50512
|
+
}
|
|
50513
|
+
const parsedRoles = parseRepositoryRoles(options.role ?? []);
|
|
50514
|
+
if ("error" in parsedRoles) {
|
|
50515
|
+
console.error(colorError(parsedRoles.error));
|
|
50516
|
+
process.exit(1);
|
|
50517
|
+
}
|
|
50518
|
+
const roles = options.clearRoles ? [] : options.role !== void 0 ? parsedRoles.roles : void 0;
|
|
50519
|
+
const roleLabel = resolveClearableOption(options.roleLabel, options.clearRoleLabel, "role-label");
|
|
50520
|
+
if ("error" in roleLabel) {
|
|
50521
|
+
console.error(colorError(roleLabel.error));
|
|
50522
|
+
process.exit(1);
|
|
50523
|
+
}
|
|
50524
|
+
const repositoryPath = resolveClearableOption(
|
|
50525
|
+
options.repoPath,
|
|
50526
|
+
options.clearRepoPath,
|
|
50527
|
+
"repo-path"
|
|
50528
|
+
);
|
|
50529
|
+
if ("error" in repositoryPath) {
|
|
50530
|
+
console.error(colorError(repositoryPath.error));
|
|
50531
|
+
process.exit(1);
|
|
50532
|
+
}
|
|
50533
|
+
const labelError = validateRoleLabel(roles, roleLabel.value);
|
|
50534
|
+
if (labelError) {
|
|
50535
|
+
console.error(colorError(labelError));
|
|
50536
|
+
process.exit(1);
|
|
50537
|
+
}
|
|
50538
|
+
const body = buildUpdateLinkBody({
|
|
50539
|
+
roles,
|
|
50540
|
+
roleLabel: roleLabel.value,
|
|
50541
|
+
repositoryPath: repositoryPath.value,
|
|
50542
|
+
scanEnabled: options.scan
|
|
50543
|
+
});
|
|
50544
|
+
if (isEmptyLinkUpdate(body)) {
|
|
50545
|
+
console.error(colorError(`Nothing to update. Pass at least one of ${UPDATE_LINK_FLAGS}.`));
|
|
50546
|
+
process.exit(1);
|
|
50547
|
+
}
|
|
50548
|
+
const organizationId = await resolveOrganizationId();
|
|
50549
|
+
const existing = await resolveExistingLink(organizationId, applicationId, options.repo);
|
|
50550
|
+
const result = await authenticatedRequest(
|
|
50551
|
+
(client) => client.application.updateApplicationRepository({
|
|
50552
|
+
params: {
|
|
50553
|
+
organizationId,
|
|
50554
|
+
applicationId,
|
|
50555
|
+
applicationRepositoryId: existing.applicationRepositoryId
|
|
50556
|
+
},
|
|
50557
|
+
body
|
|
50558
|
+
})
|
|
50559
|
+
);
|
|
50560
|
+
if (result.status !== SUCCESS_STATUS) {
|
|
50561
|
+
failLinkOp("update link", result.status, result.body);
|
|
50562
|
+
}
|
|
50563
|
+
if (output === "table") {
|
|
50564
|
+
console.log(
|
|
50565
|
+
colorSuccess(
|
|
50566
|
+
`Updated link for ${sanitizeDisplay(result.body.repositoryName)} on application ${applicationId}`
|
|
50567
|
+
)
|
|
50568
|
+
);
|
|
50569
|
+
}
|
|
50570
|
+
outputLink(result.body, output);
|
|
50571
|
+
}
|
|
50572
|
+
async function runUnlink(applicationId, options) {
|
|
50573
|
+
if (!isUuid(applicationId)) {
|
|
50574
|
+
exitInvalidApplicationId(applicationId);
|
|
50575
|
+
}
|
|
50576
|
+
const organizationId = await resolveOrganizationId();
|
|
50577
|
+
const existing = await resolveExistingLink(organizationId, applicationId, options.repo);
|
|
50578
|
+
const confirmed = await confirmAction(
|
|
50579
|
+
`Unlink ${sanitizeDisplay(existing.repositoryName)} from application ${applicationId}?`,
|
|
50580
|
+
{ skip: options.yes === true, verb: "unlink" }
|
|
50581
|
+
);
|
|
50582
|
+
if (!confirmed) {
|
|
50583
|
+
console.log("Aborted.");
|
|
50584
|
+
return;
|
|
50585
|
+
}
|
|
50586
|
+
const result = await authenticatedRequest(
|
|
50587
|
+
(client) => client.application.deleteApplicationRepository({
|
|
50588
|
+
params: {
|
|
50589
|
+
organizationId,
|
|
50590
|
+
applicationId,
|
|
50591
|
+
applicationRepositoryId: existing.applicationRepositoryId
|
|
50592
|
+
}
|
|
50593
|
+
})
|
|
50594
|
+
);
|
|
50595
|
+
if (result.status !== NO_CONTENT_STATUS) {
|
|
50596
|
+
failLinkOp("unlink", result.status, result.body);
|
|
50597
|
+
}
|
|
50598
|
+
console.log(
|
|
50599
|
+
colorSuccess(
|
|
50600
|
+
`Unlinked ${sanitizeDisplay(existing.repositoryName)} from application ${applicationId}`
|
|
50601
|
+
)
|
|
50602
|
+
);
|
|
50603
|
+
}
|
|
49977
50604
|
function createCreateCommand() {
|
|
49978
50605
|
return new Command("create").description("Create a new application").argument("<name>", "Application name").option("--type <type>", "Application type: web, cli, mobile, desktop, api-service", "web").option("--url <url>", "Application URL (required for web/api-service)").option("--repo <id-or-url>", "Link a repository at creation (UUID, URL, or owner/repo)").option("--repo-path <path>", "Path within the linked repository").option("--help-center-url <url>", "Help center URL").option("--docs-url <url>", "Documentation URL").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
|
|
49979
50606
|
"after",
|
|
@@ -50025,6 +50652,59 @@ Examples:
|
|
|
50025
50652
|
await runUpdate(applicationId, options);
|
|
50026
50653
|
});
|
|
50027
50654
|
}
|
|
50655
|
+
var ROLE_FLAG_HELP = `Repository role (repeatable): ${REPOSITORY_ROLE_INPUTS.join(", ")}`;
|
|
50656
|
+
function createLinkCommand() {
|
|
50657
|
+
return new Command("link").description("Link a repository to an application").argument("<applicationId>", "Application UUID").requiredOption("--repo <id-or-url>", "Repository to link (UUID, URL, or owner/repo)").option("--role <role>", ROLE_FLAG_HELP, collectRepeatable).option("--role-label <label>", 'Custom label for the "other" role').option("--repo-path <path>", "Path within the repository").option("--no-scan", "Link without including the repository in scans").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
|
|
50658
|
+
"after",
|
|
50659
|
+
`
|
|
50660
|
+
A link is scan-enabled unless --no-scan is passed. Scan-disabled links are
|
|
50661
|
+
skipped by scans and do not satisfy the repository precondition for starting a
|
|
50662
|
+
pentest.
|
|
50663
|
+
|
|
50664
|
+
Examples:
|
|
50665
|
+
tracecli application link <appId> --repo acme/store
|
|
50666
|
+
tracecli application link <appId> --repo acme/store --role frontend --role backend-api
|
|
50667
|
+
tracecli application link <appId> --repo acme/tools --role other --role-label "Design system"
|
|
50668
|
+
tracecli application link <appId> --repo acme/monorepo --repo-path apps/web --no-scan`
|
|
50669
|
+
).action(async (applicationId, options) => {
|
|
50670
|
+
await runLink(applicationId, options);
|
|
50671
|
+
});
|
|
50672
|
+
}
|
|
50673
|
+
function createUpdateLinkCommand() {
|
|
50674
|
+
return new Command("update-link").description("Change an existing repository link's roles, label, path, or scan state").argument("<applicationId>", "Application UUID").requiredOption(
|
|
50675
|
+
"--repo <id-or-url>",
|
|
50676
|
+
"Linked repository to change (repository UUID, link UUID, URL, or owner/repo)"
|
|
50677
|
+
).option("--role <role>", `${ROLE_FLAG_HELP}; replaces the current roles`, collectRepeatable).option("--clear-roles", "Remove every role from the link").option("--role-label <label>", 'Custom label for the "other" role').option("--clear-role-label", "Remove the custom role label").option("--repo-path <path>", "Path within the repository").option("--clear-repo-path", "Remove the repository path").option("--scan", "Include the repository in scans").option("--no-scan", "Exclude the repository from scans (the link stays)").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
|
|
50678
|
+
"after",
|
|
50679
|
+
`
|
|
50680
|
+
The update is partial: only the flags you pass change. --role replaces the
|
|
50681
|
+
whole role set, so pass every role the link should keep.
|
|
50682
|
+
|
|
50683
|
+
Examples:
|
|
50684
|
+
tracecli application update-link <appId> --repo acme/store --role frontend --role backend-api
|
|
50685
|
+
tracecli application update-link <appId> --repo acme/store --repo-path apps/web
|
|
50686
|
+
tracecli application update-link <appId> --repo acme/store --no-scan
|
|
50687
|
+
tracecli application update-link <appId> --repo <repositoryId> --scan -o json`
|
|
50688
|
+
).action(async (applicationId, options) => {
|
|
50689
|
+
await runUpdateLink(applicationId, options);
|
|
50690
|
+
});
|
|
50691
|
+
}
|
|
50692
|
+
function createUnlinkCommand() {
|
|
50693
|
+
return new Command("unlink").description("Remove a repository link from an application").argument("<applicationId>", "Application UUID").requiredOption(
|
|
50694
|
+
"--repo <id-or-url>",
|
|
50695
|
+
"Linked repository to remove (repository UUID, link UUID, URL, or owner/repo)"
|
|
50696
|
+
).option("-y, --yes", "Skip the confirmation prompt (required in non-interactive shells)").addHelpText(
|
|
50697
|
+
"after",
|
|
50698
|
+
`
|
|
50699
|
+
Only the link is removed; the repository stays connected to the organization.
|
|
50700
|
+
|
|
50701
|
+
Examples:
|
|
50702
|
+
tracecli application unlink <appId> --repo acme/store
|
|
50703
|
+
tracecli application unlink <appId> --repo <repositoryId> --yes`
|
|
50704
|
+
).action(async (applicationId, options) => {
|
|
50705
|
+
await runUnlink(applicationId, options);
|
|
50706
|
+
});
|
|
50707
|
+
}
|
|
50028
50708
|
function createDeleteCommand() {
|
|
50029
50709
|
return new Command("delete").description("Delete an application").argument("<applicationId>", "Application UUID").option("-y, --yes", "Skip the confirmation prompt (required in non-interactive shells)").action(async (applicationId, options) => {
|
|
50030
50710
|
await runDelete(applicationId, options);
|
|
@@ -50036,6 +50716,9 @@ function createApplicationCommand() {
|
|
|
50036
50716
|
application.addCommand(createListCommand2());
|
|
50037
50717
|
application.addCommand(createGetCommand());
|
|
50038
50718
|
application.addCommand(createReposCommand());
|
|
50719
|
+
application.addCommand(createLinkCommand());
|
|
50720
|
+
application.addCommand(createUpdateLinkCommand());
|
|
50721
|
+
application.addCommand(createUnlinkCommand());
|
|
50039
50722
|
application.addCommand(createUpdateCommand());
|
|
50040
50723
|
application.addCommand(createDeleteCommand());
|
|
50041
50724
|
return application;
|
|
@@ -50496,8 +51179,8 @@ function wrapTextWithPrefix(e, r2, o2, t2 = o2, s = o2, n3) {
|
|
|
50496
51179
|
hard: true,
|
|
50497
51180
|
trim: false
|
|
50498
51181
|
}).split(`
|
|
50499
|
-
`).map((
|
|
50500
|
-
const d = n3 ? n3(
|
|
51182
|
+
`).map((c86, i2, m2) => {
|
|
51183
|
+
const d = n3 ? n3(c86, i2) : c86;
|
|
50501
51184
|
return i2 === 0 ? `${t2}${d}` : i2 === m2.length - 1 ? `${s}${d}` : `${o2}${d}`;
|
|
50502
51185
|
}).join(`
|
|
50503
51186
|
`);
|
|
@@ -50995,14 +51678,14 @@ var limitOptions = ({
|
|
|
50995
51678
|
Math.min(l2 - a2 + 3, e.length - a2),
|
|
50996
51679
|
0
|
|
50997
51680
|
));
|
|
50998
|
-
let d = a2 < e.length && f > 0,
|
|
51681
|
+
let d = a2 < e.length && f > 0, c86 = a2 < e.length && f + a2 < e.length;
|
|
50999
51682
|
const W = Math.min(
|
|
51000
51683
|
f + a2,
|
|
51001
51684
|
e.length
|
|
51002
51685
|
), s = [];
|
|
51003
51686
|
let g = 0;
|
|
51004
|
-
d && g++,
|
|
51005
|
-
const T = f + (d ? 1 : 0), y = W - (
|
|
51687
|
+
d && g++, c86 && g++;
|
|
51688
|
+
const T = f + (d ? 1 : 0), y = W - (c86 ? 1 : 0);
|
|
51006
51689
|
for (let t2 = T; t2 < y; t2++) {
|
|
51007
51690
|
const n3 = e[t2], o2 = n3 ? w(n3, t2 === l2) : "", h2 = wrapAnsi(o2, i2, {
|
|
51008
51691
|
hard: true,
|
|
@@ -51023,14 +51706,14 @@ var limitOptions = ({
|
|
|
51023
51706
|
u4,
|
|
51024
51707
|
true
|
|
51025
51708
|
);
|
|
51026
|
-
d ? ({ lineCount: o2, removals: t2 } = L(), o2 > u4 && (
|
|
51709
|
+
d ? ({ lineCount: o2, removals: t2 } = L(), o2 > u4 && (c86 || (u4 -= 1), { lineCount: o2, removals: n3 } = E())) : (c86 || (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 && (c86 = true, s.splice(s.length - n3, n3));
|
|
51027
51710
|
}
|
|
51028
51711
|
const x = [];
|
|
51029
51712
|
d && x.push(M);
|
|
51030
51713
|
for (const t2 of s)
|
|
51031
51714
|
for (const n3 of t2)
|
|
51032
51715
|
x.push(n3);
|
|
51033
|
-
return
|
|
51716
|
+
return c86 && x.push(M), x;
|
|
51034
51717
|
};
|
|
51035
51718
|
var confirm = (i2) => {
|
|
51036
51719
|
const a2 = i2.active ?? "Yes", s = i2.inactive ?? "No";
|
|
@@ -51049,15 +51732,15 @@ var confirm = (i2) => {
|
|
|
51049
51732
|
u4
|
|
51050
51733
|
), o2 = `${e ? `${styleText2("gray", S_BAR)}
|
|
51051
51734
|
` : ""}${f}
|
|
51052
|
-
`,
|
|
51735
|
+
`, c86 = this.value ? a2 : s;
|
|
51053
51736
|
switch (this.state) {
|
|
51054
51737
|
case "submit": {
|
|
51055
51738
|
const r2 = e ? `${styleText2("gray", S_BAR)} ` : "";
|
|
51056
|
-
return `${o2}${r2}${styleText2("dim",
|
|
51739
|
+
return `${o2}${r2}${styleText2("dim", c86)}`;
|
|
51057
51740
|
}
|
|
51058
51741
|
case "cancel": {
|
|
51059
51742
|
const r2 = e ? `${styleText2("gray", S_BAR)} ` : "";
|
|
51060
|
-
return `${o2}${r2}${styleText2(["strikethrough", "dim"],
|
|
51743
|
+
return `${o2}${r2}${styleText2(["strikethrough", "dim"], c86)}${e ? `
|
|
51061
51744
|
${styleText2("gray", S_BAR)}` : ""}`;
|
|
51062
51745
|
}
|
|
51063
51746
|
default: {
|
|
@@ -51205,13 +51888,13 @@ var multiline = (e) => new h({
|
|
|
51205
51888
|
`, m2 = e.placeholder && e.placeholder.length > 0 ? (
|
|
51206
51889
|
// biome-ignore lint/style/noNonNullAssertion: guarded by placeholder.length > 0
|
|
51207
51890
|
styleText2("inverse", e.placeholder[0]) + styleText2("dim", e.placeholder.slice(1))
|
|
51208
|
-
) : styleText2(["inverse", "hidden"], "_"), a2 = this.userInput ? this.userInputWithCursor : m2, l2 = this.value ?? "",
|
|
51891
|
+
) : styleText2(["inverse", "hidden"], "_"), a2 = this.userInput ? this.userInputWithCursor : m2, l2 = this.value ?? "", c86 = e.showSubmit ? `
|
|
51209
51892
|
${styleText2(this.focused === "submit" ? "cyan" : "dim", "[ submit ]")}` : "";
|
|
51210
51893
|
switch (this.state) {
|
|
51211
51894
|
case "error": {
|
|
51212
51895
|
const n3 = `${styleText2("yellow", S_BAR)} `, r2 = i2 ? wrapTextWithPrefix(e.output, a2, n3, void 0) : a2, u4 = styleText2("yellow", S_BAR_END);
|
|
51213
51896
|
return `${o2}${r2}
|
|
51214
|
-
${u4} ${styleText2("yellow", this.error)}${
|
|
51897
|
+
${u4} ${styleText2("yellow", this.error)}${c86}
|
|
51215
51898
|
`;
|
|
51216
51899
|
}
|
|
51217
51900
|
case "submit": {
|
|
@@ -51239,7 +51922,7 @@ ${u4} ${styleText2("yellow", this.error)}${c84}
|
|
|
51239
51922
|
default: {
|
|
51240
51923
|
const n3 = i2 ? `${styleText2("cyan", S_BAR)} ` : "", r2 = i2 ? styleText2("cyan", S_BAR_END) : "", u4 = i2 ? wrapTextWithPrefix(e.output, a2, n3) : a2;
|
|
51241
51924
|
return `${o2}${u4}
|
|
51242
|
-
${r2}${
|
|
51925
|
+
${r2}${c86}
|
|
51243
51926
|
`;
|
|
51244
51927
|
}
|
|
51245
51928
|
}
|
|
@@ -51254,7 +51937,7 @@ var password = (r2) => new u$1({
|
|
|
51254
51937
|
render() {
|
|
51255
51938
|
const e = r2.withGuide ?? settings.withGuide, o2 = `${e ? `${styleText2("gray", S_BAR)}
|
|
51256
51939
|
` : ""}${symbol2(this.state)} ${r2.message}
|
|
51257
|
-
`,
|
|
51940
|
+
`, c86 = this.userInputWithCursor, i2 = this.masked;
|
|
51258
51941
|
switch (this.state) {
|
|
51259
51942
|
case "error": {
|
|
51260
51943
|
const s = e ? `${styleText2("yellow", S_BAR)} ` : "", n3 = e ? `${styleText2("yellow", S_BAR_END)} ` : "", l2 = i2 ?? "";
|
|
@@ -51274,7 +51957,7 @@ ${styleText2("gray", S_BAR)}` : ""}`;
|
|
|
51274
51957
|
}
|
|
51275
51958
|
default: {
|
|
51276
51959
|
const s = e ? `${styleText2("cyan", S_BAR)} ` : "", n3 = e ? styleText2("cyan", S_BAR_END) : "";
|
|
51277
|
-
return `${o2}${s}${
|
|
51960
|
+
return `${o2}${s}${c86}
|
|
51278
51961
|
${n3}
|
|
51279
51962
|
`;
|
|
51280
51963
|
}
|
|
@@ -51290,7 +51973,7 @@ var SELECT_INSTRUCTIONS = [
|
|
|
51290
51973
|
`${styleText2("dim", "\u2191/\u2193")} to navigate`,
|
|
51291
51974
|
`${styleText2("dim", "Enter:")} confirm`
|
|
51292
51975
|
];
|
|
51293
|
-
var
|
|
51976
|
+
var c85 = (t2, o2) => t2.includes(`
|
|
51294
51977
|
`) ? t2.split(`
|
|
51295
51978
|
`).map((d) => o2(d)).join(`
|
|
51296
51979
|
`) : o2(t2);
|
|
@@ -51301,15 +51984,15 @@ var select = (t2) => {
|
|
|
51301
51984
|
const s = n3.label ?? String(n3.value);
|
|
51302
51985
|
switch (m2) {
|
|
51303
51986
|
case "disabled":
|
|
51304
|
-
return `${styleText2("gray", S_RADIO_INACTIVE)} ${
|
|
51987
|
+
return `${styleText2("gray", S_RADIO_INACTIVE)} ${c85(s, (i2) => styleText2("gray", i2))}${n3.hint ? ` ${styleText2("dim", `(${n3.hint ?? "disabled"})`)}` : ""}`;
|
|
51305
51988
|
case "selected":
|
|
51306
|
-
return `${
|
|
51989
|
+
return `${c85(s, (i2) => styleText2("dim", i2))}`;
|
|
51307
51990
|
case "active":
|
|
51308
51991
|
return `${styleText2("green", S_RADIO_ACTIVE)} ${s}${n3.hint ? ` ${styleText2("dim", `(${n3.hint})`)}` : ""}`;
|
|
51309
51992
|
case "cancelled":
|
|
51310
|
-
return `${
|
|
51993
|
+
return `${c85(s, (i2) => styleText2(["strikethrough", "dim"], i2))}`;
|
|
51311
51994
|
default:
|
|
51312
|
-
return `${styleText2("dim", S_RADIO_INACTIVE)} ${
|
|
51995
|
+
return `${styleText2("dim", S_RADIO_INACTIVE)} ${c85(s, (i2) => styleText2("dim", i2))}`;
|
|
51313
51996
|
}
|
|
51314
51997
|
}, d = t2.showInstructions ?? true;
|
|
51315
51998
|
return new n$1({
|
|
@@ -51370,6 +52053,18 @@ var i = `${styleText2("gray", S_BAR)} `;
|
|
|
51370
52053
|
|
|
51371
52054
|
// src/org/invite.ts
|
|
51372
52055
|
var MEMBER_ROLE_SLUGS = MemberRoleSlugSchema.options;
|
|
52056
|
+
var ROLE_NAMES = {
|
|
52057
|
+
admin: "admin",
|
|
52058
|
+
analyst: "manager",
|
|
52059
|
+
developer: "developer"
|
|
52060
|
+
};
|
|
52061
|
+
var ROLE_BY_NAME = {
|
|
52062
|
+
admin: "admin",
|
|
52063
|
+
manager: "analyst",
|
|
52064
|
+
analyst: "analyst",
|
|
52065
|
+
developer: "developer"
|
|
52066
|
+
};
|
|
52067
|
+
var ROLE_CHOICES = MEMBER_ROLE_SLUGS.map((slug) => ROLE_NAMES[slug]).join(", ");
|
|
51373
52068
|
var DEFAULT_INVITE_ROLE = CreateMemberInvitationRequestSchema.shape.roleSlug.parse(void 0);
|
|
51374
52069
|
var InviteEmailSchema = CreateMemberInvitationRequestSchema.shape.email;
|
|
51375
52070
|
function planInvite(emailArg, options) {
|
|
@@ -51380,14 +52075,13 @@ function planInvite(emailArg, options) {
|
|
|
51380
52075
|
if (!InviteEmailSchema.safeParse(email3).success) {
|
|
51381
52076
|
return { error: `'${sanitizeDisplay(email3)}' is not a valid email address.` };
|
|
51382
52077
|
}
|
|
51383
|
-
const
|
|
51384
|
-
|
|
51385
|
-
if (!parsedRole.success) {
|
|
52078
|
+
const roleSlug = ROLE_BY_NAME[options.role.trim().toLowerCase()];
|
|
52079
|
+
if (roleSlug === void 0) {
|
|
51386
52080
|
return {
|
|
51387
|
-
error: `Invalid --role '${sanitizeDisplay(options.role)}'. Use one of: ${
|
|
52081
|
+
error: `Invalid --role '${sanitizeDisplay(options.role)}'. Use one of: ${ROLE_CHOICES}.`
|
|
51388
52082
|
};
|
|
51389
52083
|
}
|
|
51390
|
-
return { plan: { email: email3, roleSlug
|
|
52084
|
+
return { plan: { email: email3, roleSlug } };
|
|
51391
52085
|
}
|
|
51392
52086
|
function failInvite(status, body) {
|
|
51393
52087
|
const { message } = readErrorFields(body);
|
|
@@ -51395,7 +52089,7 @@ function failInvite(status, body) {
|
|
|
51395
52089
|
exitAuthFailed();
|
|
51396
52090
|
}
|
|
51397
52091
|
if (status === 403) {
|
|
51398
|
-
const hint = "Inviting members requires an organization admin
|
|
52092
|
+
const hint = "Inviting members requires an organization admin signed in with `tracecli auth login` (API keys are rejected).";
|
|
51399
52093
|
console.error(
|
|
51400
52094
|
colorError(message === void 0 || message === "Insufficient permissions" ? hint : message)
|
|
51401
52095
|
);
|
|
@@ -51440,7 +52134,7 @@ function outputInvitation(invitation, output) {
|
|
|
51440
52134
|
}
|
|
51441
52135
|
console.log(
|
|
51442
52136
|
colorSuccess(
|
|
51443
|
-
`Invitation sent to ${sanitizeDisplay(invitation.email)} as ${
|
|
52137
|
+
`Invitation sent to ${sanitizeDisplay(invitation.email)} as ${ROLE_NAMES[invitation.roleSlug]}`
|
|
51444
52138
|
)
|
|
51445
52139
|
);
|
|
51446
52140
|
console.log(` Invitation ID: ${sanitizeDisplay(invitation.invitationId)}`);
|
|
@@ -51466,20 +52160,16 @@ async function runInvite(emailArg, options) {
|
|
|
51466
52160
|
outputInvitation(result.body, output);
|
|
51467
52161
|
}
|
|
51468
52162
|
function createOrgInviteCommand() {
|
|
51469
|
-
return new Command("invite").description("Invite someone to the active organization by email").argument("<email>", "Email address to invite").option(
|
|
51470
|
-
"-r, --role <role>",
|
|
51471
|
-
`Role to grant: ${MEMBER_ROLE_SLUGS.join(", ")}`,
|
|
51472
|
-
DEFAULT_INVITE_ROLE
|
|
51473
|
-
).option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
|
|
52163
|
+
return new Command("invite").description("Invite someone to the active organization by email").argument("<email>", "Email address to invite").option("-r, --role <role>", `Role to grant: ${ROLE_CHOICES}`, DEFAULT_INVITE_ROLE).option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
|
|
51474
52164
|
"after",
|
|
51475
52165
|
`
|
|
51476
52166
|
Sends the same invitation email as the dashboard's Settings > Members page.
|
|
51477
|
-
Requires an organization admin
|
|
51478
|
-
API keys are rejected.
|
|
52167
|
+
Requires an organization admin signed in with \`tracecli auth login\`;
|
|
52168
|
+
API keys are rejected.
|
|
51479
52169
|
|
|
51480
52170
|
Examples:
|
|
51481
52171
|
tracecli org invite dev@acme.com
|
|
51482
|
-
tracecli org invite sec@acme.com --role
|
|
52172
|
+
tracecli org invite sec@acme.com --role manager
|
|
51483
52173
|
tracecli org invite cto@acme.com --role admin --output json`
|
|
51484
52174
|
).action(async (email3, options) => {
|
|
51485
52175
|
await runInvite(email3, options);
|
|
@@ -52806,7 +53496,7 @@ function extractCommandTree(cmd) {
|
|
|
52806
53496
|
description: o2.description,
|
|
52807
53497
|
takesValue: o2.required || o2.optional
|
|
52808
53498
|
}));
|
|
52809
|
-
const subcommands = cmd.commands.filter((
|
|
53499
|
+
const subcommands = cmd.commands.filter((c86) => !c86._hidden).map((c86) => extractCommandTree(c86));
|
|
52810
53500
|
return {
|
|
52811
53501
|
name: cmd.name(),
|
|
52812
53502
|
description: cmd.description(),
|
|
@@ -52872,7 +53562,7 @@ function generateBashCompletion(tree, binName) {
|
|
|
52872
53562
|
}
|
|
52873
53563
|
function collectBashCases(tree, prefix) {
|
|
52874
53564
|
const cases = /* @__PURE__ */ new Map();
|
|
52875
|
-
const subcommandNames = tree.subcommands.map((
|
|
53565
|
+
const subcommandNames = tree.subcommands.map((c86) => c86.name);
|
|
52876
53566
|
const optionNames = tree.options.flatMap((o2) => o2.short ? [o2.long, o2.short] : [o2.long]);
|
|
52877
53567
|
const extraOptions = prefix === "" ? ["--help", "--version"] : ["--help"];
|
|
52878
53568
|
const allOptions = [.../* @__PURE__ */ new Set([...optionNames, ...extraOptions])];
|
|
@@ -53178,17 +53868,17 @@ function validateInboxLabel(label) {
|
|
|
53178
53868
|
function buildCreateInboxBody(label) {
|
|
53179
53869
|
return { label };
|
|
53180
53870
|
}
|
|
53871
|
+
function forbiddenMessage(verb, needsEntitlement) {
|
|
53872
|
+
const where = needsEntitlement ? " on a pentest-enabled organization" : "";
|
|
53873
|
+
return `Only an organization admin or Manager (or Trace staff)${where} can ${verb}.`;
|
|
53874
|
+
}
|
|
53181
53875
|
function failWriteOp2(action, status, body, notFoundLabel) {
|
|
53182
53876
|
const { message, errorCode } = readErrorFields(body);
|
|
53183
53877
|
if (status === UNAUTHORIZED_STATUS2) {
|
|
53184
53878
|
exitAuthFailed();
|
|
53185
53879
|
}
|
|
53186
53880
|
if (status === 403) {
|
|
53187
|
-
console.error(
|
|
53188
|
-
colorError(
|
|
53189
|
-
`Only an organization admin (or Trace staff) on a pentest-enabled organization can ${action} inboxes.`
|
|
53190
|
-
)
|
|
53191
|
-
);
|
|
53881
|
+
console.error(colorError(forbiddenMessage(`${action} inboxes`, true)));
|
|
53192
53882
|
process.exit(1);
|
|
53193
53883
|
}
|
|
53194
53884
|
if (status === 404) {
|
|
@@ -53240,7 +53930,7 @@ function failReadOp2(action, status, body, notFoundLabel) {
|
|
|
53240
53930
|
exitAuthFailed();
|
|
53241
53931
|
}
|
|
53242
53932
|
if (status === 403) {
|
|
53243
|
-
console.error(colorError(
|
|
53933
|
+
console.error(colorError(forbiddenMessage(action, action !== "list inboxes")));
|
|
53244
53934
|
process.exit(1);
|
|
53245
53935
|
}
|
|
53246
53936
|
if (status === 404) {
|
|
@@ -53287,9 +53977,9 @@ function buildInboxesTable(inboxes) {
|
|
|
53287
53977
|
address: sanitizeDisplay(inbox.address),
|
|
53288
53978
|
label: sanitizeDisplay(inbox.label)
|
|
53289
53979
|
}));
|
|
53290
|
-
const addressWidth = Math.max(7, ...cells.map((
|
|
53980
|
+
const addressWidth = Math.max(7, ...cells.map((c86) => c86.address.length));
|
|
53291
53981
|
const header = `${"ADDRESS".padEnd(addressWidth)} LABEL`;
|
|
53292
|
-
const rows = cells.map((
|
|
53982
|
+
const rows = cells.map((c86) => `${c86.address.padEnd(addressWidth)} ${c86.label}`);
|
|
53293
53983
|
return { header, rows };
|
|
53294
53984
|
}
|
|
53295
53985
|
function formatInboxQuota(quota) {
|
|
@@ -53313,14 +54003,14 @@ function buildInboxEmailsTable(messages) {
|
|
|
53313
54003
|
subject: sanitizeDisplay(message.subject ?? ""),
|
|
53314
54004
|
unread: message.unread ? "yes" : "no"
|
|
53315
54005
|
}));
|
|
53316
|
-
const idWidth = Math.max(2, ...cells.map((
|
|
53317
|
-
const receivedWidth = Math.max(8, ...cells.map((
|
|
53318
|
-
const fromWidth = Math.max(4, ...cells.map((
|
|
53319
|
-
const toWidth = Math.max(2, ...cells.map((
|
|
53320
|
-
const subjectWidth = Math.max(7, ...cells.map((
|
|
54006
|
+
const idWidth = Math.max(2, ...cells.map((c86) => c86.id.length));
|
|
54007
|
+
const receivedWidth = Math.max(8, ...cells.map((c86) => c86.received.length));
|
|
54008
|
+
const fromWidth = Math.max(4, ...cells.map((c86) => c86.from.length));
|
|
54009
|
+
const toWidth = Math.max(2, ...cells.map((c86) => c86.to.length));
|
|
54010
|
+
const subjectWidth = Math.max(7, ...cells.map((c86) => c86.subject.length));
|
|
53321
54011
|
const header = `${"ID".padEnd(idWidth)} ${"RECEIVED".padEnd(receivedWidth)} ${"FROM".padEnd(fromWidth)} ${"TO".padEnd(toWidth)} ${"SUBJECT".padEnd(subjectWidth)} UNREAD`;
|
|
53322
54012
|
const rows = cells.map(
|
|
53323
|
-
(
|
|
54013
|
+
(c86) => `${c86.id.padEnd(idWidth)} ${c86.received.padEnd(receivedWidth)} ${c86.from.padEnd(fromWidth)} ${c86.to.padEnd(toWidth)} ${c86.subject.padEnd(subjectWidth)} ${c86.unread}`
|
|
53324
54014
|
);
|
|
53325
54015
|
return { header, rows };
|
|
53326
54016
|
}
|
|
@@ -53974,6 +54664,46 @@ function anySecretFlag(opts) {
|
|
|
53974
54664
|
function anyPasswordFlag(opts) {
|
|
53975
54665
|
return opts.passwordStdin === true || opts.passwordFile !== void 0 || opts.passwordEnv !== void 0;
|
|
53976
54666
|
}
|
|
54667
|
+
function anyUsernameFlag(opts) {
|
|
54668
|
+
return opts.usernameStdin === true || opts.usernameFile !== void 0 || opts.usernameEnv !== void 0;
|
|
54669
|
+
}
|
|
54670
|
+
function anySecretValueFlag(opts) {
|
|
54671
|
+
return opts.secretStdin === true || opts.secretFile !== void 0 || opts.secretEnv !== void 0;
|
|
54672
|
+
}
|
|
54673
|
+
function withArticle(kebab) {
|
|
54674
|
+
return `${/^(api|ssh)-/.test(kebab) ? "An" : "A"} ${kebab}`;
|
|
54675
|
+
}
|
|
54676
|
+
function rotateFlagProblem(type, opts) {
|
|
54677
|
+
const kebab = credentialTypeKebab(type);
|
|
54678
|
+
if (type === "USERNAME_PASSWORD") {
|
|
54679
|
+
if (anySecretValueFlag(opts)) {
|
|
54680
|
+
return `${withArticle(kebab)} credential takes --username-* and --password-*, not --secret-*.`;
|
|
54681
|
+
}
|
|
54682
|
+
if (!anyUsernameFlag(opts) || !anyPasswordFlag(opts)) {
|
|
54683
|
+
return "Pass both --username-* and --password-*: the login is replaced as a pair.";
|
|
54684
|
+
}
|
|
54685
|
+
if (usesStdin(usernameOpts(opts)) && usesStdin(passwordOpts(opts))) {
|
|
54686
|
+
return "Only one secret can come from stdin. Use --username-file/-env for the other.";
|
|
54687
|
+
}
|
|
54688
|
+
return null;
|
|
54689
|
+
}
|
|
54690
|
+
if (anyUsernameFlag(opts)) {
|
|
54691
|
+
return `${withArticle(kebab)} credential has no username. Pass the new secret with --secret-*.`;
|
|
54692
|
+
}
|
|
54693
|
+
if (type === "SSH_PRIVATE_KEY") {
|
|
54694
|
+
if (!anySecretValueFlag(opts)) {
|
|
54695
|
+
return "Pass the key with --secret-* too: an SSH key and its passphrase are replaced together.";
|
|
54696
|
+
}
|
|
54697
|
+
if (usesStdin(secretOpts(opts)) && usesStdin(passwordOpts(opts))) {
|
|
54698
|
+
return "Only one secret can come from stdin. Use --password-file/-env for the passphrase.";
|
|
54699
|
+
}
|
|
54700
|
+
return null;
|
|
54701
|
+
}
|
|
54702
|
+
if (anyPasswordFlag(opts)) {
|
|
54703
|
+
return `${withArticle(kebab)} credential has no password. Pass the new secret with --secret-*.`;
|
|
54704
|
+
}
|
|
54705
|
+
return null;
|
|
54706
|
+
}
|
|
53977
54707
|
function secretOpts(opts) {
|
|
53978
54708
|
return { stdin: opts.secretStdin, file: opts.secretFile, env: opts.secretEnv };
|
|
53979
54709
|
}
|
|
@@ -53989,7 +54719,11 @@ function failWriteOp3(action, status, body, notFoundLabel) {
|
|
|
53989
54719
|
exitAuthFailed();
|
|
53990
54720
|
}
|
|
53991
54721
|
if (status === 403) {
|
|
53992
|
-
console.error(
|
|
54722
|
+
console.error(
|
|
54723
|
+
colorError(
|
|
54724
|
+
`You can't ${action} credentials here. That needs an organization admin signed in with \`tracecli auth login\`; API keys are rejected.`
|
|
54725
|
+
)
|
|
54726
|
+
);
|
|
53993
54727
|
process.exit(1);
|
|
53994
54728
|
}
|
|
53995
54729
|
if (status === 404) {
|
|
@@ -54103,16 +54837,16 @@ function printCredentialsTsv(creds) {
|
|
|
54103
54837
|
}
|
|
54104
54838
|
}
|
|
54105
54839
|
function buildCredentialsTable(creds) {
|
|
54106
|
-
const cells = creds.map((
|
|
54107
|
-
id:
|
|
54108
|
-
label: sanitizeDisplay(
|
|
54109
|
-
type:
|
|
54840
|
+
const cells = creds.map((c86) => ({
|
|
54841
|
+
id: c86.credentialId,
|
|
54842
|
+
label: sanitizeDisplay(c86.label),
|
|
54843
|
+
type: c86.credentialType
|
|
54110
54844
|
}));
|
|
54111
|
-
const idWidth = Math.max(2, ...cells.map((
|
|
54112
|
-
const labelWidth = Math.max(5, ...cells.map((
|
|
54845
|
+
const idWidth = Math.max(2, ...cells.map((c86) => c86.id.length));
|
|
54846
|
+
const labelWidth = Math.max(5, ...cells.map((c86) => c86.label.length));
|
|
54113
54847
|
const header = `${"ID".padEnd(idWidth)} ${"LABEL".padEnd(labelWidth)} TYPE`;
|
|
54114
54848
|
const rows = cells.map(
|
|
54115
|
-
(
|
|
54849
|
+
(c86) => `${c86.id.padEnd(idWidth)} ${c86.label.padEnd(labelWidth)} ${c86.type}`
|
|
54116
54850
|
);
|
|
54117
54851
|
return { header, rows };
|
|
54118
54852
|
}
|
|
@@ -54306,6 +55040,43 @@ async function buildCreateBody(type, label, options) {
|
|
|
54306
55040
|
}
|
|
54307
55041
|
}
|
|
54308
55042
|
}
|
|
55043
|
+
async function buildRotateBody(type, options) {
|
|
55044
|
+
switch (type) {
|
|
55045
|
+
case "USERNAME_PASSWORD": {
|
|
55046
|
+
const username = await resolveSecret("username", "username", usernameOpts(options));
|
|
55047
|
+
const password2 = await resolveSecret("password", "password", passwordOpts(options));
|
|
55048
|
+
return { credentialType: type, username, password: password2 };
|
|
55049
|
+
}
|
|
55050
|
+
case "SSH_PRIVATE_KEY": {
|
|
55051
|
+
const privateKeyPem = await resolveSecret("private key PEM", "secret", secretOpts(options));
|
|
55052
|
+
const passphrase = anyPasswordFlag(options) ? await resolveSecret("key passphrase", "password", passwordOpts(options)) : void 0;
|
|
55053
|
+
return {
|
|
55054
|
+
credentialType: type,
|
|
55055
|
+
privateKeyPem,
|
|
55056
|
+
...passphrase !== void 0 ? { passphrase } : {}
|
|
55057
|
+
};
|
|
55058
|
+
}
|
|
55059
|
+
case "SESSION_STATE":
|
|
55060
|
+
return {
|
|
55061
|
+
credentialType: type,
|
|
55062
|
+
secretValue: await resolveSecret("session state capture", "secret", secretOpts(options))
|
|
55063
|
+
};
|
|
55064
|
+
case "MAGIC_AUTH":
|
|
55065
|
+
return {
|
|
55066
|
+
credentialType: type,
|
|
55067
|
+
secretValue: await resolveSecret("test-account email", "secret", secretOpts(options))
|
|
55068
|
+
};
|
|
55069
|
+
case "BEARER_TOKEN":
|
|
55070
|
+
case "JWT_TOKEN":
|
|
55071
|
+
case "API_KEY":
|
|
55072
|
+
case "PASSPHRASE":
|
|
55073
|
+
case "COOKIE":
|
|
55074
|
+
return {
|
|
55075
|
+
credentialType: type,
|
|
55076
|
+
secretValue: await resolveSecret("secret value", "secret", secretOpts(options))
|
|
55077
|
+
};
|
|
55078
|
+
}
|
|
55079
|
+
}
|
|
54309
55080
|
async function runList3(options) {
|
|
54310
55081
|
const output = parseOutput(options.output);
|
|
54311
55082
|
requireEnvId(options.env);
|
|
@@ -54356,12 +55127,7 @@ async function runUpdate3(credentialId, options) {
|
|
|
54356
55127
|
const output = parseOutput(options.output);
|
|
54357
55128
|
requireEnvId(options.env);
|
|
54358
55129
|
requireCredId(credentialId);
|
|
54359
|
-
|
|
54360
|
-
console.error(
|
|
54361
|
-
colorError("Secrets are immutable on update. Delete and recreate the credential to rotate.")
|
|
54362
|
-
);
|
|
54363
|
-
process.exit(1);
|
|
54364
|
-
}
|
|
55130
|
+
const rotating = anySecretFlag(options);
|
|
54365
55131
|
if (options.clearAuthConfig && anyAuthFlag(options)) {
|
|
54366
55132
|
console.error(colorError("Pass either --clear-auth-config or auth-config flags, not both."));
|
|
54367
55133
|
process.exit(1);
|
|
@@ -54374,16 +55140,32 @@ async function runUpdate3(credentialId, options) {
|
|
|
54374
55140
|
}
|
|
54375
55141
|
const organizationId = await resolveOrganizationId();
|
|
54376
55142
|
const params3 = { organizationId, environmentId: options.env, credentialId };
|
|
55143
|
+
const current = rotating || !options.clearAuthConfig && anyAuthFlag(options) ? await authenticatedRequest((client) => client.credential.getCredential({ params: params3 })) : null;
|
|
55144
|
+
if (current && current.status !== SUCCESS_STATUS) {
|
|
55145
|
+
failReadOp3("get credential", current.status, current.body, credentialId);
|
|
55146
|
+
}
|
|
55147
|
+
let rotateBody;
|
|
55148
|
+
if (current && rotating) {
|
|
55149
|
+
const type = current.body.credentialType;
|
|
55150
|
+
const problem = rotateFlagProblem(type, options) ?? (options.clearAuthConfig && (type === "SSH_PRIVATE_KEY" || type === "SESSION_STATE") ? `${withArticle(credentialTypeKebab(type))} credential's auth config can't be cleared, so --clear-auth-config would fail after the secret had already changed.` : null);
|
|
55151
|
+
if (problem) {
|
|
55152
|
+
console.error(colorError(problem));
|
|
55153
|
+
process.exit(1);
|
|
55154
|
+
}
|
|
55155
|
+
try {
|
|
55156
|
+
rotateBody = await buildRotateBody(type, options);
|
|
55157
|
+
} catch (error48) {
|
|
55158
|
+
if (error48 instanceof SecretInputError) {
|
|
55159
|
+
console.error(colorError(error48.message));
|
|
55160
|
+
process.exit(1);
|
|
55161
|
+
}
|
|
55162
|
+
throw error48;
|
|
55163
|
+
}
|
|
55164
|
+
}
|
|
54377
55165
|
let authConfig;
|
|
54378
55166
|
if (options.clearAuthConfig) {
|
|
54379
55167
|
authConfig = null;
|
|
54380
|
-
} else if (anyAuthFlag(options)) {
|
|
54381
|
-
const current = await authenticatedRequest(
|
|
54382
|
-
(client) => client.credential.getCredential({ params: params3 })
|
|
54383
|
-
);
|
|
54384
|
-
if (current.status !== SUCCESS_STATUS) {
|
|
54385
|
-
failReadOp3("get credential", current.status, current.body, credentialId);
|
|
54386
|
-
}
|
|
55168
|
+
} else if (current && anyAuthFlag(options)) {
|
|
54387
55169
|
const type = current.body.credentialType;
|
|
54388
55170
|
const foreign = rejectForeignAuthFlags(type, options);
|
|
54389
55171
|
if (foreign) {
|
|
@@ -54403,24 +55185,44 @@ async function runUpdate3(credentialId, options) {
|
|
|
54403
55185
|
...options.moveEnv !== void 0 ? { environmentId: options.moveEnv } : {},
|
|
54404
55186
|
...authConfig !== void 0 ? { authConfig } : {}
|
|
54405
55187
|
};
|
|
54406
|
-
|
|
55188
|
+
const patching = Object.keys(body).length > 0;
|
|
55189
|
+
if (!rotateBody && !patching) {
|
|
54407
55190
|
console.error(
|
|
54408
55191
|
colorError(
|
|
54409
|
-
"Nothing to update. Pass --label, --move-env, auth-config flags,
|
|
55192
|
+
"Nothing to update. Pass --label, --move-env, auth-config flags, --clear-auth-config, or a new secret."
|
|
54410
55193
|
)
|
|
54411
55194
|
);
|
|
54412
55195
|
process.exit(1);
|
|
54413
55196
|
}
|
|
54414
|
-
|
|
54415
|
-
|
|
54416
|
-
|
|
54417
|
-
|
|
54418
|
-
|
|
55197
|
+
let updated;
|
|
55198
|
+
if (rotateBody) {
|
|
55199
|
+
const secret = rotateBody;
|
|
55200
|
+
const rotated = await authenticatedRequest(
|
|
55201
|
+
(client) => client.credential.rotateCredentialSecret({ params: params3, body: secret })
|
|
55202
|
+
);
|
|
55203
|
+
if (rotated.status !== SUCCESS_STATUS) {
|
|
55204
|
+
failWriteOp3("update", rotated.status, rotated.body, credentialId);
|
|
55205
|
+
}
|
|
55206
|
+
updated = rotated.body;
|
|
54419
55207
|
}
|
|
55208
|
+
if (patching) {
|
|
55209
|
+
const result = await authenticatedRequest(
|
|
55210
|
+
(client) => client.credential.updateCredential({ params: params3, body })
|
|
55211
|
+
);
|
|
55212
|
+
if (result.status !== SUCCESS_STATUS) {
|
|
55213
|
+
if (rotateBody) {
|
|
55214
|
+
console.error(colorError("The secret was rotated, but the other changes were not saved."));
|
|
55215
|
+
}
|
|
55216
|
+
failWriteOp3("update", result.status, result.body, credentialId);
|
|
55217
|
+
}
|
|
55218
|
+
updated = result.body;
|
|
55219
|
+
}
|
|
55220
|
+
if (!updated) return;
|
|
54420
55221
|
if (output === "table") {
|
|
54421
|
-
|
|
55222
|
+
const verb = rotateBody ? patching ? "Rotated the secret and updated" : "Rotated the secret of" : "Updated";
|
|
55223
|
+
console.log(colorSuccess(`${verb} credential ${sanitizeDisplay(updated.label)}`));
|
|
54422
55224
|
}
|
|
54423
|
-
outputCredential(
|
|
55225
|
+
outputCredential(updated, output);
|
|
54424
55226
|
}
|
|
54425
55227
|
function failMfaOp(action, status, body, credentialId) {
|
|
54426
55228
|
const { message, errorCode } = readErrorFields(body);
|
|
@@ -54547,7 +55349,7 @@ async function runDelete3(credentialId, options) {
|
|
|
54547
55349
|
}
|
|
54548
55350
|
console.log(colorSuccess(`Deleted credential ${credentialId}`));
|
|
54549
55351
|
}
|
|
54550
|
-
function
|
|
55352
|
+
function failLinkOp2(op, status, body, notFoundLabel) {
|
|
54551
55353
|
const { message, errorCode } = readErrorFields(body);
|
|
54552
55354
|
if (status === UNAUTHORIZED_STATUS2) {
|
|
54553
55355
|
exitAuthFailed();
|
|
@@ -54654,13 +55456,13 @@ function buildCredentialLinksTable(links) {
|
|
|
54654
55456
|
source: sourceDisplay(link.source),
|
|
54655
55457
|
via: link.environmentCredentialSourceId ? "link-all" : ""
|
|
54656
55458
|
}));
|
|
54657
|
-
const idWidth = Math.max("LINK ID".length, ...cells.map((
|
|
54658
|
-
const labelWidth = Math.max("LABEL".length, ...cells.map((
|
|
54659
|
-
const typeWidth = Math.max("TYPE".length, ...cells.map((
|
|
54660
|
-
const sourceWidth = Math.max("SOURCE".length, ...cells.map((
|
|
55459
|
+
const idWidth = Math.max("LINK ID".length, ...cells.map((c86) => c86.id.length));
|
|
55460
|
+
const labelWidth = Math.max("LABEL".length, ...cells.map((c86) => c86.label.length));
|
|
55461
|
+
const typeWidth = Math.max("TYPE".length, ...cells.map((c86) => c86.type.length));
|
|
55462
|
+
const sourceWidth = Math.max("SOURCE".length, ...cells.map((c86) => c86.source.length));
|
|
54661
55463
|
const header = `${"LINK ID".padEnd(idWidth)} ${"LABEL".padEnd(labelWidth)} ${"TYPE".padEnd(typeWidth)} ${"SOURCE".padEnd(sourceWidth)} VIA`;
|
|
54662
55464
|
const rows = cells.map(
|
|
54663
|
-
(
|
|
55465
|
+
(c86) => `${c86.id.padEnd(idWidth)} ${c86.label.padEnd(labelWidth)} ${c86.type.padEnd(typeWidth)} ${c86.source.padEnd(sourceWidth)} ${c86.via}`.trimEnd()
|
|
54664
55466
|
);
|
|
54665
55467
|
return { header, rows };
|
|
54666
55468
|
}
|
|
@@ -54714,17 +55516,17 @@ function buildLinkableCredentialsTable(creds) {
|
|
|
54714
55516
|
}),
|
|
54715
55517
|
linked: cred.alreadyLinked ? "linked" : ""
|
|
54716
55518
|
}));
|
|
54717
|
-
const idWidth = Math.max("ID".length, ...cells.map((
|
|
54718
|
-
const labelWidth = Math.max("LABEL".length, ...cells.map((
|
|
54719
|
-
const typeWidth = Math.max("TYPE".length, ...cells.map((
|
|
54720
|
-
const sourceWidth = Math.max("SOURCE".length, ...cells.map((
|
|
55519
|
+
const idWidth = Math.max("ID".length, ...cells.map((c86) => c86.id.length));
|
|
55520
|
+
const labelWidth = Math.max("LABEL".length, ...cells.map((c86) => c86.label.length));
|
|
55521
|
+
const typeWidth = Math.max("TYPE".length, ...cells.map((c86) => c86.type.length));
|
|
55522
|
+
const sourceWidth = Math.max("SOURCE".length, ...cells.map((c86) => c86.source.length));
|
|
54721
55523
|
const header = `${"ID".padEnd(idWidth)} ${"LABEL".padEnd(labelWidth)} ${"TYPE".padEnd(typeWidth)} ${"SOURCE".padEnd(sourceWidth)} STATUS`;
|
|
54722
55524
|
const rows = cells.map(
|
|
54723
|
-
(
|
|
55525
|
+
(c86) => `${c86.id.padEnd(idWidth)} ${c86.label.padEnd(labelWidth)} ${c86.type.padEnd(typeWidth)} ${c86.source.padEnd(sourceWidth)} ${c86.linked}`.trimEnd()
|
|
54724
55526
|
);
|
|
54725
55527
|
return { header, rows };
|
|
54726
55528
|
}
|
|
54727
|
-
async function
|
|
55529
|
+
async function runLink2(credentialId, options) {
|
|
54728
55530
|
const output = parseOutput(options.output);
|
|
54729
55531
|
requireEnvId(options.env);
|
|
54730
55532
|
requireCredId(credentialId);
|
|
@@ -54736,7 +55538,7 @@ async function runLink(credentialId, options) {
|
|
|
54736
55538
|
})
|
|
54737
55539
|
);
|
|
54738
55540
|
if (result.status !== CREATED_STATUS) {
|
|
54739
|
-
|
|
55541
|
+
failLinkOp2("link", result.status, result.body, credentialId);
|
|
54740
55542
|
}
|
|
54741
55543
|
if (output === "table") {
|
|
54742
55544
|
console.log(
|
|
@@ -54747,7 +55549,7 @@ async function runLink(credentialId, options) {
|
|
|
54747
55549
|
}
|
|
54748
55550
|
outputCredentialLink(result.body, output);
|
|
54749
55551
|
}
|
|
54750
|
-
async function
|
|
55552
|
+
async function runUnlink2(credentialLinkId, options) {
|
|
54751
55553
|
requireEnvId(options.env);
|
|
54752
55554
|
requireLinkId(credentialLinkId);
|
|
54753
55555
|
const confirmed = await confirmAction(
|
|
@@ -54768,7 +55570,7 @@ async function runUnlink(credentialLinkId, options) {
|
|
|
54768
55570
|
if (result.status === 409 && readErrorFields(result.body).errorCode === "CREDENTIAL_LINKED_BY_RULE") {
|
|
54769
55571
|
await failLinkedByRule(organizationId, options.env, result.body);
|
|
54770
55572
|
}
|
|
54771
|
-
|
|
55573
|
+
failLinkOp2("unlink", result.status, result.body, credentialLinkId);
|
|
54772
55574
|
}
|
|
54773
55575
|
console.log(colorSuccess(`Unlinked credential link ${credentialLinkId}`));
|
|
54774
55576
|
}
|
|
@@ -54916,12 +55718,12 @@ function buildLinkableEnvironmentsTable(envs) {
|
|
|
54916
55718
|
count: String(env2.credentialCount),
|
|
54917
55719
|
linked: env2.alreadyLinked ? "linked" : ""
|
|
54918
55720
|
}));
|
|
54919
|
-
const idWidth = Math.max("ENVIRONMENT ID".length, ...cells.map((
|
|
54920
|
-
const nameWidth = Math.max("ENVIRONMENT".length, ...cells.map((
|
|
55721
|
+
const idWidth = Math.max("ENVIRONMENT ID".length, ...cells.map((c86) => c86.id.length));
|
|
55722
|
+
const nameWidth = Math.max("ENVIRONMENT".length, ...cells.map((c86) => c86.name.length));
|
|
54921
55723
|
const countWidth = "CREDENTIALS".length;
|
|
54922
55724
|
const header = `${"ENVIRONMENT ID".padEnd(idWidth)} ${"ENVIRONMENT".padEnd(nameWidth)} ${"CREDENTIALS".padEnd(countWidth)} STATUS`;
|
|
54923
55725
|
const rows = cells.map(
|
|
54924
|
-
(
|
|
55726
|
+
(c86) => `${c86.id.padEnd(idWidth)} ${c86.name.padEnd(nameWidth)} ${c86.count.padEnd(countWidth)} ${c86.linked}`.trimEnd()
|
|
54925
55727
|
);
|
|
54926
55728
|
return { header, rows };
|
|
54927
55729
|
}
|
|
@@ -54980,7 +55782,7 @@ async function runLinkAll(sourceEnvironmentId, options) {
|
|
|
54980
55782
|
})
|
|
54981
55783
|
);
|
|
54982
55784
|
if (result.status !== CREATED_STATUS) {
|
|
54983
|
-
|
|
55785
|
+
failLinkOp2("link all", result.status, result.body, sourceEnvironmentId);
|
|
54984
55786
|
}
|
|
54985
55787
|
const rule = result.body;
|
|
54986
55788
|
if (output === "json") {
|
|
@@ -55045,7 +55847,7 @@ async function runUnlinkAll(sourceEnvironmentId, options) {
|
|
|
55045
55847
|
})
|
|
55046
55848
|
);
|
|
55047
55849
|
if (result.status !== NO_CONTENT_STATUS) {
|
|
55048
|
-
|
|
55850
|
+
failLinkOp2("unlink all", result.status, result.body, rule.environmentCredentialSourceId);
|
|
55049
55851
|
}
|
|
55050
55852
|
console.log(
|
|
55051
55853
|
colorSuccess(
|
|
@@ -55101,18 +55903,22 @@ function createGetCommand2() {
|
|
|
55101
55903
|
});
|
|
55102
55904
|
}
|
|
55103
55905
|
function createUpdateCommand2() {
|
|
55104
|
-
const command = new Command("update").description("Update a credential (label, environment,
|
|
55906
|
+
const command = new Command("update").description("Update a credential (label, environment, auth config, or secret)").argument("<credentialId>", "Credential UUID").requiredOption("--env <environmentId>", "Current parent environment UUID").option("--label <label>", "New label").option("--move-env <environmentId>", "Move to a different environment (same application)").option("--clear-auth-config", "Remove the auth config (sends null)").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table");
|
|
55105
55907
|
addSecretInputOptions(command);
|
|
55106
55908
|
addAuthConfigOptions(command).addHelpText(
|
|
55107
55909
|
"after",
|
|
55108
55910
|
`
|
|
55109
55911
|
Auth-config flags must match the credential's existing type (looked up automatically).
|
|
55110
|
-
|
|
55912
|
+
A secret flag rotates the secret in place: the credential keeps its ID and scan history.
|
|
55913
|
+
A username/password credential takes both --username-* and --password-*; an SSH key
|
|
55914
|
+
takes --secret-* for the key and --password-* for its passphrase, if it has one.
|
|
55111
55915
|
|
|
55112
55916
|
Examples:
|
|
55113
55917
|
tracecli credential update <id> --env <envId> --label "prod (rotated 2026-06)"
|
|
55114
55918
|
tracecli credential update <id> --env <envId> --login-url https://acme.com/signin
|
|
55115
|
-
tracecli credential update <id> --env <envId> --clear-auth-config
|
|
55919
|
+
tracecli credential update <id> --env <envId> --clear-auth-config
|
|
55920
|
+
vault read -field=token secret/x | tracecli credential update <id> --env <envId> --secret-stdin
|
|
55921
|
+
tracecli credential update <id> --env <envId> --username-env LOGIN_USER --password-env LOGIN_PASS`
|
|
55116
55922
|
);
|
|
55117
55923
|
return command.action(async (credentialId, options) => {
|
|
55118
55924
|
await runUpdate3(credentialId, options);
|
|
@@ -55163,7 +55969,7 @@ left \u2014 if the current window is nearly over, the API waits for the next one
|
|
|
55163
55969
|
await runMfaCode(credentialId, options);
|
|
55164
55970
|
});
|
|
55165
55971
|
}
|
|
55166
|
-
function
|
|
55972
|
+
function createLinkCommand2() {
|
|
55167
55973
|
return new Command("link").description("Link another application's credential into an environment").argument("<credentialId>", "UUID of the credential to link (owned by another environment)").requiredOption("--env <environmentId>", "Environment UUID to link it into").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
|
|
55168
55974
|
"after",
|
|
55169
55975
|
`
|
|
@@ -55180,10 +55986,10 @@ Examples:
|
|
|
55180
55986
|
tracecli credential linkable --env <envId>
|
|
55181
55987
|
tracecli credential link <credentialId> --env <envId>`
|
|
55182
55988
|
).action(async (credentialId, options) => {
|
|
55183
|
-
await
|
|
55989
|
+
await runLink2(credentialId, options);
|
|
55184
55990
|
});
|
|
55185
55991
|
}
|
|
55186
|
-
function
|
|
55992
|
+
function createUnlinkCommand2() {
|
|
55187
55993
|
return new Command("unlink").description("Remove a credential link from an environment (the source credential is kept)").argument("<credentialLinkId>", "Credential link UUID (the LINK ID from `credential links`)").requiredOption("--env <environmentId>", "Environment UUID the credential is linked into").option("-y, --yes", "Skip the confirmation prompt (required in non-interactive shells)").addHelpText(
|
|
55188
55994
|
"after",
|
|
55189
55995
|
`
|
|
@@ -55192,7 +55998,7 @@ the environment's own credentials. A credential whose whole environment is
|
|
|
55192
55998
|
linked here (VIA link-all in \`credential links\`) stays until that is removed
|
|
55193
55999
|
with \`credential unlink-all\`.`
|
|
55194
56000
|
).action(async (credentialLinkId, options) => {
|
|
55195
|
-
await
|
|
56001
|
+
await runUnlink2(credentialLinkId, options);
|
|
55196
56002
|
});
|
|
55197
56003
|
}
|
|
55198
56004
|
function createLinksCommand() {
|
|
@@ -55256,8 +56062,8 @@ function createCredentialCommand() {
|
|
|
55256
56062
|
credential.addCommand(createSetMfaCommand());
|
|
55257
56063
|
credential.addCommand(createClearMfaCommand());
|
|
55258
56064
|
credential.addCommand(createMfaCodeCommand());
|
|
55259
|
-
credential.addCommand(
|
|
55260
|
-
credential.addCommand(
|
|
56065
|
+
credential.addCommand(createLinkCommand2());
|
|
56066
|
+
credential.addCommand(createUnlinkCommand2());
|
|
55261
56067
|
credential.addCommand(createLinkAllCommand());
|
|
55262
56068
|
credential.addCommand(createUnlinkAllCommand());
|
|
55263
56069
|
credential.addCommand(createLinksCommand());
|
|
@@ -55477,14 +56283,14 @@ function buildEnvironmentTable(envs, leading) {
|
|
|
55477
56283
|
url: e.primaryUrl != null ? sanitizeDisplay(e.primaryUrl) : "\u2014"
|
|
55478
56284
|
}));
|
|
55479
56285
|
const leadingWidths = leading.map(
|
|
55480
|
-
(column, i2) => Math.max(column.header.length, ...cells.map((
|
|
56286
|
+
(column, i2) => Math.max(column.header.length, ...cells.map((c86) => c86.leading[i2]?.length ?? 0))
|
|
55481
56287
|
);
|
|
55482
|
-
const nameWidth = Math.max(4, ...cells.map((
|
|
56288
|
+
const nameWidth = Math.max(4, ...cells.map((c86) => c86.name.length));
|
|
55483
56289
|
const padLeading = (values) => values.map((v, i2) => v.padEnd(leadingWidths[i2] ?? 0)).join(" ");
|
|
55484
56290
|
return {
|
|
55485
|
-
header: `${padLeading(leading.map((
|
|
56291
|
+
header: `${padLeading(leading.map((c86) => c86.header))} ${"NAME".padEnd(nameWidth)} PROD URL`,
|
|
55486
56292
|
rows: cells.map(
|
|
55487
|
-
(
|
|
56293
|
+
(c86) => `${padLeading(c86.leading)} ${c86.name.padEnd(nameWidth)} ${c86.prod.padEnd(4)} ${c86.url}`
|
|
55488
56294
|
)
|
|
55489
56295
|
};
|
|
55490
56296
|
}
|
|
@@ -59119,7 +59925,7 @@ function createFindingsCommand() {
|
|
|
59119
59925
|
findings.addCommand(createGetFindingCommand());
|
|
59120
59926
|
findings.addCommand(createGetFindingReproCommand());
|
|
59121
59927
|
findings.addCommand(createStatusUpdateCommand());
|
|
59122
|
-
findings.addCommand(createAttachEvidenceCommand());
|
|
59928
|
+
findings.addCommand(createAttachEvidenceCommand(), { hidden: true });
|
|
59123
59929
|
findings.addCommand(createCreateFindingCommand(), { hidden: true });
|
|
59124
59930
|
findings.addCommand(createCopyFindingsCommand(), { hidden: true });
|
|
59125
59931
|
findings.addCommand(createPublishFindingsCommand(), { hidden: true });
|
|
@@ -59503,7 +60309,7 @@ function resolveQuestionnaireMode(options) {
|
|
|
59503
60309
|
];
|
|
59504
60310
|
const chosen = exclusive.filter((entry) => entry.set);
|
|
59505
60311
|
if (chosen.length > 1) {
|
|
59506
|
-
console.error(colorError(`Pass only one of ${chosen.map((
|
|
60312
|
+
console.error(colorError(`Pass only one of ${chosen.map((c86) => c86.flag).join(" / ")}.`));
|
|
59507
60313
|
process.exit(1);
|
|
59508
60314
|
}
|
|
59509
60315
|
const only = chosen[0];
|
|
@@ -59671,7 +60477,7 @@ Examples:
|
|
|
59671
60477
|
function createPentestCommand() {
|
|
59672
60478
|
const pentest = new Command("pentest").description("Manage pentests");
|
|
59673
60479
|
pentest.addCommand(createListCommand7());
|
|
59674
|
-
pentest.addCommand(createUpdateCommand4());
|
|
60480
|
+
pentest.addCommand(createUpdateCommand4(), { hidden: true });
|
|
59675
60481
|
pentest.addCommand(createCreatePentestCommand(), { hidden: true });
|
|
59676
60482
|
pentest.addCommand(createVisibilityCommand(), { hidden: true });
|
|
59677
60483
|
pentest.addCommand(createQuestionnaireCommand());
|
|
@@ -60737,13 +61543,13 @@ function buildUploadsTable(uploads) {
|
|
|
60737
61543
|
size: formatArchiveBytes(upload.sizeBytes),
|
|
60738
61544
|
id: upload.codeUploadId
|
|
60739
61545
|
}));
|
|
60740
|
-
const nameWidth = Math.max(4, ...cells.map((
|
|
60741
|
-
const kindWidth = Math.max(4, ...cells.map((
|
|
60742
|
-
const statusWidth = Math.max(6, ...cells.map((
|
|
60743
|
-
const sizeWidth = Math.max(4, ...cells.map((
|
|
61546
|
+
const nameWidth = Math.max(4, ...cells.map((c86) => c86.name.length));
|
|
61547
|
+
const kindWidth = Math.max(4, ...cells.map((c86) => c86.kind.length));
|
|
61548
|
+
const statusWidth = Math.max(6, ...cells.map((c86) => c86.status.length));
|
|
61549
|
+
const sizeWidth = Math.max(4, ...cells.map((c86) => c86.size.length));
|
|
60744
61550
|
const header = `${"NAME".padEnd(nameWidth)} ${"KIND".padEnd(kindWidth)} ${"STATUS".padEnd(statusWidth)} ${"SIZE".padEnd(sizeWidth)} ID`;
|
|
60745
61551
|
const rows = cells.map(
|
|
60746
|
-
(
|
|
61552
|
+
(c86) => `${c86.name.padEnd(nameWidth)} ${c86.kind.padEnd(kindWidth)} ${c86.status.padEnd(statusWidth)} ${c86.size.padEnd(sizeWidth)} ${c86.id}`
|
|
60747
61553
|
);
|
|
60748
61554
|
return { header, rows };
|
|
60749
61555
|
}
|
|
@@ -61230,7 +62036,7 @@ async function runDelete5(codeUploadIdArg, options) {
|
|
|
61230
62036
|
}
|
|
61231
62037
|
console.log(colorSuccess(`Deleted upload ${codeUploadId}`));
|
|
61232
62038
|
}
|
|
61233
|
-
async function
|
|
62039
|
+
async function runLink3(options) {
|
|
61234
62040
|
const output = parseOutput(options.output);
|
|
61235
62041
|
const applicationId = requireUuid(options.app, "--app");
|
|
61236
62042
|
const codeUploadId = requireUuid(options.upload, "--upload");
|
|
@@ -61362,7 +62168,7 @@ function createDeleteCommand5() {
|
|
|
61362
62168
|
await runDelete5(codeUploadId, options);
|
|
61363
62169
|
});
|
|
61364
62170
|
}
|
|
61365
|
-
function
|
|
62171
|
+
function createLinkCommand3() {
|
|
61366
62172
|
return new Command("link").description("Link a ready source upload to an application").requiredOption("--app <applicationId>", "Application UUID").requiredOption("--upload <codeUploadId>", "Upload UUID (must be a ready source ZIP)").option("--path <repositoryPath>", "Path within the archive").option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
|
|
61367
62173
|
"after",
|
|
61368
62174
|
`
|
|
@@ -61372,7 +62178,7 @@ APK and IPA builds attach to an application with \`upload build --app\`.
|
|
|
61372
62178
|
Examples:
|
|
61373
62179
|
tracecli upload link --app <applicationId> --upload <codeUploadId>`
|
|
61374
62180
|
).action(async (options) => {
|
|
61375
|
-
await
|
|
62181
|
+
await runLink3(options);
|
|
61376
62182
|
});
|
|
61377
62183
|
}
|
|
61378
62184
|
function createUploadCommand(runtime = {}) {
|
|
@@ -61386,7 +62192,7 @@ function createUploadCommand(runtime = {}) {
|
|
|
61386
62192
|
upload.addCommand(createResumeCommand(resolved));
|
|
61387
62193
|
upload.addCommand(createWaitCommand(resolved));
|
|
61388
62194
|
upload.addCommand(createDeleteCommand5());
|
|
61389
|
-
upload.addCommand(
|
|
62195
|
+
upload.addCommand(createLinkCommand3());
|
|
61390
62196
|
return upload;
|
|
61391
62197
|
}
|
|
61392
62198
|
|
|
@@ -61405,7 +62211,7 @@ function parseVulnerabilityFilter(expression) {
|
|
|
61405
62211
|
const match = expression.match(/^([^!=]+)(!=|=)(.+)$/);
|
|
61406
62212
|
if (!match?.[1] || !match[2] || !match[3]) {
|
|
61407
62213
|
return {
|
|
61408
|
-
error: `Invalid filter expression '${expression}'. Expected format: field=value or field!=value (e.g.
|
|
62214
|
+
error: `Invalid filter expression '${expression}'. Expected format: field=value or field!=value (e.g. scanMode=SAST).`
|
|
61409
62215
|
};
|
|
61410
62216
|
}
|
|
61411
62217
|
const field = match[1].trim();
|
|
@@ -61646,7 +62452,7 @@ function createListCommand9() {
|
|
|
61646
62452
|
}
|
|
61647
62453
|
).option(
|
|
61648
62454
|
"-f, --filter <expression>",
|
|
61649
|
-
"Additional filter expression: field=value or field!=value. Repeatable. Supported fields:
|
|
62455
|
+
"Additional filter expression: field=value or field!=value. Repeatable. Supported fields: scanMode (SAST, SCA, SECRETS, DAST), severity, status, repositoryId.",
|
|
61650
62456
|
(value, previous) => [...previous, value],
|
|
61651
62457
|
[]
|
|
61652
62458
|
).option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").option("-w, --web", "Open the vulnerabilities dashboard in a browser").option("--no-pager", "Disable the interactive arrow-key pager for table output").addHelpText(
|
|
@@ -61656,8 +62462,7 @@ Examples:
|
|
|
61656
62462
|
tracecli vulnerabilities list
|
|
61657
62463
|
tracecli vulnerabilities list --severity CRITICAL --status OPEN
|
|
61658
62464
|
tracecli vulnerabilities list --repo securewithtrace/trace --limit 50
|
|
61659
|
-
tracecli vulnerabilities list --filter
|
|
61660
|
-
tracecli vulnerabilities list --filter vulnerabilityType=SAST --filter scanMode=sast
|
|
62465
|
+
tracecli vulnerabilities list --filter scanMode=SECRETS
|
|
61661
62466
|
tracecli vulnerabilities list --output json | jq '.[].title'
|
|
61662
62467
|
tracecli vulnerabilities list --output tsv | cut -f1,7
|
|
61663
62468
|
tracecli vulnerabilities list --no-pager
|
|
@@ -61780,7 +62585,7 @@ program2.addCommand(createEnvironmentCommand());
|
|
|
61780
62585
|
program2.addCommand(createCredentialCommand());
|
|
61781
62586
|
program2.addCommand(createInboxCommand());
|
|
61782
62587
|
program2.addCommand(createRepoCommand());
|
|
61783
|
-
program2.addCommand(createVulnerabilitiesCommand());
|
|
62588
|
+
program2.addCommand(createVulnerabilitiesCommand(), { hidden: true });
|
|
61784
62589
|
program2.addCommand(createCodeSizeCommand());
|
|
61785
62590
|
program2.addCommand(createUploadCommand());
|
|
61786
62591
|
program2.addCommand(createPentestCommand());
|