@zksecurity/zkao-sdk 0.2.0 → 0.5.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/dist/index.d.ts +246 -4
- package/dist/index.js +98 -0
- package/package.json +6 -2
package/dist/index.d.ts
CHANGED
|
@@ -73,6 +73,50 @@ interface paths {
|
|
|
73
73
|
patch?: never;
|
|
74
74
|
trace?: never;
|
|
75
75
|
};
|
|
76
|
+
"/projects/{projectId}/repositories/{repositoryId}/audit-areas": {
|
|
77
|
+
parameters: {
|
|
78
|
+
query?: never;
|
|
79
|
+
header?: never;
|
|
80
|
+
path?: never;
|
|
81
|
+
cookie?: never;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* List a repository's audit areas
|
|
85
|
+
* @description Requires scope: `read`. Audit areas are the named subsystems a scan can be scoped to (`auditAreaKeys` on launch). Each scan that maps the repository keeps the list current; sizes come from one branch's map, so an area that map no longer names is returned without one.
|
|
86
|
+
*/
|
|
87
|
+
get: operations["listAuditAreas"];
|
|
88
|
+
put?: never;
|
|
89
|
+
/**
|
|
90
|
+
* Add a custom audit area
|
|
91
|
+
* @description Requires scope: `guidance:write`. An area is a name and a description, never a file list: a scan resolves it against the code at the commit it runs on. The `key` is derived from the name and disambiguated on collision.
|
|
92
|
+
*/
|
|
93
|
+
post: operations["createAuditArea"];
|
|
94
|
+
delete?: never;
|
|
95
|
+
options?: never;
|
|
96
|
+
head?: never;
|
|
97
|
+
patch?: never;
|
|
98
|
+
trace?: never;
|
|
99
|
+
};
|
|
100
|
+
"/projects/{projectId}/repositories/{repositoryId}/audit-areas/{areaKey}": {
|
|
101
|
+
parameters: {
|
|
102
|
+
query?: never;
|
|
103
|
+
header?: never;
|
|
104
|
+
path?: never;
|
|
105
|
+
cookie?: never;
|
|
106
|
+
};
|
|
107
|
+
get?: never;
|
|
108
|
+
put?: never;
|
|
109
|
+
post?: never;
|
|
110
|
+
/**
|
|
111
|
+
* Delete a custom audit area
|
|
112
|
+
* @description Requires scope: `guidance:write`. Only an area with `source: custom` can be deleted; a discovered one is the map's own account of the repository and is refused with `409`. Scans that already ran keep the scope they ran with.
|
|
113
|
+
*/
|
|
114
|
+
delete: operations["deleteAuditArea"];
|
|
115
|
+
options?: never;
|
|
116
|
+
head?: never;
|
|
117
|
+
patch?: never;
|
|
118
|
+
trace?: never;
|
|
119
|
+
};
|
|
76
120
|
"/projects/{projectId}/scans": {
|
|
77
121
|
parameters: {
|
|
78
122
|
query?: never;
|
|
@@ -93,6 +137,10 @@ interface paths {
|
|
|
93
137
|
* ACTIVE. Discover valid `presetRef` / `optInFlowIds` via the discovery
|
|
94
138
|
* endpoints. Per-token spend limits are enforced, and the project must have
|
|
95
139
|
* enough prepaid credits to cover the budget (otherwise `402`).
|
|
140
|
+
*
|
|
141
|
+
* A repository added moments ago may still be analyzing, in which case
|
|
142
|
+
* this returns `409 repository_initializing`. Wait for its `readiness` to
|
|
143
|
+
* be `ready` in `GET /repositories` and launch again.
|
|
96
144
|
*/
|
|
97
145
|
post: operations["launchScan"];
|
|
98
146
|
delete?: never;
|
|
@@ -330,7 +378,7 @@ interface paths {
|
|
|
330
378
|
};
|
|
331
379
|
/**
|
|
332
380
|
* List opt-in flows available at launch
|
|
333
|
-
* @description Requires scope: `read`. Pass the chosen ids as `optInFlowIds` when launching.
|
|
381
|
+
* @description Requires scope: `read`. Pass the chosen ids as `optInFlowIds` when launching. A flow marked `rotating` may run without being asked for.
|
|
334
382
|
*/
|
|
335
383
|
get: operations["listOptionalFlows"];
|
|
336
384
|
put?: never;
|
|
@@ -445,7 +493,7 @@ interface components {
|
|
|
445
493
|
Error: {
|
|
446
494
|
error: {
|
|
447
495
|
/** @enum {string} */
|
|
448
|
-
code: "unauthorized" | "forbidden" | "not_found" | "bad_request" | "conflict" | "insufficient_credits" | "rate_limited" | "internal";
|
|
496
|
+
code: "unauthorized" | "forbidden" | "not_found" | "bad_request" | "conflict" | "insufficient_credits" | "repository_initializing" | "rate_limited" | "internal";
|
|
449
497
|
message: string;
|
|
450
498
|
};
|
|
451
499
|
};
|
|
@@ -465,6 +513,11 @@ interface components {
|
|
|
465
513
|
defaultBranch?: string | null;
|
|
466
514
|
/** @description ACTIVE | MARKED_FOR_DELETION */
|
|
467
515
|
status: string;
|
|
516
|
+
/**
|
|
517
|
+
* @description Whether a scan can start on this repository. A newly added repository is `analyzing` until a one-time pass over it finishes; launching a scan meanwhile fails with `repository_initializing`. Poll this endpoint rather than retrying the launch blind.
|
|
518
|
+
* @enum {string}
|
|
519
|
+
*/
|
|
520
|
+
readiness: "ready" | "analyzing";
|
|
468
521
|
};
|
|
469
522
|
Scan: {
|
|
470
523
|
id: string;
|
|
@@ -567,6 +620,8 @@ interface components {
|
|
|
567
620
|
flowId: string;
|
|
568
621
|
title: string;
|
|
569
622
|
description: string;
|
|
623
|
+
/** @description True when this flow belongs to a group the preset rotates through. Some of the group runs on every scan without being asked for, and which members depends on the repository. Naming it in `optInFlowIds` adds it whether or not the rotation picked it, and raises the scan's minimum budget. */
|
|
624
|
+
rotating: boolean;
|
|
570
625
|
};
|
|
571
626
|
LaunchScanRequest: {
|
|
572
627
|
repositoryId: string;
|
|
@@ -579,8 +634,10 @@ interface components {
|
|
|
579
634
|
/** @description Pin a specific commit SHA (7-40 hex chars). */
|
|
580
635
|
commitHash?: string | null;
|
|
581
636
|
commitMessage?: string | null;
|
|
582
|
-
/** @description Optional-flow ids from /optional-flows. */
|
|
637
|
+
/** @description Optional-flow ids from /optional-flows, added to the scan on top of whatever a rotating group already contributes. */
|
|
583
638
|
optInFlowIds?: string[];
|
|
639
|
+
/** @description Area keys from /audit-areas to scope this scan to. Omit or send an empty array to scan the whole repository. A key the repository's current map no longer names fails the launch rather than being dropped, so a scan budgeted for one subsystem never silently runs against everything. */
|
|
640
|
+
auditAreaKeys?: string[];
|
|
584
641
|
/** @description Guidance for this scan only, replacing the repository's configured guidance layer (it is still layered over any committed zkao.md). Omit the field to inherit the repository's guidance; send null to scan with no guidance layer. */
|
|
585
642
|
guidance?: string | null;
|
|
586
643
|
};
|
|
@@ -611,6 +668,44 @@ interface components {
|
|
|
611
668
|
/** @description True when the content already matched (no revision recorded). */
|
|
612
669
|
unchanged: boolean;
|
|
613
670
|
};
|
|
671
|
+
AuditArea: {
|
|
672
|
+
/** @description Stable slug, unique per repository. Pass it in `auditAreaKeys` when launching a scan. */
|
|
673
|
+
key: string;
|
|
674
|
+
name: string;
|
|
675
|
+
description: string | null;
|
|
676
|
+
/**
|
|
677
|
+
* @description `discovered` was named by a scan's map of the repository; `custom` was added through this API or the app.
|
|
678
|
+
* @enum {string}
|
|
679
|
+
*/
|
|
680
|
+
source: "discovered" | "custom";
|
|
681
|
+
/** @description Whether the branch's latest map still names this area. */
|
|
682
|
+
inLatestMap: boolean;
|
|
683
|
+
/** @description Files this area covers at that map. Null when the map does not name it. */
|
|
684
|
+
files: number | null;
|
|
685
|
+
/** @description Lines this area covers at that map. Null when the map does not name it. */
|
|
686
|
+
lines: number | null;
|
|
687
|
+
};
|
|
688
|
+
AuditAreaList: {
|
|
689
|
+
repositoryId: string;
|
|
690
|
+
/** @description Branch the sizes were read from. */
|
|
691
|
+
branch: string | null;
|
|
692
|
+
/** @description Whether that branch has a stored map at all. */
|
|
693
|
+
mapped: boolean;
|
|
694
|
+
totalFiles: number | null;
|
|
695
|
+
totalLines: number | null;
|
|
696
|
+
/** @description The map's own audit order first, then the areas it no longer names. */
|
|
697
|
+
areas: components["schemas"]["AuditArea"][];
|
|
698
|
+
};
|
|
699
|
+
CreateAuditAreaRequest: {
|
|
700
|
+
name: string;
|
|
701
|
+
/** @description What this part of the code does. */
|
|
702
|
+
description?: string | null;
|
|
703
|
+
};
|
|
704
|
+
DeleteAuditAreaResult: {
|
|
705
|
+
repositoryId: string;
|
|
706
|
+
key: string;
|
|
707
|
+
deleted: boolean;
|
|
708
|
+
};
|
|
614
709
|
CancelScanResult: {
|
|
615
710
|
scanId: string;
|
|
616
711
|
/** @description Terminal status after cancellation (always CANCELLED). */
|
|
@@ -696,6 +791,15 @@ interface components {
|
|
|
696
791
|
"application/json": components["schemas"]["Error"];
|
|
697
792
|
};
|
|
698
793
|
};
|
|
794
|
+
/** @description The repository is still being analyzed and cannot be scanned yet. The same request succeeds once `GET /repositories` reports its `readiness` as `ready`. (code `repository_initializing`) */
|
|
795
|
+
RepositoryInitializing: {
|
|
796
|
+
headers: {
|
|
797
|
+
[name: string]: unknown;
|
|
798
|
+
};
|
|
799
|
+
content: {
|
|
800
|
+
"application/json": components["schemas"]["Error"];
|
|
801
|
+
};
|
|
802
|
+
};
|
|
699
803
|
/** @description The token lacks the required scope */
|
|
700
804
|
Forbidden: {
|
|
701
805
|
headers: {
|
|
@@ -833,6 +937,97 @@ interface operations {
|
|
|
833
937
|
409: components["responses"]["Conflict"];
|
|
834
938
|
};
|
|
835
939
|
};
|
|
940
|
+
listAuditAreas: {
|
|
941
|
+
parameters: {
|
|
942
|
+
query?: {
|
|
943
|
+
/** @description Branch whose map the sizes come from. Defaults to the repository's default branch. */
|
|
944
|
+
branch?: string;
|
|
945
|
+
};
|
|
946
|
+
header?: never;
|
|
947
|
+
path: {
|
|
948
|
+
projectId: components["parameters"]["ProjectId"];
|
|
949
|
+
repositoryId: components["parameters"]["RepositoryId"];
|
|
950
|
+
};
|
|
951
|
+
cookie?: never;
|
|
952
|
+
};
|
|
953
|
+
requestBody?: never;
|
|
954
|
+
responses: {
|
|
955
|
+
/** @description OK */
|
|
956
|
+
200: {
|
|
957
|
+
headers: {
|
|
958
|
+
[name: string]: unknown;
|
|
959
|
+
};
|
|
960
|
+
content: {
|
|
961
|
+
"application/json": components["schemas"]["AuditAreaList"];
|
|
962
|
+
};
|
|
963
|
+
};
|
|
964
|
+
401: components["responses"]["Unauthorized"];
|
|
965
|
+
403: components["responses"]["Forbidden"];
|
|
966
|
+
404: components["responses"]["NotFound"];
|
|
967
|
+
};
|
|
968
|
+
};
|
|
969
|
+
createAuditArea: {
|
|
970
|
+
parameters: {
|
|
971
|
+
query?: never;
|
|
972
|
+
header?: never;
|
|
973
|
+
path: {
|
|
974
|
+
projectId: components["parameters"]["ProjectId"];
|
|
975
|
+
repositoryId: components["parameters"]["RepositoryId"];
|
|
976
|
+
};
|
|
977
|
+
cookie?: never;
|
|
978
|
+
};
|
|
979
|
+
requestBody: {
|
|
980
|
+
content: {
|
|
981
|
+
"application/json": components["schemas"]["CreateAuditAreaRequest"];
|
|
982
|
+
};
|
|
983
|
+
};
|
|
984
|
+
responses: {
|
|
985
|
+
/** @description Created */
|
|
986
|
+
201: {
|
|
987
|
+
headers: {
|
|
988
|
+
[name: string]: unknown;
|
|
989
|
+
};
|
|
990
|
+
content: {
|
|
991
|
+
"application/json": {
|
|
992
|
+
area: components["schemas"]["AuditArea"];
|
|
993
|
+
};
|
|
994
|
+
};
|
|
995
|
+
};
|
|
996
|
+
400: components["responses"]["BadRequest"];
|
|
997
|
+
401: components["responses"]["Unauthorized"];
|
|
998
|
+
403: components["responses"]["Forbidden"];
|
|
999
|
+
404: components["responses"]["NotFound"];
|
|
1000
|
+
409: components["responses"]["Conflict"];
|
|
1001
|
+
};
|
|
1002
|
+
};
|
|
1003
|
+
deleteAuditArea: {
|
|
1004
|
+
parameters: {
|
|
1005
|
+
query?: never;
|
|
1006
|
+
header?: never;
|
|
1007
|
+
path: {
|
|
1008
|
+
projectId: components["parameters"]["ProjectId"];
|
|
1009
|
+
repositoryId: components["parameters"]["RepositoryId"];
|
|
1010
|
+
areaKey: string;
|
|
1011
|
+
};
|
|
1012
|
+
cookie?: never;
|
|
1013
|
+
};
|
|
1014
|
+
requestBody?: never;
|
|
1015
|
+
responses: {
|
|
1016
|
+
/** @description OK */
|
|
1017
|
+
200: {
|
|
1018
|
+
headers: {
|
|
1019
|
+
[name: string]: unknown;
|
|
1020
|
+
};
|
|
1021
|
+
content: {
|
|
1022
|
+
"application/json": components["schemas"]["DeleteAuditAreaResult"];
|
|
1023
|
+
};
|
|
1024
|
+
};
|
|
1025
|
+
401: components["responses"]["Unauthorized"];
|
|
1026
|
+
403: components["responses"]["Forbidden"];
|
|
1027
|
+
404: components["responses"]["NotFound"];
|
|
1028
|
+
409: components["responses"]["Conflict"];
|
|
1029
|
+
};
|
|
1030
|
+
};
|
|
836
1031
|
listScans: {
|
|
837
1032
|
parameters: {
|
|
838
1033
|
query?: {
|
|
@@ -890,6 +1085,7 @@ interface operations {
|
|
|
890
1085
|
402: components["responses"]["InsufficientCredits"];
|
|
891
1086
|
403: components["responses"]["Forbidden"];
|
|
892
1087
|
404: components["responses"]["NotFound"];
|
|
1088
|
+
409: components["responses"]["RepositoryInitializing"];
|
|
893
1089
|
429: components["responses"]["RateLimited"];
|
|
894
1090
|
};
|
|
895
1091
|
};
|
|
@@ -1368,6 +1564,9 @@ type TriageStatus = Schemas["TriageStatus"];
|
|
|
1368
1564
|
type ScanStatus = Schemas["ScanStatus"];
|
|
1369
1565
|
type PublishArtifactResult = Schemas["PublishArtifactResult"];
|
|
1370
1566
|
type RepositoryGuidance = Schemas["RepositoryGuidance"];
|
|
1567
|
+
type AuditArea = Schemas["AuditArea"];
|
|
1568
|
+
type AuditAreaList = Schemas["AuditAreaList"];
|
|
1569
|
+
type DeleteAuditAreaResult = Schemas["DeleteAuditAreaResult"];
|
|
1371
1570
|
type SetGuidanceResult = Schemas["SetGuidanceResult"];
|
|
1372
1571
|
type BillingBalance = Schemas["BillingBalance"];
|
|
1373
1572
|
type BillingUsage = Schemas["BillingUsage"];
|
|
@@ -1398,6 +1597,16 @@ type ZkaoClientOptions = {
|
|
|
1398
1597
|
/** Terminal scan statuses: polling can stop once a scan reaches one of these. */
|
|
1399
1598
|
declare const TERMINAL_SCAN_STATUSES: readonly ScanStatus[];
|
|
1400
1599
|
declare function isTerminalScanStatus(status: ScanStatus): boolean;
|
|
1600
|
+
type WaitForRepositoryReadyOptions = {
|
|
1601
|
+
/** First poll delay, in ms (default 5000). Grows with backoff up to maxIntervalMs. */
|
|
1602
|
+
intervalMs?: number;
|
|
1603
|
+
/** Cap on the poll delay, in ms (default 30000). */
|
|
1604
|
+
maxIntervalMs?: number;
|
|
1605
|
+
/** Give up after this long, in ms (default 30m). Throws on timeout. */
|
|
1606
|
+
timeoutMs?: number;
|
|
1607
|
+
/** Abort the wait (e.g. on Ctrl-C). Rejects with the abort reason. */
|
|
1608
|
+
signal?: AbortSignal;
|
|
1609
|
+
};
|
|
1401
1610
|
type WaitForScanOptions = {
|
|
1402
1611
|
/** First poll delay, in ms (default 5000). Grows with backoff up to maxIntervalMs. */
|
|
1403
1612
|
intervalMs?: number;
|
|
@@ -1426,6 +1635,15 @@ declare class ZkaoClient {
|
|
|
1426
1635
|
constructor(options: ZkaoClientOptions);
|
|
1427
1636
|
private get path();
|
|
1428
1637
|
listRepositories(): Promise<Repository[]>;
|
|
1638
|
+
/**
|
|
1639
|
+
* Block until a repository is ready to scan, then return it.
|
|
1640
|
+
*
|
|
1641
|
+
* A repository added moments ago is still being analyzed, and launching a
|
|
1642
|
+
* scan against it fails with `repository_initializing`. Call this between
|
|
1643
|
+
* adding a repository and launching its first scan rather than retrying the
|
|
1644
|
+
* launch and swallowing the error.
|
|
1645
|
+
*/
|
|
1646
|
+
waitForRepositoryReady(repositoryId: string, opts?: WaitForRepositoryReadyOptions): Promise<Repository>;
|
|
1429
1647
|
/** Read a repository's configured guidance (requires the `read` scope). */
|
|
1430
1648
|
getRepositoryGuidance(repositoryId: string): Promise<RepositoryGuidance>;
|
|
1431
1649
|
/**
|
|
@@ -1438,6 +1656,30 @@ declare class ZkaoClient {
|
|
|
1438
1656
|
setRepositoryGuidance(repositoryId: string, content: string | null, opts?: {
|
|
1439
1657
|
expectedContent?: string | null;
|
|
1440
1658
|
}): Promise<SetGuidanceResult>;
|
|
1659
|
+
/**
|
|
1660
|
+
* List a repository's audit areas (requires the `read` scope).
|
|
1661
|
+
*
|
|
1662
|
+
* An area is a named subsystem a scan can be scoped to: pass its `key` in
|
|
1663
|
+
* `auditAreaKeys` when launching. Sizes come from one branch's map, so an
|
|
1664
|
+
* area that map no longer names is returned without one. Defaults to the
|
|
1665
|
+
* repository's default branch.
|
|
1666
|
+
*/
|
|
1667
|
+
listAuditAreas(repositoryId: string, opts?: {
|
|
1668
|
+
branch?: string;
|
|
1669
|
+
}): Promise<AuditAreaList>;
|
|
1670
|
+
/**
|
|
1671
|
+
* Add a custom audit area (requires the `guidance:write` scope).
|
|
1672
|
+
*
|
|
1673
|
+
* An area is a name and a description, never a file list: a scan resolves it
|
|
1674
|
+
* against the code at the commit it runs on. The returned `key` is derived
|
|
1675
|
+
* from the name.
|
|
1676
|
+
*/
|
|
1677
|
+
createAuditArea(repositoryId: string, name: string, description?: string | null): Promise<AuditArea>;
|
|
1678
|
+
/**
|
|
1679
|
+
* Delete a custom audit area (requires the `guidance:write` scope). An area
|
|
1680
|
+
* a scan's map named is refused with a `409`.
|
|
1681
|
+
*/
|
|
1682
|
+
deleteAuditArea(repositoryId: string, areaKey: string): Promise<DeleteAuditAreaResult>;
|
|
1441
1683
|
listScans(opts?: {
|
|
1442
1684
|
page?: number;
|
|
1443
1685
|
limit?: number;
|
|
@@ -1530,4 +1772,4 @@ declare class ZkaoClient {
|
|
|
1530
1772
|
}): Promise<UsageMonthSummary[]>;
|
|
1531
1773
|
}
|
|
1532
1774
|
|
|
1533
|
-
export { type BillingBalance, type BillingSummary, type BillingUsage, type CancelScanResult, type ChangeNote, DEFAULT_BASE_URL, type Finding, type FindingDetail, type FindingNote, type LaunchScanRequest, type LaunchScanResult, type OptionalFlow, type Paginated, type PublishArtifactResult, type Repository, type RepositoryGuidance, type ResolutionReason, type ResolutionStatus, type Scan, type ScanDetail, type ScanPreset, type ScanStatus, type SetGuidanceResult, type Severity, TERMINAL_SCAN_STATUSES, type TriageStatus, type UsageEvent, type UsageEventType, type UsageMonthSummary, type WaitForScanOptions, ZkaoApiError, ZkaoClient, type ZkaoClientOptions, type components, isTerminalScanStatus, normalizeBaseUrl, type paths, resolveBaseUrlFromEnv };
|
|
1775
|
+
export { type BillingBalance, type BillingSummary, type BillingUsage, type CancelScanResult, type ChangeNote, DEFAULT_BASE_URL, type Finding, type FindingDetail, type FindingNote, type LaunchScanRequest, type LaunchScanResult, type OptionalFlow, type Paginated, type PublishArtifactResult, type Repository, type RepositoryGuidance, type ResolutionReason, type ResolutionStatus, type Scan, type ScanDetail, type ScanPreset, type ScanStatus, type SetGuidanceResult, type Severity, TERMINAL_SCAN_STATUSES, type TriageStatus, type UsageEvent, type UsageEventType, type UsageMonthSummary, type WaitForRepositoryReadyOptions, type WaitForScanOptions, ZkaoApiError, ZkaoClient, type ZkaoClientOptions, type components, isTerminalScanStatus, normalizeBaseUrl, type paths, resolveBaseUrlFromEnv };
|
package/dist/index.js
CHANGED
|
@@ -120,6 +120,55 @@ var ZkaoClient = class {
|
|
|
120
120
|
});
|
|
121
121
|
return unwrap(res).repositories;
|
|
122
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* Block until a repository is ready to scan, then return it.
|
|
125
|
+
*
|
|
126
|
+
* A repository added moments ago is still being analyzed, and launching a
|
|
127
|
+
* scan against it fails with `repository_initializing`. Call this between
|
|
128
|
+
* adding a repository and launching its first scan rather than retrying the
|
|
129
|
+
* launch and swallowing the error.
|
|
130
|
+
*/
|
|
131
|
+
async waitForRepositoryReady(repositoryId, opts = {}) {
|
|
132
|
+
const intervalMs = opts.intervalMs ?? 5e3;
|
|
133
|
+
const maxIntervalMs = opts.maxIntervalMs ?? 3e4;
|
|
134
|
+
const timeoutMs = opts.timeoutMs ?? 30 * 60 * 1e3;
|
|
135
|
+
const deadline = Date.now() + timeoutMs;
|
|
136
|
+
for (let attempt = 0; ; attempt++) {
|
|
137
|
+
throwIfAborted(opts.signal);
|
|
138
|
+
const res = await this.http.GET("/projects/{projectId}/repositories", {
|
|
139
|
+
params: { path: this.path },
|
|
140
|
+
signal: opts.signal
|
|
141
|
+
});
|
|
142
|
+
const retryAfterMs = parseRetryAfterMs(
|
|
143
|
+
res.response.headers.get("retry-after")
|
|
144
|
+
);
|
|
145
|
+
if (res.response.status !== 429) {
|
|
146
|
+
const repository = unwrap(res).repositories.find(
|
|
147
|
+
(candidate) => candidate.id === repositoryId
|
|
148
|
+
);
|
|
149
|
+
if (!repository) {
|
|
150
|
+
throw new Error(
|
|
151
|
+
`Repository ${repositoryId} is not in this project (or this token's allowlist)`
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
if (repository.readiness === "ready") {
|
|
155
|
+
return repository;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const backoffMs = Math.min(
|
|
159
|
+
maxIntervalMs,
|
|
160
|
+
Math.round(intervalMs * 1.5 ** attempt)
|
|
161
|
+
);
|
|
162
|
+
const baseMs = retryAfterMs ?? backoffMs;
|
|
163
|
+
const delayMs = baseMs + Math.round(Math.random() * baseMs * 0.2);
|
|
164
|
+
if (Date.now() + delayMs > deadline) {
|
|
165
|
+
throw new Error(
|
|
166
|
+
`Timed out waiting for repository ${repositoryId} to be ready after ${timeoutMs}ms`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
await sleep(delayMs, opts.signal);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
123
172
|
/** Read a repository's configured guidance (requires the `read` scope). */
|
|
124
173
|
async getRepositoryGuidance(repositoryId) {
|
|
125
174
|
const res = await this.http.GET(
|
|
@@ -145,6 +194,55 @@ var ZkaoClient = class {
|
|
|
145
194
|
);
|
|
146
195
|
return unwrap(res);
|
|
147
196
|
}
|
|
197
|
+
// --- Audit areas --------------------------------------------------------
|
|
198
|
+
/**
|
|
199
|
+
* List a repository's audit areas (requires the `read` scope).
|
|
200
|
+
*
|
|
201
|
+
* An area is a named subsystem a scan can be scoped to: pass its `key` in
|
|
202
|
+
* `auditAreaKeys` when launching. Sizes come from one branch's map, so an
|
|
203
|
+
* area that map no longer names is returned without one. Defaults to the
|
|
204
|
+
* repository's default branch.
|
|
205
|
+
*/
|
|
206
|
+
async listAuditAreas(repositoryId, opts = {}) {
|
|
207
|
+
const res = await this.http.GET(
|
|
208
|
+
"/projects/{projectId}/repositories/{repositoryId}/audit-areas",
|
|
209
|
+
{
|
|
210
|
+
params: {
|
|
211
|
+
path: { ...this.path, repositoryId },
|
|
212
|
+
query: opts.branch === void 0 ? {} : { branch: opts.branch }
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
);
|
|
216
|
+
return unwrap(res);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Add a custom audit area (requires the `guidance:write` scope).
|
|
220
|
+
*
|
|
221
|
+
* An area is a name and a description, never a file list: a scan resolves it
|
|
222
|
+
* against the code at the commit it runs on. The returned `key` is derived
|
|
223
|
+
* from the name.
|
|
224
|
+
*/
|
|
225
|
+
async createAuditArea(repositoryId, name, description) {
|
|
226
|
+
const res = await this.http.POST(
|
|
227
|
+
"/projects/{projectId}/repositories/{repositoryId}/audit-areas",
|
|
228
|
+
{
|
|
229
|
+
params: { path: { ...this.path, repositoryId } },
|
|
230
|
+
body: { name, description: description ?? null }
|
|
231
|
+
}
|
|
232
|
+
);
|
|
233
|
+
return unwrap(res).area;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Delete a custom audit area (requires the `guidance:write` scope). An area
|
|
237
|
+
* a scan's map named is refused with a `409`.
|
|
238
|
+
*/
|
|
239
|
+
async deleteAuditArea(repositoryId, areaKey) {
|
|
240
|
+
const res = await this.http.DELETE(
|
|
241
|
+
"/projects/{projectId}/repositories/{repositoryId}/audit-areas/{areaKey}",
|
|
242
|
+
{ params: { path: { ...this.path, repositoryId, areaKey } } }
|
|
243
|
+
);
|
|
244
|
+
return unwrap(res);
|
|
245
|
+
}
|
|
148
246
|
// --- Scans --------------------------------------------------------------
|
|
149
247
|
async listScans(opts = {}) {
|
|
150
248
|
const res = await this.http.GET("/projects/{projectId}/scans", {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zksecurity/zkao-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "TypeScript SDK for the zkao Project API",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "zkSecurity",
|
|
@@ -29,7 +29,11 @@
|
|
|
29
29
|
"import": "./dist/index.js"
|
|
30
30
|
}
|
|
31
31
|
},
|
|
32
|
-
"files": [
|
|
32
|
+
"files": [
|
|
33
|
+
"dist",
|
|
34
|
+
"LICENSE",
|
|
35
|
+
"README.md"
|
|
36
|
+
],
|
|
33
37
|
"engines": {
|
|
34
38
|
"node": ">=18"
|
|
35
39
|
},
|