@socketsecurity/sdk 1.10.1 → 1.11.1
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/CHANGELOG.md +19 -0
- package/README.md +153 -311
- package/dist/constants.js +23 -117
- package/dist/file-upload.js +118 -127
- package/dist/http-client.d.ts +11 -8
- package/dist/http-client.js +281 -223
- package/dist/index.js +43 -48
- package/dist/package.json.js +212 -0
- package/dist/quota-utils.d.ts +13 -6
- package/dist/quota-utils.js +128 -105
- package/dist/socket-sdk-class.d.ts +1 -1
- package/dist/socket-sdk-class.js +1488 -1407
- package/dist/testing.d.ts +453 -0
- package/dist/testing.js +387 -0
- package/dist/types.d.ts +26 -0
- package/dist/user-agent.js +11 -7
- package/dist/utils.d.ts +2 -1
- package/dist/utils.js +66 -60
- package/package.json +27 -6
- package/dist/promise-queue.js +0 -91
- package/dist/types.js +0 -3
package/dist/socket-sdk-class.js
CHANGED
|
@@ -1,1430 +1,1511 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var events = require('node:events');
|
|
4
|
+
var node_fs = require('node:fs');
|
|
5
|
+
var readline = require('node:readline');
|
|
6
|
+
var cacheWithTtl = require('@socketsecurity/registry/lib/cache-with-ttl');
|
|
7
|
+
var SOCKET_PUBLIC_API_TOKEN = require('@socketsecurity/registry/lib/constants/SOCKET_PUBLIC_API_TOKEN');
|
|
8
|
+
var UNKNOWN_ERROR = require('@socketsecurity/registry/lib/constants/UNKNOWN_ERROR');
|
|
9
|
+
var abortSignal = require('@socketsecurity/registry/lib/constants/abort-signal');
|
|
10
|
+
var debug = require('@socketsecurity/registry/lib/debug');
|
|
11
|
+
var json = require('@socketsecurity/registry/lib/json');
|
|
12
|
+
var objects = require('@socketsecurity/registry/lib/objects');
|
|
13
|
+
var promises = require('@socketsecurity/registry/lib/promises');
|
|
14
|
+
var url = require('@socketsecurity/registry/lib/url');
|
|
15
|
+
var constants = require('./constants.js');
|
|
16
|
+
var fileUpload = require('./file-upload.js');
|
|
17
|
+
var httpClient = require('./http-client.js');
|
|
18
|
+
var utils = require('./utils.js');
|
|
19
|
+
|
|
7
20
|
/**
|
|
8
21
|
* @fileoverview SocketSdk class implementation for Socket security API client.
|
|
9
22
|
* Provides complete API functionality for vulnerability scanning, analysis, and reporting.
|
|
10
23
|
*/
|
|
11
|
-
const node_events_1 = __importDefault(require("node:events"));
|
|
12
|
-
const node_fs_1 = require("node:fs");
|
|
13
|
-
const node_readline_1 = __importDefault(require("node:readline"));
|
|
14
|
-
const SOCKET_PUBLIC_API_TOKEN_1 = __importDefault(require("@socketsecurity/registry/lib/constants/SOCKET_PUBLIC_API_TOKEN"));
|
|
15
|
-
const UNKNOWN_ERROR_1 = __importDefault(require("@socketsecurity/registry/lib/constants/UNKNOWN_ERROR"));
|
|
16
|
-
const abort_signal_1 = __importDefault(require("@socketsecurity/registry/lib/constants/abort-signal"));
|
|
17
|
-
const debug_1 = require("@socketsecurity/registry/lib/debug");
|
|
18
|
-
const json_1 = require("@socketsecurity/registry/lib/json");
|
|
19
|
-
const objects_1 = require("@socketsecurity/registry/lib/objects");
|
|
20
|
-
const promises_1 = require("@socketsecurity/registry/lib/promises");
|
|
21
|
-
const url_1 = require("@socketsecurity/registry/lib/url");
|
|
22
|
-
const constants_1 = require("./constants");
|
|
23
|
-
const file_upload_1 = require("./file-upload");
|
|
24
|
-
const http_client_1 = require("./http-client");
|
|
25
|
-
const utils_1 = require("./utils");
|
|
26
24
|
/**
|
|
27
25
|
* Socket SDK for programmatic access to Socket.dev security analysis APIs.
|
|
28
26
|
* Provides methods for package scanning, organization management, and security analysis.
|
|
29
27
|
*/
|
|
30
28
|
class SocketSdk {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
29
|
+
#apiToken;
|
|
30
|
+
#baseUrl;
|
|
31
|
+
#cache;
|
|
32
|
+
#reqOptions;
|
|
33
|
+
#retries;
|
|
34
|
+
#retryDelay;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Initialize Socket SDK with API token and configuration options.
|
|
38
|
+
* Sets up authentication, base URL, HTTP client options, retry behavior, and caching.
|
|
39
|
+
*/
|
|
40
|
+
constructor(apiToken, options) {
|
|
41
|
+
const {
|
|
42
|
+
agent: agentOrObj,
|
|
43
|
+
baseUrl = 'https://api.socket.dev/v0/',
|
|
44
|
+
cache = false,
|
|
45
|
+
cacheTtl = 5 * 60 * 1000,
|
|
46
|
+
retries = 0,
|
|
47
|
+
retryDelay = 100,
|
|
48
|
+
timeout,
|
|
49
|
+
userAgent
|
|
50
|
+
} = {
|
|
51
|
+
__proto__: null,
|
|
52
|
+
...options
|
|
53
|
+
};
|
|
54
|
+
const agentKeys = agentOrObj ? Object.keys(agentOrObj) : [];
|
|
55
|
+
const agentAsGotOptions = agentOrObj;
|
|
56
|
+
const agent = agentKeys.length && agentKeys.every(k => constants.httpAgentNames.has(k)) ? /* c8 ignore next 3 - Got-style agent options compatibility layer */
|
|
57
|
+
agentAsGotOptions.https || agentAsGotOptions.http || agentAsGotOptions.http2 : agentOrObj;
|
|
58
|
+
this.#apiToken = apiToken;
|
|
59
|
+
this.#baseUrl = utils.normalizeBaseUrl(baseUrl);
|
|
60
|
+
this.#cache = cache ? cacheWithTtl.createTtlCache({
|
|
61
|
+
memoize: true,
|
|
62
|
+
prefix: 'socket-sdk',
|
|
63
|
+
ttl: cacheTtl
|
|
64
|
+
}) : undefined;
|
|
65
|
+
this.#retries = retries;
|
|
66
|
+
this.#retryDelay = retryDelay;
|
|
67
|
+
this.#reqOptions = {
|
|
68
|
+
...(agent ? {
|
|
69
|
+
agent
|
|
70
|
+
} : {}),
|
|
71
|
+
headers: {
|
|
72
|
+
Authorization: `Basic ${btoa(`${apiToken}:`)}`,
|
|
73
|
+
'User-Agent': userAgent ?? constants.DEFAULT_USER_AGENT
|
|
74
|
+
},
|
|
75
|
+
signal: abortSignal,
|
|
76
|
+
...(timeout ? {
|
|
77
|
+
timeout
|
|
78
|
+
} : {})
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Execute an HTTP request with retry logic.
|
|
84
|
+
* Internal method for wrapping HTTP operations with exponential backoff.
|
|
85
|
+
*/
|
|
86
|
+
async #executeWithRetry(operation) {
|
|
87
|
+
const result = await promises.pRetry(operation, {
|
|
88
|
+
baseDelayMs: this.#retryDelay,
|
|
89
|
+
onRetry(_attempt, error) {
|
|
90
|
+
/* c8 ignore next 3 - Early return for non-ResponseError types in retry logic */
|
|
91
|
+
if (!(error instanceof httpClient.ResponseError)) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const {
|
|
95
|
+
statusCode
|
|
96
|
+
} = error.response;
|
|
97
|
+
// Don't retry authentication/authorization errors - they won't succeed.
|
|
98
|
+
if (statusCode === 401 || statusCode === 403) {
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
onRetryRethrow: true,
|
|
103
|
+
retries: this.#retries
|
|
104
|
+
});
|
|
105
|
+
/* c8 ignore next 3 - Defensive check for undefined result from pRetry abort */
|
|
106
|
+
if (result === undefined) {
|
|
107
|
+
throw new Error('Request aborted');
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Execute a GET request with optional caching.
|
|
114
|
+
* Internal method for handling cached GET requests with retry logic.
|
|
115
|
+
*/
|
|
116
|
+
async #getCached(cacheKey, fetcher) {
|
|
117
|
+
// If caching is disabled, just execute the request.
|
|
118
|
+
if (!this.#cache) {
|
|
119
|
+
return await this.#executeWithRetry(fetcher);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Use cache with retry logic.
|
|
123
|
+
return await this.#cache.getOrFetch(cacheKey, async () => {
|
|
124
|
+
return await this.#executeWithRetry(fetcher);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Create async generator for streaming batch package URL processing.
|
|
130
|
+
* Internal method for handling chunked PURL responses with error handling.
|
|
131
|
+
*/
|
|
132
|
+
async *#createBatchPurlGenerator(componentsObj, queryParams) {
|
|
133
|
+
let res;
|
|
134
|
+
try {
|
|
135
|
+
res = await this.#executeWithRetry(() => this.#createBatchPurlRequest(componentsObj, queryParams));
|
|
136
|
+
} catch (e) {
|
|
137
|
+
yield await this.#handleApiError(e);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
// Validate response before processing.
|
|
141
|
+
/* c8 ignore next 3 - Defensive check, response should always be defined after successful request */
|
|
142
|
+
if (!res) {
|
|
143
|
+
throw new Error('Failed to get response from batch PURL request');
|
|
144
|
+
}
|
|
145
|
+
// Parse the newline delimited JSON response.
|
|
146
|
+
const rli = readline.createInterface({
|
|
147
|
+
input: res,
|
|
148
|
+
crlfDelay: Number.POSITIVE_INFINITY,
|
|
149
|
+
signal: abortSignal
|
|
150
|
+
});
|
|
151
|
+
const isPublicToken = this.#apiToken === SOCKET_PUBLIC_API_TOKEN;
|
|
152
|
+
for await (const line of rli) {
|
|
153
|
+
const trimmed = line.trim();
|
|
154
|
+
const artifact = trimmed ? json.jsonParse(line, {
|
|
155
|
+
throws: false
|
|
156
|
+
}) : /* c8 ignore next - Empty line handling in batch streaming response parsing. */null;
|
|
157
|
+
if (objects.isObjectObject(artifact)) {
|
|
158
|
+
yield this.#handleApiSuccess(isPublicToken ? /* c8 ignore start - Public token artifact reshaping branch for policy compliance. */httpClient.reshapeArtifactForPublicPolicy(artifact, false, queryParams?.['actions']) : /* c8 ignore stop */
|
|
159
|
+
artifact);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Create HTTP request for batch package URL processing.
|
|
166
|
+
* Internal method for handling PURL batch API calls with retry logic.
|
|
167
|
+
*/
|
|
168
|
+
async #createBatchPurlRequest(componentsObj, queryParams) {
|
|
169
|
+
// Adds the first 'abort' listener to abortSignal.
|
|
170
|
+
const req = httpClient.getHttpModule(this.#baseUrl).request(`${this.#baseUrl}purl?${utils.queryToSearchParams(queryParams)}`, {
|
|
171
|
+
method: 'POST',
|
|
172
|
+
...this.#reqOptions
|
|
173
|
+
}).end(JSON.stringify(componentsObj));
|
|
174
|
+
const response = await httpClient.getResponse(req);
|
|
175
|
+
|
|
176
|
+
// Throw ResponseError for non-2xx status codes so retry logic works properly.
|
|
177
|
+
if (!httpClient.isResponseOk(response)) {
|
|
178
|
+
throw new httpClient.ResponseError(response);
|
|
179
|
+
}
|
|
180
|
+
return response;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Create standardized error result from query operation exceptions.
|
|
185
|
+
* Internal error handling for non-throwing query API methods.
|
|
186
|
+
*/
|
|
187
|
+
#createQueryErrorResult(e) {
|
|
188
|
+
if (e instanceof SyntaxError) {
|
|
189
|
+
// Try to get response text from enhanced error, fall back to regex pattern for compatibility.
|
|
190
|
+
const enhancedError = e;
|
|
191
|
+
/* c8 ignore next - Defensive empty string fallback for originalResponse. */
|
|
192
|
+
let responseText = enhancedError.originalResponse || '';
|
|
193
|
+
|
|
194
|
+
/* c8 ignore next 5 - Empty response text fallback check for JSON parsing errors without originalResponse. */
|
|
195
|
+
if (!responseText) {
|
|
196
|
+
const match = e.message.match(/Invalid JSON response:\n([\s\S]*?)\n→/);
|
|
197
|
+
responseText = match?.[1] || '';
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/* c8 ignore next - Defensive empty string fallback when slice returns empty. */
|
|
201
|
+
const preview = responseText.slice(0, 100) || '';
|
|
202
|
+
return {
|
|
203
|
+
cause: `Please report this. JSON.parse threw an error over the following response: \`${preview.trim()}${responseText.length > 100 ? '...' : ''}\``,
|
|
204
|
+
data: undefined,
|
|
205
|
+
error: 'Server returned invalid JSON',
|
|
206
|
+
status: 0,
|
|
207
|
+
success: false
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/* c8 ignore start - Defensive error stringification fallback branches for edge cases. */
|
|
212
|
+
const errStr = e ? String(e).trim() : '';
|
|
213
|
+
return {
|
|
214
|
+
cause: errStr || UNKNOWN_ERROR,
|
|
215
|
+
data: undefined,
|
|
216
|
+
error: 'API request failed',
|
|
217
|
+
status: 0,
|
|
218
|
+
success: false
|
|
219
|
+
};
|
|
220
|
+
/* c8 ignore stop */
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Extract text content from HTTP response stream.
|
|
225
|
+
* Internal method with size limits to prevent memory exhaustion.
|
|
226
|
+
*/
|
|
227
|
+
async #getResponseText(response) {
|
|
228
|
+
const chunks = [];
|
|
229
|
+
let size = 0;
|
|
230
|
+
// 50MB limit to prevent out-of-memory errors from large responses.
|
|
231
|
+
const MAX = 50 * 1024 * 1024;
|
|
232
|
+
for await (const chunk of response) {
|
|
233
|
+
size += chunk.length;
|
|
234
|
+
/* c8 ignore next 3 - MAX size limit protection for edge cases */
|
|
235
|
+
if (size > MAX) {
|
|
236
|
+
throw new Error('Response body exceeds maximum size limit');
|
|
237
|
+
}
|
|
238
|
+
chunks.push(chunk);
|
|
239
|
+
}
|
|
240
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Handle API error responses and convert to standardized error result.
|
|
245
|
+
* Internal error handling with status code analysis and message formatting.
|
|
246
|
+
*/
|
|
247
|
+
async #handleApiError(error) {
|
|
248
|
+
if (!(error instanceof httpClient.ResponseError)) {
|
|
249
|
+
throw new Error('Unexpected Socket API error', {
|
|
250
|
+
cause: error
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
const {
|
|
254
|
+
statusCode
|
|
255
|
+
} = error.response;
|
|
256
|
+
// Throw server errors (5xx) immediately - these are not recoverable client-side.
|
|
257
|
+
if (statusCode && statusCode >= 500) {
|
|
258
|
+
throw new Error(`Socket API server error (${statusCode})`, {
|
|
259
|
+
cause: error
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
// The error payload may give a meaningful hint as to what went wrong.
|
|
263
|
+
const bodyStr = await httpClient.getErrorResponseBody(error.response);
|
|
264
|
+
// Try to parse the body as JSON, fallback to treating as plain text.
|
|
265
|
+
let body;
|
|
266
|
+
try {
|
|
267
|
+
const parsed = JSON.parse(bodyStr);
|
|
268
|
+
// Client errors (4xx) should return actionable error messages.
|
|
269
|
+
// Extract both message and details from error response for better context.
|
|
270
|
+
if (typeof parsed?.error?.message === 'string') {
|
|
271
|
+
body = parsed.error.message;
|
|
272
|
+
|
|
273
|
+
// Include details if present for additional error context.
|
|
274
|
+
if (parsed.error.details) {
|
|
275
|
+
const detailsStr = typeof parsed.error.details === 'string' ? parsed.error.details : JSON.stringify(parsed.error.details);
|
|
276
|
+
body = `${body} - Details: ${detailsStr}`;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
} catch {
|
|
280
|
+
body = bodyStr;
|
|
281
|
+
}
|
|
282
|
+
// Build error message that includes the body content if available.
|
|
283
|
+
let errorMessage = error.message ?? UNKNOWN_ERROR;
|
|
284
|
+
const trimmedBody = body?.trim();
|
|
285
|
+
if (trimmedBody && !errorMessage.includes(trimmedBody)) {
|
|
286
|
+
// Replace generic status message with actual error body if present,
|
|
287
|
+
// otherwise append the body to the error message.
|
|
288
|
+
const statusMessage = error.response?.statusMessage;
|
|
289
|
+
if (statusMessage && errorMessage.includes(statusMessage)) {
|
|
290
|
+
errorMessage = errorMessage.replace(statusMessage, trimmedBody);
|
|
291
|
+
} else {
|
|
292
|
+
/* c8 ignore next 2 - edge case where statusMessage is undefined or not in error message. */
|
|
293
|
+
errorMessage = `${errorMessage}: ${trimmedBody}`;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return {
|
|
297
|
+
cause: body,
|
|
298
|
+
data: undefined,
|
|
299
|
+
error: errorMessage,
|
|
300
|
+
/* c8 ignore next - fallback for missing status code in edge cases. */
|
|
301
|
+
status: statusCode ?? 0,
|
|
302
|
+
success: false
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Handle successful API responses and convert to standardized success result.
|
|
308
|
+
* Internal success handling with consistent response formatting.
|
|
309
|
+
*/
|
|
310
|
+
#handleApiSuccess(data) {
|
|
311
|
+
return {
|
|
312
|
+
cause: undefined,
|
|
313
|
+
data: data,
|
|
314
|
+
error: undefined,
|
|
315
|
+
// Use generic 200 OK status for all successful API responses.
|
|
316
|
+
status: 200,
|
|
317
|
+
success: true
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Handle query API response data based on requested response type.
|
|
323
|
+
* Internal method for processing different response formats (json, text, response).
|
|
324
|
+
*/
|
|
325
|
+
async #handleQueryResponseData(response, responseType) {
|
|
326
|
+
if (responseType === 'response') {
|
|
327
|
+
return response;
|
|
328
|
+
}
|
|
329
|
+
if (responseType === 'text') {
|
|
330
|
+
return await this.#getResponseText(response);
|
|
331
|
+
}
|
|
332
|
+
if (responseType === 'json') {
|
|
333
|
+
return await httpClient.getResponseJson(response);
|
|
334
|
+
}
|
|
335
|
+
return response;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Fetch package analysis data for multiple packages in a single batch request.
|
|
340
|
+
* Returns all results at once after processing is complete.
|
|
341
|
+
*
|
|
342
|
+
* @throws {Error} When server returns 5xx status codes
|
|
343
|
+
*/
|
|
344
|
+
async batchPackageFetch(componentsObj, queryParams) {
|
|
345
|
+
let res;
|
|
346
|
+
try {
|
|
347
|
+
res = await this.#createBatchPurlRequest(componentsObj, queryParams);
|
|
348
|
+
} catch (e) {
|
|
349
|
+
return await this.#handleApiError(e);
|
|
350
|
+
}
|
|
351
|
+
// Validate response before processing.
|
|
352
|
+
/* c8 ignore next 3 - Defensive check, response should always be defined after successful request */
|
|
353
|
+
if (!res) {
|
|
354
|
+
throw new Error('Failed to get response from batch PURL request');
|
|
355
|
+
}
|
|
356
|
+
// Parse the newline delimited JSON response.
|
|
357
|
+
const rli = readline.createInterface({
|
|
358
|
+
input: res,
|
|
359
|
+
crlfDelay: Number.POSITIVE_INFINITY,
|
|
360
|
+
signal: abortSignal
|
|
361
|
+
});
|
|
362
|
+
const isPublicToken = this.#apiToken === SOCKET_PUBLIC_API_TOKEN;
|
|
363
|
+
const results = [];
|
|
364
|
+
for await (const line of rli) {
|
|
365
|
+
const trimmed = line.trim();
|
|
366
|
+
const artifact = trimmed ? json.jsonParse(line, {
|
|
367
|
+
throws: false
|
|
368
|
+
}) : /* c8 ignore next - Empty line handling in batch parsing. */null;
|
|
369
|
+
if (objects.isObjectObject(artifact)) {
|
|
370
|
+
results.push(isPublicToken ? /* c8 ignore start - Public token artifact reshaping for policy compliance. */
|
|
371
|
+
httpClient.reshapeArtifactForPublicPolicy(artifact, false, queryParams?.['actions']) : /* c8 ignore stop */
|
|
372
|
+
artifact);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
const compact = url.urlSearchParamAsBoolean(objects.getOwn(queryParams, 'compact'));
|
|
376
|
+
return this.#handleApiSuccess(compact ? results : results);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Stream package analysis data for multiple packages with chunked processing and concurrency control.
|
|
381
|
+
* Returns results as they become available via async generator.
|
|
382
|
+
*
|
|
383
|
+
* @throws {Error} When server returns 5xx status codes
|
|
384
|
+
*/
|
|
385
|
+
async *batchPackageStream(componentsObj, options) {
|
|
386
|
+
const {
|
|
387
|
+
chunkSize = 100,
|
|
388
|
+
concurrencyLimit = 10,
|
|
389
|
+
queryParams
|
|
390
|
+
} = {
|
|
391
|
+
__proto__: null,
|
|
392
|
+
...options
|
|
393
|
+
};
|
|
394
|
+
// The createBatchPurlGenerator method will add 2 'abort' event listeners to
|
|
395
|
+
// abortSignal so we multiply the concurrencyLimit by 2.
|
|
396
|
+
const neededMaxListeners = concurrencyLimit * 2;
|
|
397
|
+
// Increase abortSignal max listeners count to avoid Node's MaxListenersExceededWarning.
|
|
398
|
+
const oldAbortSignalMaxListeners = events.getMaxListeners(abortSignal);
|
|
399
|
+
let abortSignalMaxListeners = oldAbortSignalMaxListeners;
|
|
400
|
+
/* c8 ignore start - EventTarget max listeners adjustment for high concurrency batch operations, difficult to test reliably. */
|
|
401
|
+
if (oldAbortSignalMaxListeners < neededMaxListeners) {
|
|
402
|
+
abortSignalMaxListeners = oldAbortSignalMaxListeners + neededMaxListeners;
|
|
403
|
+
events.setMaxListeners(abortSignalMaxListeners, abortSignal);
|
|
404
|
+
}
|
|
405
|
+
/* c8 ignore stop */
|
|
406
|
+
const {
|
|
407
|
+
components
|
|
408
|
+
} = componentsObj;
|
|
409
|
+
const {
|
|
410
|
+
length: componentsCount
|
|
411
|
+
} = components;
|
|
412
|
+
const running = [];
|
|
413
|
+
let index = 0;
|
|
414
|
+
const enqueueGen = () => {
|
|
415
|
+
if (index >= componentsCount) {
|
|
416
|
+
// No more work to do.
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
const generator = this.#createBatchPurlGenerator({
|
|
420
|
+
// Chunk components.
|
|
421
|
+
components: components.slice(index, index + chunkSize)
|
|
422
|
+
}, queryParams);
|
|
423
|
+
continueGen(generator);
|
|
424
|
+
index += chunkSize;
|
|
425
|
+
};
|
|
426
|
+
const continueGen = generator => {
|
|
427
|
+
const {
|
|
428
|
+
promise,
|
|
429
|
+
reject: rejectFn,
|
|
430
|
+
resolve: resolveFn
|
|
431
|
+
} = utils.promiseWithResolvers();
|
|
432
|
+
running.push({
|
|
433
|
+
generator,
|
|
434
|
+
promise
|
|
435
|
+
});
|
|
436
|
+
void generator.next().then(iteratorResult => resolveFn({
|
|
437
|
+
generator,
|
|
438
|
+
iteratorResult
|
|
439
|
+
}), rejectFn);
|
|
440
|
+
};
|
|
441
|
+
// Start initial batch of generators.
|
|
442
|
+
while (running.length < concurrencyLimit && index < componentsCount) {
|
|
443
|
+
enqueueGen();
|
|
444
|
+
}
|
|
445
|
+
while (running.length > 0) {
|
|
446
|
+
// eslint-disable-next-line no-await-in-loop
|
|
447
|
+
const {
|
|
448
|
+
generator,
|
|
449
|
+
iteratorResult
|
|
450
|
+
} = await Promise.race(running.map(entry => entry.promise));
|
|
451
|
+
// Remove generator with safe index lookup.
|
|
452
|
+
const index = running.findIndex(entry => entry.generator === generator);
|
|
453
|
+
/* c8 ignore next 3 - Defensive check for concurrent generator cleanup edge case. */
|
|
454
|
+
if (index === -1) {
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
running.splice(index, 1);
|
|
458
|
+
// Yield the value if one is given, even when done:true.
|
|
459
|
+
if (iteratorResult.value) {
|
|
460
|
+
yield iteratorResult.value;
|
|
461
|
+
}
|
|
462
|
+
if (iteratorResult.done) {
|
|
463
|
+
// Start a new generator if available.
|
|
464
|
+
enqueueGen();
|
|
465
|
+
} else {
|
|
466
|
+
// Keep fetching values from this generator.
|
|
467
|
+
continueGen(generator);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
// Reset abortSignal max listeners count.
|
|
471
|
+
/* c8 ignore start - Reset EventTarget max listeners to original value after batch operations. */
|
|
472
|
+
if (abortSignalMaxListeners > oldAbortSignalMaxListeners) {
|
|
473
|
+
events.setMaxListeners(oldAbortSignalMaxListeners, abortSignal);
|
|
474
|
+
}
|
|
475
|
+
/* c8 ignore stop */
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Create a snapshot of project dependencies by uploading manifest files.
|
|
480
|
+
* Analyzes dependency files to generate a comprehensive security report.
|
|
481
|
+
*
|
|
482
|
+
* @throws {Error} When server returns 5xx status codes
|
|
483
|
+
*/
|
|
484
|
+
async createDependenciesSnapshot(filepaths, options) {
|
|
485
|
+
const {
|
|
486
|
+
pathsRelativeTo = '.',
|
|
487
|
+
queryParams
|
|
488
|
+
} = {
|
|
489
|
+
__proto__: null,
|
|
490
|
+
...options
|
|
491
|
+
};
|
|
492
|
+
const basePath = utils.resolveBasePath(pathsRelativeTo);
|
|
493
|
+
const absFilepaths = utils.resolveAbsPaths(filepaths, basePath);
|
|
494
|
+
try {
|
|
495
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await fileUpload.createUploadRequest(this.#baseUrl, `dependencies/upload?${utils.queryToSearchParams(queryParams)}`, fileUpload.createRequestBodyForFilepaths(absFilepaths, basePath), this.#reqOptions)));
|
|
496
|
+
return this.#handleApiSuccess(data);
|
|
497
|
+
} catch (e) {
|
|
498
|
+
return await this.#handleApiError(e);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Create a diff scan from two full scan IDs.
|
|
504
|
+
* Compares two existing full scans to identify changes.
|
|
505
|
+
*
|
|
506
|
+
* @throws {Error} When server returns 5xx status codes
|
|
507
|
+
*/
|
|
508
|
+
async createOrgDiffScanFromIds(orgSlug, queryParams) {
|
|
509
|
+
try {
|
|
510
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/diff-scans?${utils.queryToSearchParams(queryParams)}`, {}, this.#reqOptions)));
|
|
511
|
+
return this.#handleApiSuccess(data);
|
|
512
|
+
} catch (e) {
|
|
513
|
+
return await this.#handleApiError(e);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Create a comprehensive security scan for an organization.
|
|
519
|
+
* Uploads project files and initiates full security analysis.
|
|
520
|
+
*
|
|
521
|
+
* @throws {Error} When server returns 5xx status codes
|
|
522
|
+
*/
|
|
523
|
+
async createOrgFullScan(orgSlug, filepaths, options) {
|
|
524
|
+
const {
|
|
525
|
+
pathsRelativeTo = '.',
|
|
526
|
+
queryParams
|
|
527
|
+
} = {
|
|
528
|
+
__proto__: null,
|
|
529
|
+
...options
|
|
530
|
+
};
|
|
531
|
+
const basePath = utils.resolveBasePath(pathsRelativeTo);
|
|
532
|
+
const absFilepaths = utils.resolveAbsPaths(filepaths, basePath);
|
|
533
|
+
try {
|
|
534
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await fileUpload.createUploadRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans?${utils.queryToSearchParams(queryParams)}`, fileUpload.createRequestBodyForFilepaths(absFilepaths, basePath), this.#reqOptions)));
|
|
535
|
+
return this.#handleApiSuccess(data);
|
|
536
|
+
} catch (e) {
|
|
537
|
+
return await this.#handleApiError(e);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Create a new repository in an organization.
|
|
543
|
+
* Registers a repository for monitoring and security scanning.
|
|
544
|
+
*
|
|
545
|
+
* @throws {Error} When server returns 5xx status codes
|
|
546
|
+
*/
|
|
547
|
+
async createOrgRepo(orgSlug, queryParams) {
|
|
548
|
+
try {
|
|
549
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos`, queryParams, this.#reqOptions)));
|
|
550
|
+
return this.#handleApiSuccess(data);
|
|
551
|
+
} catch (e) {
|
|
552
|
+
return await this.#handleApiError(e);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* Create a new repository label for an organization.
|
|
558
|
+
* Adds label for repository categorization and management.
|
|
559
|
+
*
|
|
560
|
+
* @throws {Error} When server returns 5xx status codes
|
|
561
|
+
*/
|
|
562
|
+
async createOrgRepoLabel(orgSlug, repoSlug, labelData) {
|
|
563
|
+
try {
|
|
564
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}/labels`, labelData, this.#reqOptions)));
|
|
565
|
+
return this.#handleApiSuccess(data);
|
|
566
|
+
} catch (e) {
|
|
567
|
+
return await this.#handleApiError(e);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Create a security scan by uploading project files.
|
|
573
|
+
* Analyzes uploaded files for security vulnerabilities and policy violations.
|
|
574
|
+
*
|
|
575
|
+
* @throws {Error} When server returns 5xx status codes
|
|
576
|
+
*/
|
|
577
|
+
async createScanFromFilepaths(filepaths, options) {
|
|
578
|
+
const {
|
|
579
|
+
issueRules,
|
|
580
|
+
pathsRelativeTo = '.'
|
|
581
|
+
} = {
|
|
582
|
+
__proto__: null,
|
|
583
|
+
...options
|
|
584
|
+
};
|
|
585
|
+
const basePath = utils.resolveBasePath(pathsRelativeTo);
|
|
586
|
+
const absFilepaths = utils.resolveAbsPaths(filepaths, basePath);
|
|
587
|
+
try {
|
|
588
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await fileUpload.createUploadRequest(this.#baseUrl, 'report/upload', [...fileUpload.createRequestBodyForFilepaths(absFilepaths, basePath), /* c8 ignore next 3 - Optional issueRules parameter edge case. */
|
|
589
|
+
...(issueRules ? fileUpload.createRequestBodyForJson(issueRules, 'issueRules') : [])], {
|
|
590
|
+
...this.#reqOptions,
|
|
591
|
+
method: 'PUT'
|
|
592
|
+
})
|
|
593
|
+
/* c8 ignore next 3 - Success path return statement requires complex file upload mocking with authentication. */));
|
|
594
|
+
return this.#handleApiSuccess(data);
|
|
595
|
+
} catch (e) {
|
|
596
|
+
return await this.#handleApiError(e);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Delete a diff scan from an organization.
|
|
602
|
+
* Permanently removes diff scan data and results.
|
|
603
|
+
*
|
|
604
|
+
* @throws {Error} When server returns 5xx status codes
|
|
605
|
+
*/
|
|
606
|
+
async deleteOrgDiffScan(orgSlug, diffScanId) {
|
|
607
|
+
try {
|
|
608
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createDeleteRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/diff-scans/${encodeURIComponent(diffScanId)}`, this.#reqOptions)));
|
|
609
|
+
return this.#handleApiSuccess(data);
|
|
610
|
+
} catch (e) {
|
|
611
|
+
return await this.#handleApiError(e);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Delete a full scan from an organization.
|
|
617
|
+
* Permanently removes scan data and results.
|
|
618
|
+
*
|
|
619
|
+
* @throws {Error} When server returns 5xx status codes
|
|
620
|
+
*/
|
|
621
|
+
async deleteOrgFullScan(orgSlug, fullScanId) {
|
|
622
|
+
try {
|
|
623
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createDeleteRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}`, this.#reqOptions)));
|
|
624
|
+
return this.#handleApiSuccess(data);
|
|
625
|
+
} catch (e) {
|
|
626
|
+
return await this.#handleApiError(e);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Delete a repository from an organization.
|
|
632
|
+
* Removes repository monitoring and associated scan data.
|
|
633
|
+
*
|
|
634
|
+
* @throws {Error} When server returns 5xx status codes
|
|
635
|
+
*/
|
|
636
|
+
async deleteOrgRepo(orgSlug, repoSlug) {
|
|
637
|
+
try {
|
|
638
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createDeleteRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}`, this.#reqOptions)));
|
|
639
|
+
return this.#handleApiSuccess(data);
|
|
640
|
+
} catch (e) {
|
|
641
|
+
return await this.#handleApiError(e);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* Delete a repository label from an organization.
|
|
647
|
+
* Removes label and associated configuration.
|
|
648
|
+
*
|
|
649
|
+
* @throws {Error} When server returns 5xx status codes
|
|
650
|
+
*/
|
|
651
|
+
async deleteOrgRepoLabel(orgSlug, repoSlug, labelSlug) {
|
|
652
|
+
try {
|
|
653
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createDeleteRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}/labels/${encodeURIComponent(labelSlug)}`, this.#reqOptions)));
|
|
654
|
+
return this.#handleApiSuccess(data);
|
|
655
|
+
} catch (e) {
|
|
656
|
+
return await this.#handleApiError(e);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* Delete a scan report permanently.
|
|
662
|
+
* Removes scan data and analysis results from the system.
|
|
663
|
+
*
|
|
664
|
+
* @throws {Error} When server returns 5xx status codes
|
|
665
|
+
*/
|
|
666
|
+
async deleteReport(reportId) {
|
|
667
|
+
try {
|
|
668
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createDeleteRequest(this.#baseUrl, `report/delete/${encodeURIComponent(reportId)}`, this.#reqOptions)));
|
|
669
|
+
return this.#handleApiSuccess(data);
|
|
670
|
+
} catch (e) {
|
|
671
|
+
return await this.#handleApiError(e);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Export scan results in CycloneDX SBOM format.
|
|
677
|
+
* Returns Software Bill of Materials compliant with CycloneDX standard.
|
|
678
|
+
*
|
|
679
|
+
* @throws {Error} When server returns 5xx status codes
|
|
680
|
+
*/
|
|
681
|
+
async exportCDX(orgSlug, fullScanId) {
|
|
682
|
+
try {
|
|
683
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}/sbom/export/cdx`, this.#reqOptions)));
|
|
684
|
+
return this.#handleApiSuccess(data);
|
|
685
|
+
} catch (e) {
|
|
686
|
+
return await this.#handleApiError(e);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Export scan results in SPDX SBOM format.
|
|
692
|
+
* Returns Software Bill of Materials compliant with SPDX standard.
|
|
693
|
+
*
|
|
694
|
+
* @throws {Error} When server returns 5xx status codes
|
|
695
|
+
*/
|
|
696
|
+
async exportSPDX(orgSlug, fullScanId) {
|
|
697
|
+
try {
|
|
698
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}/sbom/export/spdx`, this.#reqOptions)));
|
|
699
|
+
return this.#handleApiSuccess(data);
|
|
700
|
+
} catch (e) {
|
|
701
|
+
return await this.#handleApiError(e);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* Execute a raw GET request to any API endpoint with configurable response type.
|
|
707
|
+
* Supports both throwing (default) and non-throwing modes.
|
|
708
|
+
* @param urlPath - API endpoint path (e.g., 'organizations')
|
|
709
|
+
* @param options - Request options including responseType and throws behavior
|
|
710
|
+
* @returns Raw response, parsed data, or SocketSdkGenericResult based on options
|
|
711
|
+
*/
|
|
712
|
+
async getApi(urlPath, options) {
|
|
713
|
+
const {
|
|
714
|
+
responseType = 'response',
|
|
715
|
+
throws = true
|
|
716
|
+
} = {
|
|
717
|
+
__proto__: null,
|
|
718
|
+
...options
|
|
719
|
+
};
|
|
720
|
+
try {
|
|
721
|
+
const response = await httpClient.createGetRequest(this.#baseUrl, urlPath, this.#reqOptions);
|
|
722
|
+
// Check for HTTP error status codes first.
|
|
723
|
+
if (!httpClient.isResponseOk(response)) {
|
|
724
|
+
if (throws) {
|
|
725
|
+
throw new httpClient.ResponseError(response);
|
|
726
|
+
}
|
|
727
|
+
const errorResult = await this.#handleApiError(new httpClient.ResponseError(response));
|
|
175
728
|
return {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
729
|
+
cause: errorResult.cause,
|
|
730
|
+
data: undefined,
|
|
731
|
+
error: errorResult.error,
|
|
732
|
+
status: errorResult.status,
|
|
733
|
+
success: false
|
|
181
734
|
};
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
* Handle API error responses and convert to standardized error result.
|
|
205
|
-
* Internal error handling with status code analysis and message formatting.
|
|
206
|
-
*/
|
|
207
|
-
async #handleApiError(error) {
|
|
208
|
-
if (!(error instanceof http_client_1.ResponseError)) {
|
|
209
|
-
throw new Error('Unexpected Socket API error', {
|
|
210
|
-
cause: error,
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
const { statusCode } = error.response;
|
|
214
|
-
// Throw server errors (5xx) immediately - these are not recoverable client-side.
|
|
215
|
-
if (statusCode && statusCode >= 500) {
|
|
216
|
-
throw new Error(`Socket API server error (${statusCode})`, {
|
|
217
|
-
cause: error,
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
// The error payload may give a meaningful hint as to what went wrong.
|
|
221
|
-
const bodyStr = await (0, http_client_1.getErrorResponseBody)(error.response);
|
|
222
|
-
// Try to parse the body as JSON, fallback to treating as plain text.
|
|
223
|
-
let body;
|
|
224
|
-
try {
|
|
225
|
-
const parsed = JSON.parse(bodyStr);
|
|
226
|
-
// Client errors (4xx) should return actionable error messages.
|
|
227
|
-
// Extract both message and details from error response for better context.
|
|
228
|
-
if (typeof parsed?.error?.message === 'string') {
|
|
229
|
-
body = parsed.error.message;
|
|
230
|
-
// Include details if present for additional error context.
|
|
231
|
-
if (parsed.error.details) {
|
|
232
|
-
const detailsStr = typeof parsed.error.details === 'string'
|
|
233
|
-
? parsed.error.details
|
|
234
|
-
: JSON.stringify(parsed.error.details);
|
|
235
|
-
body = `${body} - Details: ${detailsStr}`;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
catch {
|
|
240
|
-
body = bodyStr;
|
|
241
|
-
}
|
|
242
|
-
// Build error message that includes the body content if available.
|
|
243
|
-
let errorMessage = error.message ?? UNKNOWN_ERROR_1.default;
|
|
244
|
-
const trimmedBody = body?.trim();
|
|
245
|
-
if (trimmedBody && !errorMessage.includes(trimmedBody)) {
|
|
246
|
-
// Replace generic status message with actual error body if present,
|
|
247
|
-
// otherwise append the body to the error message.
|
|
248
|
-
const statusMessage = error.response?.statusMessage;
|
|
249
|
-
if (statusMessage && errorMessage.includes(statusMessage)) {
|
|
250
|
-
errorMessage = errorMessage.replace(statusMessage, trimmedBody);
|
|
251
|
-
}
|
|
252
|
-
else {
|
|
253
|
-
/* c8 ignore next 2 - edge case where statusMessage is undefined or not in error message. */
|
|
254
|
-
errorMessage = `${errorMessage}: ${trimmedBody}`;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
735
|
+
}
|
|
736
|
+
const data = await this.#handleQueryResponseData(response, responseType);
|
|
737
|
+
if (throws) {
|
|
738
|
+
return data;
|
|
739
|
+
}
|
|
740
|
+
return {
|
|
741
|
+
cause: undefined,
|
|
742
|
+
data,
|
|
743
|
+
error: undefined,
|
|
744
|
+
/* c8 ignore next - Defensive fallback: response.statusCode is always defined in Node.js http/https */
|
|
745
|
+
status: response.statusCode ?? 200,
|
|
746
|
+
success: true
|
|
747
|
+
};
|
|
748
|
+
} catch (e) {
|
|
749
|
+
if (throws) {
|
|
750
|
+
throw e;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/* c8 ignore start - Defensive fallback: ResponseError in catch block handled in try block (lines 897-910) */
|
|
754
|
+
if (e instanceof httpClient.ResponseError) {
|
|
755
|
+
// Re-use existing error handling logic from the SDK
|
|
756
|
+
const errorResult = await this.#handleApiError(e);
|
|
257
757
|
return {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
success: false,
|
|
758
|
+
cause: errorResult.cause,
|
|
759
|
+
data: undefined,
|
|
760
|
+
error: errorResult.error,
|
|
761
|
+
status: errorResult.status,
|
|
762
|
+
success: false
|
|
264
763
|
};
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
764
|
+
}
|
|
765
|
+
/* c8 ignore stop */
|
|
766
|
+
|
|
767
|
+
/* c8 ignore next - Fallback error handling for non-ResponseError cases in getApi. */
|
|
768
|
+
return this.#createQueryErrorResult(e);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Get list of API tokens for an organization.
|
|
774
|
+
* Returns organization API tokens with metadata and permissions.
|
|
775
|
+
*
|
|
776
|
+
* @throws {Error} When server returns 5xx status codes
|
|
777
|
+
*/
|
|
778
|
+
async getAPITokens(orgSlug) {
|
|
779
|
+
try {
|
|
780
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/tokens`, this.#reqOptions)));
|
|
781
|
+
return this.#handleApiSuccess(data);
|
|
782
|
+
} catch (e) {
|
|
783
|
+
return await this.#handleApiError(e);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* Retrieve audit log events for an organization.
|
|
789
|
+
* Returns chronological log of security and administrative actions.
|
|
790
|
+
*
|
|
791
|
+
* @throws {Error} When server returns 5xx status codes
|
|
792
|
+
*/
|
|
793
|
+
async getAuditLogEvents(orgSlug, queryParams) {
|
|
794
|
+
try {
|
|
795
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/audit-log?${utils.queryToSearchParams(queryParams)}`, this.#reqOptions)));
|
|
796
|
+
return this.#handleApiSuccess(data);
|
|
797
|
+
} catch (e) {
|
|
798
|
+
return await this.#handleApiError(e);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* Get details for a specific diff scan.
|
|
804
|
+
* Returns comparison between two full scans with artifact changes.
|
|
805
|
+
*
|
|
806
|
+
* @throws {Error} When server returns 5xx status codes
|
|
807
|
+
*/
|
|
808
|
+
async getDiffScanById(orgSlug, diffScanId) {
|
|
809
|
+
try {
|
|
810
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/diff-scans/${encodeURIComponent(diffScanId)}`, this.#reqOptions)));
|
|
811
|
+
return this.#handleApiSuccess(data);
|
|
812
|
+
} catch (e) {
|
|
813
|
+
return await this.#handleApiError(e);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Retrieve the enabled entitlements for an organization.
|
|
819
|
+
*
|
|
820
|
+
* This method fetches the organization's entitlements and filters for only* the enabled ones, returning their keys. Entitlements represent Socket
|
|
821
|
+
* Products that the organization has access to use.
|
|
822
|
+
*/
|
|
823
|
+
async getEnabledEntitlements(orgSlug) {
|
|
824
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/entitlements`, this.#reqOptions)));
|
|
825
|
+
|
|
826
|
+
// Extract enabled products from the response.
|
|
827
|
+
const items = data?.items || [];
|
|
828
|
+
return items.filter(item => item && item.enabled === true && item.key).map(item => item.key);
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* Retrieve all entitlements for an organization.
|
|
833
|
+
*
|
|
834
|
+
* This method fetches all entitlements (both enabled and disabled) for
|
|
835
|
+
* an organization, returning the complete list with their status.
|
|
836
|
+
*/
|
|
837
|
+
async getEntitlements(orgSlug) {
|
|
838
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/entitlements`, this.#reqOptions)));
|
|
839
|
+
return data?.items || [];
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* Get security issues for a specific npm package and version.
|
|
844
|
+
* Returns detailed vulnerability and security alert information.
|
|
845
|
+
*
|
|
846
|
+
* @throws {Error} When server returns 5xx status codes
|
|
847
|
+
*/
|
|
848
|
+
async getIssuesByNpmPackage(pkgName, version) {
|
|
849
|
+
try {
|
|
850
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `npm/${encodeURIComponent(pkgName)}/${encodeURIComponent(version)}/issues`, this.#reqOptions)));
|
|
851
|
+
return this.#handleApiSuccess(data);
|
|
852
|
+
} catch (e) {
|
|
853
|
+
return await this.#handleApiError(e);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* Get analytics data for organization usage patterns and security metrics.
|
|
859
|
+
* Returns statistical analysis for specified time period.
|
|
860
|
+
*
|
|
861
|
+
* @throws {Error} When server returns 5xx status codes
|
|
862
|
+
*/
|
|
863
|
+
async getOrgAnalytics(time) {
|
|
864
|
+
try {
|
|
865
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `analytics/org/${encodeURIComponent(time)}`, this.#reqOptions)));
|
|
866
|
+
return this.#handleApiSuccess(data);
|
|
867
|
+
} catch (e) {
|
|
868
|
+
return await this.#handleApiError(e);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
/**
|
|
873
|
+
* List all organizations accessible to the current user.
|
|
874
|
+
* Returns organization details and access permissions.
|
|
875
|
+
*
|
|
876
|
+
* @throws {Error} When server returns 5xx status codes
|
|
877
|
+
*/
|
|
878
|
+
async getOrganizations() {
|
|
879
|
+
try {
|
|
880
|
+
const data = await this.#getCached('organizations', async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, 'organizations', this.#reqOptions)));
|
|
881
|
+
return this.#handleApiSuccess(data);
|
|
882
|
+
} catch (e) {
|
|
883
|
+
return await this.#handleApiError(e);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
/**
|
|
888
|
+
* Get complete full scan results in memory.
|
|
889
|
+
* Returns entire scan data as JSON for programmatic processing.
|
|
890
|
+
*
|
|
891
|
+
* @throws {Error} When server returns 5xx status codes
|
|
892
|
+
*/
|
|
893
|
+
async getOrgFullScanBuffered(orgSlug, fullScanId) {
|
|
894
|
+
try {
|
|
895
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}`, this.#reqOptions)));
|
|
896
|
+
return this.#handleApiSuccess(data);
|
|
897
|
+
} catch (e) {
|
|
898
|
+
return await this.#handleApiError(e);
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/**
|
|
903
|
+
* List all full scans for an organization.
|
|
904
|
+
* Returns paginated list of scan metadata and status.
|
|
905
|
+
*
|
|
906
|
+
* @throws {Error} When server returns 5xx status codes
|
|
907
|
+
*/
|
|
908
|
+
async getOrgFullScanList(orgSlug, queryParams) {
|
|
909
|
+
try {
|
|
910
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans?${utils.queryToSearchParams(queryParams)}`, this.#reqOptions)));
|
|
911
|
+
return this.#handleApiSuccess(data);
|
|
912
|
+
} catch (e) {
|
|
913
|
+
return await this.#handleApiError(e);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
/**
|
|
918
|
+
* Get metadata for a specific full scan.
|
|
919
|
+
* Returns scan configuration, status, and summary information.
|
|
920
|
+
*
|
|
921
|
+
* @throws {Error} When server returns 5xx status codes
|
|
922
|
+
*/
|
|
923
|
+
async getOrgFullScanMetadata(orgSlug, fullScanId) {
|
|
924
|
+
try {
|
|
925
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}/metadata`, this.#reqOptions)));
|
|
926
|
+
return this.#handleApiSuccess(data);
|
|
927
|
+
} catch (e) {
|
|
928
|
+
return await this.#handleApiError(e);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/**
|
|
933
|
+
* Get organization's license policy configuration.* Returns allowed, restricted, and monitored license types.
|
|
934
|
+
*
|
|
935
|
+
* @throws {Error} When server returns 5xx status codes
|
|
936
|
+
*/
|
|
937
|
+
async getOrgLicensePolicy(orgSlug) {
|
|
938
|
+
try {
|
|
939
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/settings/license-policy`, this.#reqOptions)));
|
|
940
|
+
return this.#handleApiSuccess(data);
|
|
941
|
+
} catch (e) {
|
|
942
|
+
return await this.#handleApiError(e);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
/**
|
|
947
|
+
* Get details for a specific organization repository.
|
|
948
|
+
* Returns repository configuration, monitoring status, and metadata.
|
|
949
|
+
*
|
|
950
|
+
* @throws {Error} When server returns 5xx status codes
|
|
951
|
+
*/
|
|
952
|
+
async getOrgRepo(orgSlug, repoSlug) {
|
|
953
|
+
const orgSlugParam = encodeURIComponent(orgSlug);
|
|
954
|
+
const repoSlugParam = encodeURIComponent(repoSlug);
|
|
955
|
+
try {
|
|
956
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${orgSlugParam}/repos/${repoSlugParam}`, this.#reqOptions)));
|
|
957
|
+
return this.#handleApiSuccess(data);
|
|
958
|
+
} catch (e) {
|
|
959
|
+
return await this.#handleApiError(e);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* Get details for a specific repository label.
|
|
965
|
+
* Returns label configuration and metadata.
|
|
966
|
+
*
|
|
967
|
+
* @throws {Error} When server returns 5xx status codes
|
|
968
|
+
*/
|
|
969
|
+
async getOrgRepoLabel(orgSlug, repoSlug, labelSlug) {
|
|
970
|
+
try {
|
|
971
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}/labels/${encodeURIComponent(labelSlug)}`, this.#reqOptions)));
|
|
972
|
+
return this.#handleApiSuccess(data);
|
|
973
|
+
} catch (e) {
|
|
974
|
+
return await this.#handleApiError(e);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
/**
|
|
979
|
+
* Get list of repository labels for an organization.
|
|
980
|
+
* Returns all labels configured for repository management.
|
|
981
|
+
*
|
|
982
|
+
* @throws {Error} When server returns 5xx status codes
|
|
983
|
+
*/
|
|
984
|
+
async getOrgRepoLabelList(orgSlug, repoSlug) {
|
|
985
|
+
try {
|
|
986
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}/labels`, this.#reqOptions)));
|
|
987
|
+
return this.#handleApiSuccess(data);
|
|
988
|
+
} catch (e) {
|
|
989
|
+
return await this.#handleApiError(e);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
/**
|
|
994
|
+
* List all repositories in an organization.
|
|
995
|
+
* Returns paginated list of repository metadata and status.
|
|
996
|
+
*
|
|
997
|
+
* @throws {Error} When server returns 5xx status codes
|
|
998
|
+
*/
|
|
999
|
+
async getOrgRepoList(orgSlug, queryParams) {
|
|
1000
|
+
try {
|
|
1001
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos?${utils.queryToSearchParams(queryParams)}`, this.#reqOptions)));
|
|
1002
|
+
return this.#handleApiSuccess(data);
|
|
1003
|
+
} catch (e) {
|
|
1004
|
+
return await this.#handleApiError(e);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/**
|
|
1009
|
+
* Get organization's security policy configuration.* Returns alert rules, severity thresholds, and enforcement settings.
|
|
1010
|
+
*
|
|
1011
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1012
|
+
*/
|
|
1013
|
+
async getOrgSecurityPolicy(orgSlug) {
|
|
1014
|
+
try {
|
|
1015
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/settings/security-policy`, this.#reqOptions)));
|
|
1016
|
+
return this.#handleApiSuccess(data);
|
|
1017
|
+
} catch (e) {
|
|
1018
|
+
return await this.#handleApiError(e);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
/**
|
|
1023
|
+
* Get organization triage settings and status.
|
|
1024
|
+
* Returns alert triage configuration and current state.
|
|
1025
|
+
*
|
|
1026
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1027
|
+
*/
|
|
1028
|
+
async getOrgTriage(orgSlug) {
|
|
1029
|
+
try {
|
|
1030
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/triage`, this.#reqOptions)));
|
|
1031
|
+
return this.#handleApiSuccess(data);
|
|
1032
|
+
} catch (e) {
|
|
1033
|
+
return await this.#handleApiError(e);
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
/**
|
|
1038
|
+
* Get current API quota usage and limits.
|
|
1039
|
+
* Returns remaining requests, rate limits, and quota reset times.
|
|
1040
|
+
*
|
|
1041
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1042
|
+
*/
|
|
1043
|
+
async getQuota() {
|
|
1044
|
+
try {
|
|
1045
|
+
const data = await this.#getCached('quota', async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, 'quota', this.#reqOptions)));
|
|
1046
|
+
return this.#handleApiSuccess(data);
|
|
1047
|
+
} catch (e) {
|
|
1048
|
+
return await this.#handleApiError(e);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
/**
|
|
1053
|
+
* Get analytics data for a specific repository.
|
|
1054
|
+
* Returns security metrics, dependency trends, and vulnerability statistics.
|
|
1055
|
+
*
|
|
1056
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1057
|
+
*/
|
|
1058
|
+
async getRepoAnalytics(repo, time) {
|
|
1059
|
+
try {
|
|
1060
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `analytics/repo/${encodeURIComponent(repo)}/${encodeURIComponent(time)}`, this.#reqOptions)));
|
|
1061
|
+
return this.#handleApiSuccess(data);
|
|
1062
|
+
} catch (e) {
|
|
1063
|
+
return await this.#handleApiError(e);
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
/**
|
|
1068
|
+
* Get detailed results for a specific scan.
|
|
1069
|
+
* Returns complete scan analysis including vulnerabilities and alerts.
|
|
1070
|
+
*
|
|
1071
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1072
|
+
*/
|
|
1073
|
+
async getScan(id) {
|
|
1074
|
+
try {
|
|
1075
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `report/view/${encodeURIComponent(id)}`, this.#reqOptions)));
|
|
1076
|
+
return this.#handleApiSuccess(data);
|
|
1077
|
+
} catch (e) {
|
|
1078
|
+
return await this.#handleApiError(e);
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
/**
|
|
1083
|
+
* List all scans accessible to the current user.
|
|
1084
|
+
* Returns paginated list of scan metadata and status.
|
|
1085
|
+
*
|
|
1086
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1087
|
+
*/
|
|
1088
|
+
async getScanList() {
|
|
1089
|
+
try {
|
|
1090
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, 'report/list', this.#reqOptions), 'GET'));
|
|
1091
|
+
return this.#handleApiSuccess(data);
|
|
1092
|
+
} catch (e) {
|
|
1093
|
+
return await this.#handleApiError(e);
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
/**
|
|
1098
|
+
* Get security score for a specific npm package and version.
|
|
1099
|
+
* Returns numerical security rating and scoring breakdown.
|
|
1100
|
+
*
|
|
1101
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1102
|
+
*/
|
|
1103
|
+
async getScoreByNpmPackage(pkgName, version) {
|
|
1104
|
+
try {
|
|
1105
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `npm/${encodeURIComponent(pkgName)}/${encodeURIComponent(version)}/score`, this.#reqOptions)));
|
|
1106
|
+
return this.#handleApiSuccess(data);
|
|
1107
|
+
} catch (e) {
|
|
1108
|
+
return await this.#handleApiError(e);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
/**
|
|
1113
|
+
* Get list of file types and formats supported for scanning.
|
|
1114
|
+
* Returns supported manifest files, lockfiles, and configuration formats.
|
|
1115
|
+
*
|
|
1116
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1117
|
+
*/
|
|
1118
|
+
async getSupportedScanFiles() {
|
|
1119
|
+
try {
|
|
1120
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, 'report/supported', this.#reqOptions)));
|
|
1121
|
+
return this.#handleApiSuccess(data);
|
|
1122
|
+
} catch (e) {
|
|
1123
|
+
return await this.#handleApiError(e);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
/**
|
|
1128
|
+
* List all diff scans for an organization.
|
|
1129
|
+
* Returns paginated list of diff scan metadata and status.
|
|
1130
|
+
*
|
|
1131
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1132
|
+
*/
|
|
1133
|
+
async listOrgDiffScans(orgSlug) {
|
|
1134
|
+
try {
|
|
1135
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/diff-scans`, this.#reqOptions)));
|
|
1136
|
+
return this.#handleApiSuccess(data);
|
|
1137
|
+
} catch (e) {
|
|
1138
|
+
return await this.#handleApiError(e);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
/**
|
|
1143
|
+
* Create a new API token for an organization.
|
|
1144
|
+
* Generates API token with specified scopes and metadata.
|
|
1145
|
+
*
|
|
1146
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1147
|
+
*/
|
|
1148
|
+
async postAPIToken(orgSlug, tokenData) {
|
|
1149
|
+
try {
|
|
1150
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/tokens`, tokenData, this.#reqOptions)));
|
|
1151
|
+
return this.#handleApiSuccess(data);
|
|
1152
|
+
} catch (e) {
|
|
1153
|
+
return await this.#handleApiError(e);
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
/**
|
|
1158
|
+
* Revoke an API token for an organization.
|
|
1159
|
+
* Permanently disables the token and removes access.
|
|
1160
|
+
*
|
|
1161
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1162
|
+
*/
|
|
1163
|
+
async postAPITokensRevoke(orgSlug, tokenId) {
|
|
1164
|
+
try {
|
|
1165
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/tokens/${encodeURIComponent(tokenId)}/revoke`, {}, this.#reqOptions)));
|
|
1166
|
+
return this.#handleApiSuccess(data);
|
|
1167
|
+
} catch (e) {
|
|
1168
|
+
return await this.#handleApiError(e);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
/**
|
|
1173
|
+
* Rotate an API token for an organization.
|
|
1174
|
+
* Generates new token value while preserving token metadata.
|
|
1175
|
+
*
|
|
1176
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1177
|
+
*/
|
|
1178
|
+
async postAPITokensRotate(orgSlug, tokenId) {
|
|
1179
|
+
try {
|
|
1180
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/tokens/${encodeURIComponent(tokenId)}/rotate`, {}, this.#reqOptions)));
|
|
1181
|
+
return this.#handleApiSuccess(data);
|
|
1182
|
+
} catch (e) {
|
|
1183
|
+
return await this.#handleApiError(e);
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
/**
|
|
1188
|
+
* Update an existing API token for an organization.
|
|
1189
|
+
* Modifies token metadata, scopes, or other properties.
|
|
1190
|
+
*
|
|
1191
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1192
|
+
*/
|
|
1193
|
+
async postAPITokenUpdate(orgSlug, tokenId, updateData) {
|
|
1194
|
+
try {
|
|
1195
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/tokens/${encodeURIComponent(tokenId)}/update`, updateData, this.#reqOptions)));
|
|
1196
|
+
return this.#handleApiSuccess(data);
|
|
1197
|
+
} catch (e) {
|
|
1198
|
+
return await this.#handleApiError(e);
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
/**
|
|
1203
|
+
* Update user or organization settings.
|
|
1204
|
+
* Configures preferences, notifications, and security policies.
|
|
1205
|
+
*
|
|
1206
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1207
|
+
*/
|
|
1208
|
+
async postSettings(selectors) {
|
|
1209
|
+
try {
|
|
1210
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, 'settings', {
|
|
1211
|
+
json: selectors
|
|
1212
|
+
}, this.#reqOptions)));
|
|
1213
|
+
return this.#handleApiSuccess(data);
|
|
1214
|
+
} catch (e) {
|
|
1215
|
+
return await this.#handleApiError(e);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
/**
|
|
1220
|
+
* Search for dependencies across monitored projects.
|
|
1221
|
+
* Returns matching packages with security information and usage patterns.
|
|
1222
|
+
*
|
|
1223
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1224
|
+
*/
|
|
1225
|
+
async searchDependencies(queryParams) {
|
|
1226
|
+
try {
|
|
1227
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, 'dependencies/search', queryParams, this.#reqOptions)));
|
|
1228
|
+
return this.#handleApiSuccess(data);
|
|
1229
|
+
} catch (e) {
|
|
1230
|
+
return await this.#handleApiError(e);
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
/**
|
|
1235
|
+
* Send POST or PUT request with JSON body and return parsed JSON response.
|
|
1236
|
+
* Supports both throwing (default) and non-throwing modes.
|
|
1237
|
+
* @param urlPath - API endpoint path (e.g., 'organizations')
|
|
1238
|
+
* @param options - Request options including method, body, and throws behavior
|
|
1239
|
+
* @returns Parsed JSON response or SocketSdkGenericResult based on options
|
|
1240
|
+
*/
|
|
1241
|
+
async sendApi(urlPath, options) {
|
|
1242
|
+
const {
|
|
1243
|
+
body,
|
|
1244
|
+
// Default to POST method for JSON API requests.
|
|
1245
|
+
method = 'POST',
|
|
1246
|
+
throws = true
|
|
1247
|
+
} = {
|
|
1248
|
+
__proto__: null,
|
|
1249
|
+
...options
|
|
1250
|
+
};
|
|
1251
|
+
try {
|
|
1252
|
+
// Route to appropriate HTTP method handler (POST or PUT).
|
|
1253
|
+
const response = await httpClient.createRequestWithJson(method, this.#baseUrl, urlPath, body, this.#reqOptions);
|
|
1254
|
+
const data = await httpClient.getResponseJson(response);
|
|
1255
|
+
if (throws) {
|
|
1256
|
+
return data;
|
|
1257
|
+
}
|
|
1258
|
+
return {
|
|
1259
|
+
cause: undefined,
|
|
1260
|
+
data,
|
|
1261
|
+
error: undefined,
|
|
1262
|
+
/* c8 ignore next - Defensive fallback: response.statusCode is always defined in Node.js http/https */
|
|
1263
|
+
status: response.statusCode ?? 200,
|
|
1264
|
+
success: true
|
|
1265
|
+
};
|
|
1266
|
+
} catch (e) {
|
|
1267
|
+
if (throws) {
|
|
1268
|
+
throw e;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
/* c8 ignore start - Defensive fallback: ResponseError in catch block handled in try block (lines 1686-1695) */
|
|
1272
|
+
if (e instanceof httpClient.ResponseError) {
|
|
1273
|
+
// Re-use existing error handling logic from the SDK
|
|
1274
|
+
const errorResult = await this.#handleApiError(e);
|
|
271
1275
|
return {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
success: true,
|
|
1276
|
+
cause: errorResult.cause,
|
|
1277
|
+
data: undefined,
|
|
1278
|
+
error: errorResult.error,
|
|
1279
|
+
status: errorResult.status,
|
|
1280
|
+
success: false
|
|
278
1281
|
};
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
1282
|
+
}
|
|
1283
|
+
/* c8 ignore stop */
|
|
1284
|
+
|
|
1285
|
+
/* c8 ignore start - Defensive error stringification fallback branches for sendApi edge cases. */
|
|
1286
|
+
const errStr = e ? String(e).trim() : '';
|
|
1287
|
+
return {
|
|
1288
|
+
cause: errStr || UNKNOWN_ERROR,
|
|
1289
|
+
data: undefined,
|
|
1290
|
+
error: 'API request failed',
|
|
1291
|
+
status: 0,
|
|
1292
|
+
success: false
|
|
1293
|
+
};
|
|
1294
|
+
/* c8 ignore stop */
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
/**
|
|
1299
|
+
* Stream a full scan's results to file or stdout.* Provides efficient streaming for large scan datasets.
|
|
1300
|
+
*
|
|
1301
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1302
|
+
*/
|
|
1303
|
+
async streamOrgFullScan(orgSlug, fullScanId, options) {
|
|
1304
|
+
const {
|
|
1305
|
+
output
|
|
1306
|
+
} = {
|
|
1307
|
+
__proto__: null,
|
|
1308
|
+
...options
|
|
1309
|
+
};
|
|
1310
|
+
try {
|
|
1311
|
+
const req = httpClient.getHttpModule(this.#baseUrl).request(`${this.#baseUrl}orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}`, {
|
|
1312
|
+
method: 'GET',
|
|
1313
|
+
...this.#reqOptions
|
|
1314
|
+
}).end();
|
|
1315
|
+
const res = await httpClient.getResponse(req);
|
|
1316
|
+
|
|
1317
|
+
// Check for HTTP error status codes.
|
|
1318
|
+
if (!httpClient.isResponseOk(res)) {
|
|
1319
|
+
throw new httpClient.ResponseError(res);
|
|
1320
|
+
}
|
|
1321
|
+
if (typeof output === 'string') {
|
|
1322
|
+
// Stream to file with error handling.
|
|
1323
|
+
const writeStream = node_fs.createWriteStream(output);
|
|
1324
|
+
res.pipe(writeStream);
|
|
1325
|
+
/* c8 ignore next 4 - Write stream error handler, difficult to test reliably */
|
|
1326
|
+
writeStream.on('error', error => {
|
|
1327
|
+
throw new Error(`Failed to write to file: ${output}`, {
|
|
1328
|
+
cause: error
|
|
1329
|
+
});
|
|
320
1330
|
});
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
return;
|
|
370
|
-
}
|
|
371
|
-
const generator = this.#createBatchPurlGenerator({
|
|
372
|
-
// Chunk components.
|
|
373
|
-
components: components.slice(index, index + chunkSize),
|
|
374
|
-
}, queryParams);
|
|
375
|
-
continueGen(generator);
|
|
376
|
-
index += chunkSize;
|
|
377
|
-
};
|
|
378
|
-
const continueGen = (generator) => {
|
|
379
|
-
const { promise, reject: rejectFn, resolve: resolveFn, } = (0, utils_1.promiseWithResolvers)();
|
|
380
|
-
running.push({
|
|
381
|
-
generator,
|
|
382
|
-
promise,
|
|
383
|
-
});
|
|
384
|
-
void generator
|
|
385
|
-
.next()
|
|
386
|
-
.then(iteratorResult => resolveFn({ generator, iteratorResult }), rejectFn);
|
|
387
|
-
};
|
|
388
|
-
// Start initial batch of generators.
|
|
389
|
-
while (running.length < concurrencyLimit && index < componentsCount) {
|
|
390
|
-
enqueueGen();
|
|
391
|
-
}
|
|
392
|
-
while (running.length > 0) {
|
|
393
|
-
// eslint-disable-next-line no-await-in-loop
|
|
394
|
-
const { generator, iteratorResult } = await Promise.race(running.map(entry => entry.promise));
|
|
395
|
-
// Remove generator with safe index lookup.
|
|
396
|
-
const index = running.findIndex(entry => entry.generator === generator);
|
|
397
|
-
/* c8 ignore next 3 - Defensive check for concurrent generator cleanup edge case. */
|
|
398
|
-
if (index === -1) {
|
|
399
|
-
continue;
|
|
400
|
-
}
|
|
401
|
-
running.splice(index, 1);
|
|
402
|
-
// Yield the value if one is given, even when done:true.
|
|
403
|
-
if (iteratorResult.value) {
|
|
404
|
-
yield iteratorResult.value;
|
|
405
|
-
}
|
|
406
|
-
if (iteratorResult.done) {
|
|
407
|
-
// Start a new generator if available.
|
|
408
|
-
enqueueGen();
|
|
409
|
-
}
|
|
410
|
-
else {
|
|
411
|
-
// Keep fetching values from this generator.
|
|
412
|
-
continueGen(generator);
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
// Reset abortSignal max listeners count.
|
|
416
|
-
/* c8 ignore start - Reset EventTarget max listeners to original value after batch operations. */
|
|
417
|
-
if (abortSignalMaxListeners > oldAbortSignalMaxListeners) {
|
|
418
|
-
node_events_1.default.setMaxListeners(oldAbortSignalMaxListeners, abort_signal_1.default);
|
|
419
|
-
}
|
|
420
|
-
/* c8 ignore stop */
|
|
421
|
-
}
|
|
422
|
-
/**
|
|
423
|
-
* Create a snapshot of project dependencies by uploading manifest files.
|
|
424
|
-
* Analyzes dependency files to generate a comprehensive security report.
|
|
425
|
-
*
|
|
426
|
-
* @throws {Error} When server returns 5xx status codes
|
|
427
|
-
*/
|
|
428
|
-
async createDependenciesSnapshot(filepaths, options) {
|
|
429
|
-
const { pathsRelativeTo = '.', queryParams } = {
|
|
430
|
-
__proto__: null,
|
|
431
|
-
...options,
|
|
432
|
-
};
|
|
433
|
-
const basePath = (0, utils_1.resolveBasePath)(pathsRelativeTo);
|
|
434
|
-
const absFilepaths = (0, utils_1.resolveAbsPaths)(filepaths, basePath);
|
|
435
|
-
try {
|
|
436
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, file_upload_1.createUploadRequest)(this.#baseUrl, `dependencies/upload?${(0, utils_1.queryToSearchParams)(queryParams)}`, (0, file_upload_1.createRequestBodyForFilepaths)(absFilepaths, basePath), this.#reqOptions)));
|
|
437
|
-
return this.#handleApiSuccess(data);
|
|
438
|
-
}
|
|
439
|
-
catch (e) {
|
|
440
|
-
return await this.#handleApiError(e);
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
/**
|
|
444
|
-
* Create a diff scan from two full scan IDs.
|
|
445
|
-
* Compares two existing full scans to identify changes.
|
|
446
|
-
*
|
|
447
|
-
* @throws {Error} When server returns 5xx status codes
|
|
448
|
-
*/
|
|
449
|
-
async createOrgDiffScanFromIds(orgSlug, queryParams) {
|
|
450
|
-
try {
|
|
451
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createRequestWithJson)('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/diff-scans?${(0, utils_1.queryToSearchParams)(queryParams)}`, {}, this.#reqOptions)));
|
|
452
|
-
return this.#handleApiSuccess(data);
|
|
453
|
-
}
|
|
454
|
-
catch (e) {
|
|
455
|
-
return await this.#handleApiError(e);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
/**
|
|
459
|
-
* Create a comprehensive security scan for an organization.
|
|
460
|
-
* Uploads project files and initiates full security analysis.
|
|
461
|
-
*
|
|
462
|
-
* @throws {Error} When server returns 5xx status codes
|
|
463
|
-
*/
|
|
464
|
-
async createOrgFullScan(orgSlug, filepaths, options) {
|
|
465
|
-
const { pathsRelativeTo = '.', queryParams } = {
|
|
466
|
-
__proto__: null,
|
|
467
|
-
...options,
|
|
468
|
-
};
|
|
469
|
-
const basePath = (0, utils_1.resolveBasePath)(pathsRelativeTo);
|
|
470
|
-
const absFilepaths = (0, utils_1.resolveAbsPaths)(filepaths, basePath);
|
|
471
|
-
try {
|
|
472
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, file_upload_1.createUploadRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans?${(0, utils_1.queryToSearchParams)(queryParams)}`, (0, file_upload_1.createRequestBodyForFilepaths)(absFilepaths, basePath), this.#reqOptions)));
|
|
473
|
-
return this.#handleApiSuccess(data);
|
|
474
|
-
}
|
|
475
|
-
catch (e) {
|
|
476
|
-
return await this.#handleApiError(e);
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
/**
|
|
480
|
-
* Create a new repository in an organization.
|
|
481
|
-
* Registers a repository for monitoring and security scanning.
|
|
482
|
-
*
|
|
483
|
-
* @throws {Error} When server returns 5xx status codes
|
|
484
|
-
*/
|
|
485
|
-
async createOrgRepo(orgSlug, queryParams) {
|
|
486
|
-
try {
|
|
487
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createRequestWithJson)('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos`, queryParams, this.#reqOptions)));
|
|
488
|
-
return this.#handleApiSuccess(data);
|
|
489
|
-
}
|
|
490
|
-
catch (e) {
|
|
491
|
-
return await this.#handleApiError(e);
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
/**
|
|
495
|
-
* Create a new repository label for an organization.
|
|
496
|
-
* Adds label for repository categorization and management.
|
|
497
|
-
*
|
|
498
|
-
* @throws {Error} When server returns 5xx status codes
|
|
499
|
-
*/
|
|
500
|
-
async createOrgRepoLabel(orgSlug, repoSlug, labelData) {
|
|
501
|
-
try {
|
|
502
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createRequestWithJson)('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}/labels`, labelData, this.#reqOptions)));
|
|
503
|
-
return this.#handleApiSuccess(data);
|
|
504
|
-
}
|
|
505
|
-
catch (e) {
|
|
506
|
-
return await this.#handleApiError(e);
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
/**
|
|
510
|
-
* Create a security scan by uploading project files.
|
|
511
|
-
* Analyzes uploaded files for security vulnerabilities and policy violations.
|
|
512
|
-
*
|
|
513
|
-
* @throws {Error} When server returns 5xx status codes
|
|
514
|
-
*/
|
|
515
|
-
async createScanFromFilepaths(filepaths, options) {
|
|
516
|
-
const { issueRules, pathsRelativeTo = '.' } = {
|
|
517
|
-
__proto__: null,
|
|
518
|
-
...options,
|
|
519
|
-
};
|
|
520
|
-
const basePath = (0, utils_1.resolveBasePath)(pathsRelativeTo);
|
|
521
|
-
const absFilepaths = (0, utils_1.resolveAbsPaths)(filepaths, basePath);
|
|
522
|
-
try {
|
|
523
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, file_upload_1.createUploadRequest)(this.#baseUrl, 'report/upload', [
|
|
524
|
-
...(0, file_upload_1.createRequestBodyForFilepaths)(absFilepaths, basePath),
|
|
525
|
-
/* c8 ignore next 3 - Optional issueRules parameter edge case. */
|
|
526
|
-
...(issueRules
|
|
527
|
-
? (0, file_upload_1.createRequestBodyForJson)(issueRules, 'issueRules')
|
|
528
|
-
: []),
|
|
529
|
-
], {
|
|
530
|
-
...this.#reqOptions,
|
|
531
|
-
method: 'PUT',
|
|
532
|
-
})
|
|
533
|
-
/* c8 ignore next 3 - Success path return statement requires complex file upload mocking with authentication. */
|
|
534
|
-
));
|
|
535
|
-
return this.#handleApiSuccess(data);
|
|
536
|
-
}
|
|
537
|
-
catch (e) {
|
|
538
|
-
return await this.#handleApiError(e);
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
/**
|
|
542
|
-
* Delete a diff scan from an organization.
|
|
543
|
-
* Permanently removes diff scan data and results.
|
|
544
|
-
*
|
|
545
|
-
* @throws {Error} When server returns 5xx status codes
|
|
546
|
-
*/
|
|
547
|
-
async deleteOrgDiffScan(orgSlug, diffScanId) {
|
|
548
|
-
try {
|
|
549
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createDeleteRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/diff-scans/${encodeURIComponent(diffScanId)}`, this.#reqOptions)));
|
|
550
|
-
return this.#handleApiSuccess(data);
|
|
551
|
-
}
|
|
552
|
-
catch (e) {
|
|
553
|
-
return await this.#handleApiError(e);
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
/**
|
|
557
|
-
* Delete a full scan from an organization.
|
|
558
|
-
* Permanently removes scan data and results.
|
|
559
|
-
*
|
|
560
|
-
* @throws {Error} When server returns 5xx status codes
|
|
561
|
-
*/
|
|
562
|
-
async deleteOrgFullScan(orgSlug, fullScanId) {
|
|
563
|
-
try {
|
|
564
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createDeleteRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}`, this.#reqOptions)));
|
|
565
|
-
return this.#handleApiSuccess(data);
|
|
566
|
-
}
|
|
567
|
-
catch (e) {
|
|
568
|
-
return await this.#handleApiError(e);
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
/**
|
|
572
|
-
* Delete a repository from an organization.
|
|
573
|
-
* Removes repository monitoring and associated scan data.
|
|
574
|
-
*
|
|
575
|
-
* @throws {Error} When server returns 5xx status codes
|
|
576
|
-
*/
|
|
577
|
-
async deleteOrgRepo(orgSlug, repoSlug) {
|
|
578
|
-
try {
|
|
579
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createDeleteRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}`, this.#reqOptions)));
|
|
580
|
-
return this.#handleApiSuccess(data);
|
|
581
|
-
}
|
|
582
|
-
catch (e) {
|
|
583
|
-
return await this.#handleApiError(e);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
/**
|
|
587
|
-
* Delete a repository label from an organization.
|
|
588
|
-
* Removes label and associated configuration.
|
|
589
|
-
*
|
|
590
|
-
* @throws {Error} When server returns 5xx status codes
|
|
591
|
-
*/
|
|
592
|
-
async deleteOrgRepoLabel(orgSlug, repoSlug, labelSlug) {
|
|
593
|
-
try {
|
|
594
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createDeleteRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}/labels/${encodeURIComponent(labelSlug)}`, this.#reqOptions)));
|
|
595
|
-
return this.#handleApiSuccess(data);
|
|
596
|
-
}
|
|
597
|
-
catch (e) {
|
|
598
|
-
return await this.#handleApiError(e);
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
/**
|
|
602
|
-
* Delete a scan report permanently.
|
|
603
|
-
* Removes scan data and analysis results from the system.
|
|
604
|
-
*
|
|
605
|
-
* @throws {Error} When server returns 5xx status codes
|
|
606
|
-
*/
|
|
607
|
-
async deleteReport(reportId) {
|
|
608
|
-
try {
|
|
609
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createDeleteRequest)(this.#baseUrl, `report/delete/${encodeURIComponent(reportId)}`, this.#reqOptions)));
|
|
610
|
-
return this.#handleApiSuccess(data);
|
|
611
|
-
}
|
|
612
|
-
catch (e) {
|
|
613
|
-
return await this.#handleApiError(e);
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
/**
|
|
617
|
-
* Export scan results in CycloneDX SBOM format.
|
|
618
|
-
* Returns Software Bill of Materials compliant with CycloneDX standard.
|
|
619
|
-
*
|
|
620
|
-
* @throws {Error} When server returns 5xx status codes
|
|
621
|
-
*/
|
|
622
|
-
async exportCDX(orgSlug, fullScanId) {
|
|
623
|
-
try {
|
|
624
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}/sbom/export/cdx`, this.#reqOptions)));
|
|
625
|
-
return this.#handleApiSuccess(data);
|
|
626
|
-
}
|
|
627
|
-
catch (e) {
|
|
628
|
-
return await this.#handleApiError(e);
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
/**
|
|
632
|
-
* Export scan results in SPDX SBOM format.
|
|
633
|
-
* Returns Software Bill of Materials compliant with SPDX standard.
|
|
634
|
-
*
|
|
635
|
-
* @throws {Error} When server returns 5xx status codes
|
|
636
|
-
*/
|
|
637
|
-
async exportSPDX(orgSlug, fullScanId) {
|
|
638
|
-
try {
|
|
639
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}/sbom/export/spdx`, this.#reqOptions)));
|
|
640
|
-
return this.#handleApiSuccess(data);
|
|
641
|
-
}
|
|
642
|
-
catch (e) {
|
|
643
|
-
return await this.#handleApiError(e);
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
/**
|
|
647
|
-
* Execute a raw GET request to any API endpoint with configurable response type.
|
|
648
|
-
* Supports both throwing (default) and non-throwing modes.
|
|
649
|
-
* @param urlPath - API endpoint path (e.g., 'organizations')
|
|
650
|
-
* @param options - Request options including responseType and throws behavior
|
|
651
|
-
* @returns Raw response, parsed data, or SocketSdkGenericResult based on options
|
|
652
|
-
*/
|
|
653
|
-
async getApi(urlPath, options) {
|
|
654
|
-
const { responseType = 'response', throws = true } = {
|
|
655
|
-
__proto__: null,
|
|
656
|
-
...options,
|
|
657
|
-
};
|
|
658
|
-
try {
|
|
659
|
-
const response = await (0, http_client_1.createGetRequest)(this.#baseUrl, urlPath, this.#reqOptions);
|
|
660
|
-
// Check for HTTP error status codes first.
|
|
661
|
-
if (!(0, http_client_1.isResponseOk)(response)) {
|
|
662
|
-
if (throws) {
|
|
663
|
-
throw new http_client_1.ResponseError(response);
|
|
664
|
-
}
|
|
665
|
-
const errorResult = await this.#handleApiError(new http_client_1.ResponseError(response));
|
|
666
|
-
return {
|
|
667
|
-
cause: errorResult.cause,
|
|
668
|
-
data: undefined,
|
|
669
|
-
error: errorResult.error,
|
|
670
|
-
status: errorResult.status,
|
|
671
|
-
success: false,
|
|
672
|
-
};
|
|
673
|
-
}
|
|
674
|
-
const data = await this.#handleQueryResponseData(response, responseType);
|
|
675
|
-
if (throws) {
|
|
676
|
-
return data;
|
|
677
|
-
}
|
|
678
|
-
return {
|
|
679
|
-
cause: undefined,
|
|
680
|
-
data,
|
|
681
|
-
error: undefined,
|
|
682
|
-
/* c8 ignore next - Defensive fallback: response.statusCode is always defined in Node.js http/https */
|
|
683
|
-
status: response.statusCode ?? 200,
|
|
684
|
-
success: true,
|
|
685
|
-
};
|
|
686
|
-
}
|
|
687
|
-
catch (e) {
|
|
688
|
-
if (throws) {
|
|
689
|
-
throw e;
|
|
690
|
-
}
|
|
691
|
-
/* c8 ignore start - Defensive fallback: ResponseError in catch block handled in try block (lines 897-910) */
|
|
692
|
-
if (e instanceof http_client_1.ResponseError) {
|
|
693
|
-
// Re-use existing error handling logic from the SDK
|
|
694
|
-
const errorResult = await this.#handleApiError(e);
|
|
695
|
-
return {
|
|
696
|
-
cause: errorResult.cause,
|
|
697
|
-
data: undefined,
|
|
698
|
-
error: errorResult.error,
|
|
699
|
-
status: errorResult.status,
|
|
700
|
-
success: false,
|
|
701
|
-
};
|
|
702
|
-
}
|
|
703
|
-
/* c8 ignore stop */
|
|
704
|
-
/* c8 ignore next - Fallback error handling for non-ResponseError cases in getApi. */
|
|
705
|
-
return this.#createQueryErrorResult(e);
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
/**
|
|
709
|
-
* Get list of API tokens for an organization.
|
|
710
|
-
* Returns organization API tokens with metadata and permissions.
|
|
711
|
-
*
|
|
712
|
-
* @throws {Error} When server returns 5xx status codes
|
|
713
|
-
*/
|
|
714
|
-
async getAPITokens(orgSlug) {
|
|
715
|
-
try {
|
|
716
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/tokens`, this.#reqOptions)));
|
|
717
|
-
return this.#handleApiSuccess(data);
|
|
718
|
-
}
|
|
719
|
-
catch (e) {
|
|
720
|
-
return await this.#handleApiError(e);
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
/**
|
|
724
|
-
* Retrieve audit log events for an organization.
|
|
725
|
-
* Returns chronological log of security and administrative actions.
|
|
726
|
-
*
|
|
727
|
-
* @throws {Error} When server returns 5xx status codes
|
|
728
|
-
*/
|
|
729
|
-
async getAuditLogEvents(orgSlug, queryParams) {
|
|
730
|
-
try {
|
|
731
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/audit-log?${(0, utils_1.queryToSearchParams)(queryParams)}`, this.#reqOptions)));
|
|
732
|
-
return this.#handleApiSuccess(data);
|
|
733
|
-
}
|
|
734
|
-
catch (e) {
|
|
735
|
-
return await this.#handleApiError(e);
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
/**
|
|
739
|
-
* Get details for a specific diff scan.
|
|
740
|
-
* Returns comparison between two full scans with artifact changes.
|
|
741
|
-
*
|
|
742
|
-
* @throws {Error} When server returns 5xx status codes
|
|
743
|
-
*/
|
|
744
|
-
async getDiffScanById(orgSlug, diffScanId) {
|
|
745
|
-
try {
|
|
746
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/diff-scans/${encodeURIComponent(diffScanId)}`, this.#reqOptions)));
|
|
747
|
-
return this.#handleApiSuccess(data);
|
|
748
|
-
}
|
|
749
|
-
catch (e) {
|
|
750
|
-
return await this.#handleApiError(e);
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
/**
|
|
754
|
-
* Retrieve the enabled entitlements for an organization.
|
|
755
|
-
*
|
|
756
|
-
* This method fetches the organization's entitlements and filters for only* the enabled ones, returning their keys. Entitlements represent Socket
|
|
757
|
-
* Products that the organization has access to use.
|
|
758
|
-
*/
|
|
759
|
-
async getEnabledEntitlements(orgSlug) {
|
|
760
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/entitlements`, this.#reqOptions)));
|
|
761
|
-
// Extract enabled products from the response.
|
|
762
|
-
const items = data?.items || [];
|
|
763
|
-
return items
|
|
764
|
-
.filter((item) => item && item.enabled === true && item.key)
|
|
765
|
-
.map((item) => item.key);
|
|
766
|
-
}
|
|
767
|
-
/**
|
|
768
|
-
* Retrieve all entitlements for an organization.
|
|
769
|
-
*
|
|
770
|
-
* This method fetches all entitlements (both enabled and disabled) for
|
|
771
|
-
* an organization, returning the complete list with their status.
|
|
772
|
-
*/
|
|
773
|
-
async getEntitlements(orgSlug) {
|
|
774
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/entitlements`, this.#reqOptions)));
|
|
775
|
-
return data?.items || [];
|
|
776
|
-
}
|
|
777
|
-
/**
|
|
778
|
-
* Get security issues for a specific npm package and version.
|
|
779
|
-
* Returns detailed vulnerability and security alert information.
|
|
780
|
-
*
|
|
781
|
-
* @throws {Error} When server returns 5xx status codes
|
|
782
|
-
*/
|
|
783
|
-
async getIssuesByNpmPackage(pkgName, version) {
|
|
784
|
-
try {
|
|
785
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `npm/${encodeURIComponent(pkgName)}/${encodeURIComponent(version)}/issues`, this.#reqOptions)));
|
|
786
|
-
return this.#handleApiSuccess(data);
|
|
787
|
-
}
|
|
788
|
-
catch (e) {
|
|
789
|
-
return await this.#handleApiError(e);
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
/**
|
|
793
|
-
* Get analytics data for organization usage patterns and security metrics.
|
|
794
|
-
* Returns statistical analysis for specified time period.
|
|
795
|
-
*
|
|
796
|
-
* @throws {Error} When server returns 5xx status codes
|
|
797
|
-
*/
|
|
798
|
-
async getOrgAnalytics(time) {
|
|
799
|
-
try {
|
|
800
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `analytics/org/${encodeURIComponent(time)}`, this.#reqOptions)));
|
|
801
|
-
return this.#handleApiSuccess(data);
|
|
802
|
-
}
|
|
803
|
-
catch (e) {
|
|
804
|
-
return await this.#handleApiError(e);
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
/**
|
|
808
|
-
* List all organizations accessible to the current user.
|
|
809
|
-
* Returns organization details and access permissions.
|
|
810
|
-
*
|
|
811
|
-
* @throws {Error} When server returns 5xx status codes
|
|
812
|
-
*/
|
|
813
|
-
async getOrganizations() {
|
|
814
|
-
try {
|
|
815
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, 'organizations', this.#reqOptions)));
|
|
816
|
-
return this.#handleApiSuccess(data);
|
|
817
|
-
}
|
|
818
|
-
catch (e) {
|
|
819
|
-
return await this.#handleApiError(e);
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
/**
|
|
823
|
-
* Get complete full scan results in memory.
|
|
824
|
-
* Returns entire scan data as JSON for programmatic processing.
|
|
825
|
-
*
|
|
826
|
-
* @throws {Error} When server returns 5xx status codes
|
|
827
|
-
*/
|
|
828
|
-
async getOrgFullScanBuffered(orgSlug, fullScanId) {
|
|
829
|
-
try {
|
|
830
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}`, this.#reqOptions)));
|
|
831
|
-
return this.#handleApiSuccess(data);
|
|
832
|
-
}
|
|
833
|
-
catch (e) {
|
|
834
|
-
return await this.#handleApiError(e);
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
/**
|
|
838
|
-
* List all full scans for an organization.
|
|
839
|
-
* Returns paginated list of scan metadata and status.
|
|
840
|
-
*
|
|
841
|
-
* @throws {Error} When server returns 5xx status codes
|
|
842
|
-
*/
|
|
843
|
-
async getOrgFullScanList(orgSlug, queryParams) {
|
|
844
|
-
try {
|
|
845
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans?${(0, utils_1.queryToSearchParams)(queryParams)}`, this.#reqOptions)));
|
|
846
|
-
return this.#handleApiSuccess(data);
|
|
847
|
-
}
|
|
848
|
-
catch (e) {
|
|
849
|
-
return await this.#handleApiError(e);
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
/**
|
|
853
|
-
* Get metadata for a specific full scan.
|
|
854
|
-
* Returns scan configuration, status, and summary information.
|
|
855
|
-
*
|
|
856
|
-
* @throws {Error} When server returns 5xx status codes
|
|
857
|
-
*/
|
|
858
|
-
async getOrgFullScanMetadata(orgSlug, fullScanId) {
|
|
859
|
-
try {
|
|
860
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}/metadata`, this.#reqOptions)));
|
|
861
|
-
return this.#handleApiSuccess(data);
|
|
862
|
-
}
|
|
863
|
-
catch (e) {
|
|
864
|
-
return await this.#handleApiError(e);
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
/**
|
|
868
|
-
* Get organization's license policy configuration.* Returns allowed, restricted, and monitored license types.
|
|
869
|
-
*
|
|
870
|
-
* @throws {Error} When server returns 5xx status codes
|
|
871
|
-
*/
|
|
872
|
-
async getOrgLicensePolicy(orgSlug) {
|
|
873
|
-
try {
|
|
874
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/settings/license-policy`, this.#reqOptions)));
|
|
875
|
-
return this.#handleApiSuccess(data);
|
|
876
|
-
}
|
|
877
|
-
catch (e) {
|
|
878
|
-
return await this.#handleApiError(e);
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
/**
|
|
882
|
-
* Get details for a specific organization repository.
|
|
883
|
-
* Returns repository configuration, monitoring status, and metadata.
|
|
884
|
-
*
|
|
885
|
-
* @throws {Error} When server returns 5xx status codes
|
|
886
|
-
*/
|
|
887
|
-
async getOrgRepo(orgSlug, repoSlug) {
|
|
888
|
-
const orgSlugParam = encodeURIComponent(orgSlug);
|
|
889
|
-
const repoSlugParam = encodeURIComponent(repoSlug);
|
|
890
|
-
try {
|
|
891
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${orgSlugParam}/repos/${repoSlugParam}`, this.#reqOptions)));
|
|
892
|
-
return this.#handleApiSuccess(data);
|
|
893
|
-
}
|
|
894
|
-
catch (e) {
|
|
895
|
-
return await this.#handleApiError(e);
|
|
896
|
-
}
|
|
897
|
-
}
|
|
898
|
-
/**
|
|
899
|
-
* Get details for a specific repository label.
|
|
900
|
-
* Returns label configuration and metadata.
|
|
901
|
-
*
|
|
902
|
-
* @throws {Error} When server returns 5xx status codes
|
|
903
|
-
*/
|
|
904
|
-
async getOrgRepoLabel(orgSlug, repoSlug, labelSlug) {
|
|
905
|
-
try {
|
|
906
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}/labels/${encodeURIComponent(labelSlug)}`, this.#reqOptions)));
|
|
907
|
-
return this.#handleApiSuccess(data);
|
|
908
|
-
}
|
|
909
|
-
catch (e) {
|
|
910
|
-
return await this.#handleApiError(e);
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
/**
|
|
914
|
-
* Get list of repository labels for an organization.
|
|
915
|
-
* Returns all labels configured for repository management.
|
|
916
|
-
*
|
|
917
|
-
* @throws {Error} When server returns 5xx status codes
|
|
918
|
-
*/
|
|
919
|
-
async getOrgRepoLabelList(orgSlug, repoSlug) {
|
|
920
|
-
try {
|
|
921
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}/labels`, this.#reqOptions)));
|
|
922
|
-
return this.#handleApiSuccess(data);
|
|
923
|
-
}
|
|
924
|
-
catch (e) {
|
|
925
|
-
return await this.#handleApiError(e);
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
/**
|
|
929
|
-
* List all repositories in an organization.
|
|
930
|
-
* Returns paginated list of repository metadata and status.
|
|
931
|
-
*
|
|
932
|
-
* @throws {Error} When server returns 5xx status codes
|
|
933
|
-
*/
|
|
934
|
-
async getOrgRepoList(orgSlug, queryParams) {
|
|
935
|
-
try {
|
|
936
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos?${(0, utils_1.queryToSearchParams)(queryParams)}`, this.#reqOptions)));
|
|
937
|
-
return this.#handleApiSuccess(data);
|
|
938
|
-
}
|
|
939
|
-
catch (e) {
|
|
940
|
-
return await this.#handleApiError(e);
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
/**
|
|
944
|
-
* Get organization's security policy configuration.* Returns alert rules, severity thresholds, and enforcement settings.
|
|
945
|
-
*
|
|
946
|
-
* @throws {Error} When server returns 5xx status codes
|
|
947
|
-
*/
|
|
948
|
-
async getOrgSecurityPolicy(orgSlug) {
|
|
949
|
-
try {
|
|
950
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/settings/security-policy`, this.#reqOptions)));
|
|
951
|
-
return this.#handleApiSuccess(data);
|
|
952
|
-
}
|
|
953
|
-
catch (e) {
|
|
954
|
-
return await this.#handleApiError(e);
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
/**
|
|
958
|
-
* Get organization triage settings and status.
|
|
959
|
-
* Returns alert triage configuration and current state.
|
|
960
|
-
*
|
|
961
|
-
* @throws {Error} When server returns 5xx status codes
|
|
962
|
-
*/
|
|
963
|
-
async getOrgTriage(orgSlug) {
|
|
964
|
-
try {
|
|
965
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/triage`, this.#reqOptions)));
|
|
966
|
-
return this.#handleApiSuccess(data);
|
|
967
|
-
}
|
|
968
|
-
catch (e) {
|
|
969
|
-
return await this.#handleApiError(e);
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
/**
|
|
973
|
-
* Get current API quota usage and limits.
|
|
974
|
-
* Returns remaining requests, rate limits, and quota reset times.
|
|
975
|
-
*
|
|
976
|
-
* @throws {Error} When server returns 5xx status codes
|
|
977
|
-
*/
|
|
978
|
-
async getQuota() {
|
|
979
|
-
try {
|
|
980
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, 'quota', this.#reqOptions)));
|
|
981
|
-
return this.#handleApiSuccess(data);
|
|
982
|
-
}
|
|
983
|
-
catch (e) {
|
|
984
|
-
return await this.#handleApiError(e);
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
/**
|
|
988
|
-
* Get analytics data for a specific repository.
|
|
989
|
-
* Returns security metrics, dependency trends, and vulnerability statistics.
|
|
990
|
-
*
|
|
991
|
-
* @throws {Error} When server returns 5xx status codes
|
|
992
|
-
*/
|
|
993
|
-
async getRepoAnalytics(repo, time) {
|
|
994
|
-
try {
|
|
995
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `analytics/repo/${encodeURIComponent(repo)}/${encodeURIComponent(time)}`, this.#reqOptions)));
|
|
996
|
-
return this.#handleApiSuccess(data);
|
|
997
|
-
}
|
|
998
|
-
catch (e) {
|
|
999
|
-
return await this.#handleApiError(e);
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
/**
|
|
1003
|
-
* Get detailed results for a specific scan.
|
|
1004
|
-
* Returns complete scan analysis including vulnerabilities and alerts.
|
|
1005
|
-
*
|
|
1006
|
-
* @throws {Error} When server returns 5xx status codes
|
|
1007
|
-
*/
|
|
1008
|
-
async getScan(id) {
|
|
1009
|
-
try {
|
|
1010
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `report/view/${encodeURIComponent(id)}`, this.#reqOptions)));
|
|
1011
|
-
return this.#handleApiSuccess(data);
|
|
1012
|
-
}
|
|
1013
|
-
catch (e) {
|
|
1014
|
-
return await this.#handleApiError(e);
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
/**
|
|
1018
|
-
* List all scans accessible to the current user.
|
|
1019
|
-
* Returns paginated list of scan metadata and status.
|
|
1020
|
-
*
|
|
1021
|
-
* @throws {Error} When server returns 5xx status codes
|
|
1022
|
-
*/
|
|
1023
|
-
async getScanList() {
|
|
1024
|
-
try {
|
|
1025
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, 'report/list', this.#reqOptions), 'GET'));
|
|
1026
|
-
return this.#handleApiSuccess(data);
|
|
1027
|
-
}
|
|
1028
|
-
catch (e) {
|
|
1029
|
-
return await this.#handleApiError(e);
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
|
-
/**
|
|
1033
|
-
* Get security score for a specific npm package and version.
|
|
1034
|
-
* Returns numerical security rating and scoring breakdown.
|
|
1035
|
-
*
|
|
1036
|
-
* @throws {Error} When server returns 5xx status codes
|
|
1037
|
-
*/
|
|
1038
|
-
async getScoreByNpmPackage(pkgName, version) {
|
|
1039
|
-
try {
|
|
1040
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `npm/${encodeURIComponent(pkgName)}/${encodeURIComponent(version)}/score`, this.#reqOptions)));
|
|
1041
|
-
return this.#handleApiSuccess(data);
|
|
1042
|
-
}
|
|
1043
|
-
catch (e) {
|
|
1044
|
-
return await this.#handleApiError(e);
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
/**
|
|
1048
|
-
* Get list of file types and formats supported for scanning.
|
|
1049
|
-
* Returns supported manifest files, lockfiles, and configuration formats.
|
|
1050
|
-
*
|
|
1051
|
-
* @throws {Error} When server returns 5xx status codes
|
|
1052
|
-
*/
|
|
1053
|
-
async getSupportedScanFiles() {
|
|
1054
|
-
try {
|
|
1055
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, 'report/supported', this.#reqOptions)));
|
|
1056
|
-
return this.#handleApiSuccess(data);
|
|
1057
|
-
}
|
|
1058
|
-
catch (e) {
|
|
1059
|
-
return await this.#handleApiError(e);
|
|
1060
|
-
}
|
|
1061
|
-
}
|
|
1062
|
-
/**
|
|
1063
|
-
* List all diff scans for an organization.
|
|
1064
|
-
* Returns paginated list of diff scan metadata and status.
|
|
1065
|
-
*
|
|
1066
|
-
* @throws {Error} When server returns 5xx status codes
|
|
1067
|
-
*/
|
|
1068
|
-
async listOrgDiffScans(orgSlug) {
|
|
1069
|
-
try {
|
|
1070
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/diff-scans`, this.#reqOptions)));
|
|
1071
|
-
return this.#handleApiSuccess(data);
|
|
1072
|
-
}
|
|
1073
|
-
catch (e) {
|
|
1074
|
-
return await this.#handleApiError(e);
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
|
-
/**
|
|
1078
|
-
* Create a new API token for an organization.
|
|
1079
|
-
* Generates API token with specified scopes and metadata.
|
|
1080
|
-
*
|
|
1081
|
-
* @throws {Error} When server returns 5xx status codes
|
|
1082
|
-
*/
|
|
1083
|
-
async postAPIToken(orgSlug, tokenData) {
|
|
1084
|
-
try {
|
|
1085
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createRequestWithJson)('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/tokens`, tokenData, this.#reqOptions)));
|
|
1086
|
-
return this.#handleApiSuccess(data);
|
|
1087
|
-
}
|
|
1088
|
-
catch (e) {
|
|
1089
|
-
return await this.#handleApiError(e);
|
|
1090
|
-
}
|
|
1091
|
-
}
|
|
1092
|
-
/**
|
|
1093
|
-
* Revoke an API token for an organization.
|
|
1094
|
-
* Permanently disables the token and removes access.
|
|
1095
|
-
*
|
|
1096
|
-
* @throws {Error} When server returns 5xx status codes
|
|
1097
|
-
*/
|
|
1098
|
-
async postAPITokensRevoke(orgSlug, tokenId) {
|
|
1099
|
-
try {
|
|
1100
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createRequestWithJson)('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/tokens/${encodeURIComponent(tokenId)}/revoke`, {}, this.#reqOptions)));
|
|
1101
|
-
return this.#handleApiSuccess(data);
|
|
1102
|
-
}
|
|
1103
|
-
catch (e) {
|
|
1104
|
-
return await this.#handleApiError(e);
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
/**
|
|
1108
|
-
* Rotate an API token for an organization.
|
|
1109
|
-
* Generates new token value while preserving token metadata.
|
|
1110
|
-
*
|
|
1111
|
-
* @throws {Error} When server returns 5xx status codes
|
|
1112
|
-
*/
|
|
1113
|
-
async postAPITokensRotate(orgSlug, tokenId) {
|
|
1114
|
-
try {
|
|
1115
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createRequestWithJson)('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/tokens/${encodeURIComponent(tokenId)}/rotate`, {}, this.#reqOptions)));
|
|
1116
|
-
return this.#handleApiSuccess(data);
|
|
1117
|
-
}
|
|
1118
|
-
catch (e) {
|
|
1119
|
-
return await this.#handleApiError(e);
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1122
|
-
/**
|
|
1123
|
-
* Update an existing API token for an organization.
|
|
1124
|
-
* Modifies token metadata, scopes, or other properties.
|
|
1125
|
-
*
|
|
1126
|
-
* @throws {Error} When server returns 5xx status codes
|
|
1127
|
-
*/
|
|
1128
|
-
async postAPITokenUpdate(orgSlug, tokenId, updateData) {
|
|
1129
|
-
try {
|
|
1130
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createRequestWithJson)('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/tokens/${encodeURIComponent(tokenId)}/update`, updateData, this.#reqOptions)));
|
|
1131
|
-
return this.#handleApiSuccess(data);
|
|
1132
|
-
}
|
|
1133
|
-
catch (e) {
|
|
1134
|
-
return await this.#handleApiError(e);
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
/**
|
|
1138
|
-
* Update user or organization settings.
|
|
1139
|
-
* Configures preferences, notifications, and security policies.
|
|
1140
|
-
*
|
|
1141
|
-
* @throws {Error} When server returns 5xx status codes
|
|
1142
|
-
*/
|
|
1143
|
-
async postSettings(selectors) {
|
|
1144
|
-
try {
|
|
1145
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createRequestWithJson)('POST', this.#baseUrl, 'settings', { json: selectors }, this.#reqOptions)));
|
|
1146
|
-
return this.#handleApiSuccess(data);
|
|
1147
|
-
}
|
|
1148
|
-
catch (e) {
|
|
1149
|
-
return await this.#handleApiError(e);
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1152
|
-
/**
|
|
1153
|
-
* Search for dependencies across monitored projects.
|
|
1154
|
-
* Returns matching packages with security information and usage patterns.
|
|
1155
|
-
*
|
|
1156
|
-
* @throws {Error} When server returns 5xx status codes
|
|
1157
|
-
*/
|
|
1158
|
-
async searchDependencies(queryParams) {
|
|
1159
|
-
try {
|
|
1160
|
-
const data = await this.#executeWithRetry(async () => await (0, http_client_1.getResponseJson)(await (0, http_client_1.createRequestWithJson)('POST', this.#baseUrl, 'dependencies/search', queryParams, this.#reqOptions)));
|
|
1161
|
-
return this.#handleApiSuccess(data);
|
|
1162
|
-
}
|
|
1163
|
-
catch (e) {
|
|
1164
|
-
return await this.#handleApiError(e);
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1167
|
-
/**
|
|
1168
|
-
* Send POST or PUT request with JSON body and return parsed JSON response.
|
|
1169
|
-
* Supports both throwing (default) and non-throwing modes.
|
|
1170
|
-
* @param urlPath - API endpoint path (e.g., 'organizations')
|
|
1171
|
-
* @param options - Request options including method, body, and throws behavior
|
|
1172
|
-
* @returns Parsed JSON response or SocketSdkGenericResult based on options
|
|
1173
|
-
*/
|
|
1174
|
-
async sendApi(urlPath, options) {
|
|
1175
|
-
const { body,
|
|
1176
|
-
// Default to POST method for JSON API requests.
|
|
1177
|
-
method = 'POST', throws = true, } = { __proto__: null, ...options };
|
|
1178
|
-
try {
|
|
1179
|
-
// Route to appropriate HTTP method handler (POST or PUT).
|
|
1180
|
-
const response = await (0, http_client_1.createRequestWithJson)(method, this.#baseUrl, urlPath, body, this.#reqOptions);
|
|
1181
|
-
const data = (await (0, http_client_1.getResponseJson)(response));
|
|
1182
|
-
if (throws) {
|
|
1183
|
-
return data;
|
|
1184
|
-
}
|
|
1185
|
-
return {
|
|
1186
|
-
cause: undefined,
|
|
1187
|
-
data,
|
|
1188
|
-
error: undefined,
|
|
1189
|
-
/* c8 ignore next - Defensive fallback: response.statusCode is always defined in Node.js http/https */
|
|
1190
|
-
status: response.statusCode ?? 200,
|
|
1191
|
-
success: true,
|
|
1192
|
-
};
|
|
1193
|
-
}
|
|
1194
|
-
catch (e) {
|
|
1195
|
-
if (throws) {
|
|
1196
|
-
throw e;
|
|
1197
|
-
}
|
|
1198
|
-
/* c8 ignore start - Defensive fallback: ResponseError in catch block handled in try block (lines 1686-1695) */
|
|
1199
|
-
if (e instanceof http_client_1.ResponseError) {
|
|
1200
|
-
// Re-use existing error handling logic from the SDK
|
|
1201
|
-
const errorResult = await this.#handleApiError(e);
|
|
1202
|
-
return {
|
|
1203
|
-
cause: errorResult.cause,
|
|
1204
|
-
data: undefined,
|
|
1205
|
-
error: errorResult.error,
|
|
1206
|
-
status: errorResult.status,
|
|
1207
|
-
success: false,
|
|
1208
|
-
};
|
|
1209
|
-
}
|
|
1210
|
-
/* c8 ignore stop */
|
|
1211
|
-
/* c8 ignore start - Defensive error stringification fallback branches for sendApi edge cases. */
|
|
1212
|
-
const errStr = e ? String(e).trim() : '';
|
|
1213
|
-
return {
|
|
1214
|
-
cause: errStr || UNKNOWN_ERROR_1.default,
|
|
1215
|
-
data: undefined,
|
|
1216
|
-
error: 'API request failed',
|
|
1217
|
-
status: 0,
|
|
1218
|
-
success: false,
|
|
1219
|
-
};
|
|
1220
|
-
/* c8 ignore stop */
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
|
-
/**
|
|
1224
|
-
* Stream a full scan's results to file or stdout.* Provides efficient streaming for large scan datasets.
|
|
1225
|
-
*
|
|
1226
|
-
* @throws {Error} When server returns 5xx status codes
|
|
1227
|
-
*/
|
|
1228
|
-
async streamOrgFullScan(orgSlug, fullScanId, options) {
|
|
1229
|
-
const { output } = {
|
|
1230
|
-
__proto__: null,
|
|
1231
|
-
...options,
|
|
1232
|
-
};
|
|
1233
|
-
try {
|
|
1234
|
-
const req = (0, http_client_1.getHttpModule)(this.#baseUrl)
|
|
1235
|
-
.request(`${this.#baseUrl}orgs/${encodeURIComponent(orgSlug)}/full-scans/${encodeURIComponent(fullScanId)}`, {
|
|
1236
|
-
method: 'GET',
|
|
1237
|
-
...this.#reqOptions,
|
|
1238
|
-
})
|
|
1239
|
-
.end();
|
|
1240
|
-
const res = await (0, http_client_1.getResponse)(req);
|
|
1241
|
-
// Check for HTTP error status codes.
|
|
1242
|
-
if (!(0, http_client_1.isResponseOk)(res)) {
|
|
1243
|
-
throw new http_client_1.ResponseError(res);
|
|
1244
|
-
}
|
|
1245
|
-
if (typeof output === 'string') {
|
|
1246
|
-
// Stream to file with error handling.
|
|
1247
|
-
const writeStream = (0, node_fs_1.createWriteStream)(output);
|
|
1248
|
-
res.pipe(writeStream);
|
|
1249
|
-
/* c8 ignore next 4 - Write stream error handler, difficult to test reliably */
|
|
1250
|
-
writeStream.on('error', error => {
|
|
1251
|
-
throw new Error(`Failed to write to file: ${output}`, {
|
|
1252
|
-
cause: error,
|
|
1253
|
-
});
|
|
1254
|
-
});
|
|
1255
|
-
}
|
|
1256
|
-
else if (output === true) {
|
|
1257
|
-
// Stream to stdout with error handling.
|
|
1258
|
-
res.pipe(process.stdout);
|
|
1259
|
-
/* c8 ignore next 3 - Stdout error handler, difficult to test reliably */
|
|
1260
|
-
process.stdout.on('error', error => {
|
|
1261
|
-
throw new Error('Failed to write to stdout', { cause: error });
|
|
1262
|
-
});
|
|
1331
|
+
} else if (output === true) {
|
|
1332
|
+
// Stream to stdout with error handling.
|
|
1333
|
+
res.pipe(process.stdout);
|
|
1334
|
+
/* c8 ignore next 3 - Stdout error handler, difficult to test reliably */
|
|
1335
|
+
process.stdout.on('error', error => {
|
|
1336
|
+
throw new Error('Failed to write to stdout', {
|
|
1337
|
+
cause: error
|
|
1338
|
+
});
|
|
1339
|
+
});
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
// If output is false or undefined, just return the response without streaming
|
|
1343
|
+
return this.#handleApiSuccess(res);
|
|
1344
|
+
} catch (e) {
|
|
1345
|
+
return await this.#handleApiError(e);
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
/**
|
|
1350
|
+
* Stream patches for artifacts in a scan report.
|
|
1351
|
+
*
|
|
1352
|
+
* This method streams all available patches for artifacts in a scan.
|
|
1353
|
+
* Free tier users will only receive free patches.
|
|
1354
|
+
*
|
|
1355
|
+
* Note: This method returns a ReadableStream for processing large datasets.
|
|
1356
|
+
*/
|
|
1357
|
+
async streamPatchesFromScan(orgSlug, scanId) {
|
|
1358
|
+
const response = await this.#executeWithRetry(async () => await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/patches/scan/${encodeURIComponent(scanId)}`, this.#reqOptions));
|
|
1359
|
+
|
|
1360
|
+
// Check for HTTP error status codes.
|
|
1361
|
+
if (!httpClient.isResponseOk(response)) {
|
|
1362
|
+
throw new httpClient.ResponseError(response, 'GET Request failed');
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
// The response itself is the readable stream for NDJSON data
|
|
1366
|
+
// Convert the Node.js readable stream to a Web ReadableStream
|
|
1367
|
+
return new ReadableStream({
|
|
1368
|
+
start(controller) {
|
|
1369
|
+
response.on('data', chunk => {
|
|
1370
|
+
// Parse NDJSON chunks line by line
|
|
1371
|
+
const lines = chunk.toString().split('\n').filter(line => line.trim());
|
|
1372
|
+
for (const line of lines) {
|
|
1373
|
+
try {
|
|
1374
|
+
const data = JSON.parse(line);
|
|
1375
|
+
controller.enqueue(data);
|
|
1376
|
+
} catch (e) {
|
|
1377
|
+
// Log parse errors for debugging invalid NDJSON lines.
|
|
1378
|
+
debug.debugLog('streamPatchesFromScan', `Failed to parse line: ${e}`);
|
|
1263
1379
|
}
|
|
1264
|
-
|
|
1265
|
-
return this.#handleApiSuccess(res);
|
|
1266
|
-
}
|
|
1267
|
-
catch (e) {
|
|
1268
|
-
return await this.#handleApiError(e);
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
/**
|
|
1272
|
-
* Stream patches for artifacts in a scan report.
|
|
1273
|
-
*
|
|
1274
|
-
* This method streams all available patches for artifacts in a scan.
|
|
1275
|
-
* Free tier users will only receive free patches.
|
|
1276
|
-
*
|
|
1277
|
-
* Note: This method returns a ReadableStream for processing large datasets.
|
|
1278
|
-
*/
|
|
1279
|
-
async streamPatchesFromScan(orgSlug, scanId) {
|
|
1280
|
-
const response = await this.#executeWithRetry(async () => await (0, http_client_1.createGetRequest)(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/patches/scan/${encodeURIComponent(scanId)}`, this.#reqOptions));
|
|
1281
|
-
// Check for HTTP error status codes.
|
|
1282
|
-
if (!(0, http_client_1.isResponseOk)(response)) {
|
|
1283
|
-
throw new http_client_1.ResponseError(response, 'GET Request failed');
|
|
1284
|
-
}
|
|
1285
|
-
// The response itself is the readable stream for NDJSON data
|
|
1286
|
-
// Convert the Node.js readable stream to a Web ReadableStream
|
|
1287
|
-
return new ReadableStream({
|
|
1288
|
-
start(controller) {
|
|
1289
|
-
response.on('data', (chunk) => {
|
|
1290
|
-
// Parse NDJSON chunks line by line
|
|
1291
|
-
const lines = chunk
|
|
1292
|
-
.toString()
|
|
1293
|
-
.split('\n')
|
|
1294
|
-
.filter(line => line.trim());
|
|
1295
|
-
for (const line of lines) {
|
|
1296
|
-
try {
|
|
1297
|
-
const data = JSON.parse(line);
|
|
1298
|
-
controller.enqueue(data);
|
|
1299
|
-
}
|
|
1300
|
-
catch (e) {
|
|
1301
|
-
// Log parse errors for debugging invalid NDJSON lines.
|
|
1302
|
-
(0, debug_1.debugLog)('streamPatchesFromScan', `Failed to parse line: ${e}`);
|
|
1303
|
-
}
|
|
1304
|
-
}
|
|
1305
|
-
});
|
|
1306
|
-
response.on('end', () => {
|
|
1307
|
-
controller.close();
|
|
1308
|
-
});
|
|
1309
|
-
response.on('error', error => {
|
|
1310
|
-
/* c8 ignore next - Streaming error handler, difficult to test reliably. */
|
|
1311
|
-
controller.error(error);
|
|
1312
|
-
});
|
|
1313
|
-
},
|
|
1380
|
+
}
|
|
1314
1381
|
});
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
}
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
}
|
|
1382
|
+
response.on('end', () => {
|
|
1383
|
+
controller.close();
|
|
1384
|
+
});
|
|
1385
|
+
response.on('error', error => {
|
|
1386
|
+
/* c8 ignore next - Streaming error handler, difficult to test reliably. */
|
|
1387
|
+
controller.error(error);
|
|
1388
|
+
});
|
|
1389
|
+
}
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
/**
|
|
1394
|
+
* Update alert triage status for an organization.
|
|
1395
|
+
* Modifies alert resolution status and triage decisions.
|
|
1396
|
+
*
|
|
1397
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1398
|
+
*/
|
|
1399
|
+
async updateOrgAlertTriage(orgSlug, alertId, triageData) {
|
|
1400
|
+
try {
|
|
1401
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('PUT', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/triage/${encodeURIComponent(alertId)}`, triageData, this.#reqOptions)));
|
|
1402
|
+
return this.#handleApiSuccess(data);
|
|
1403
|
+
} catch (e) {
|
|
1404
|
+
return await this.#handleApiError(e);
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
/**
|
|
1409
|
+
* Update organization's license policy configuration.* Modifies allowed, restricted, and monitored license types.
|
|
1410
|
+
*
|
|
1411
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1412
|
+
*/
|
|
1413
|
+
async updateOrgLicensePolicy(orgSlug, policyData, queryParams) {
|
|
1414
|
+
try {
|
|
1415
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/settings/license-policy?${utils.queryToSearchParams(queryParams)}`, policyData, this.#reqOptions)));
|
|
1416
|
+
return this.#handleApiSuccess(data);
|
|
1417
|
+
} catch (e) {
|
|
1418
|
+
return await this.#handleApiError(e);
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
/**
|
|
1423
|
+
* Update configuration for an organization repository.
|
|
1424
|
+
* Modifies monitoring settings, branch configuration, and scan preferences.
|
|
1425
|
+
*
|
|
1426
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1427
|
+
*/
|
|
1428
|
+
async updateOrgRepo(orgSlug, repoSlug, queryParams) {
|
|
1429
|
+
try {
|
|
1430
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}`, queryParams, this.#reqOptions)));
|
|
1431
|
+
return this.#handleApiSuccess(data);
|
|
1432
|
+
} catch (e) {
|
|
1433
|
+
return await this.#handleApiError(e);
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
/**
|
|
1438
|
+
* Update a repository label for an organization.
|
|
1439
|
+
* Modifies label properties and configuration.
|
|
1440
|
+
*
|
|
1441
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1442
|
+
*/
|
|
1443
|
+
async updateOrgRepoLabel(orgSlug, repoSlug, labelSlug, labelData) {
|
|
1444
|
+
try {
|
|
1445
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('PUT', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/repos/${encodeURIComponent(repoSlug)}/labels/${encodeURIComponent(labelSlug)}`, labelData, this.#reqOptions)));
|
|
1446
|
+
return this.#handleApiSuccess(data);
|
|
1447
|
+
} catch (e) {
|
|
1448
|
+
return await this.#handleApiError(e);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
/**
|
|
1453
|
+
* Update organization's security policy configuration.* Modifies alert rules, severity thresholds, and enforcement settings.
|
|
1454
|
+
*
|
|
1455
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1456
|
+
*/
|
|
1457
|
+
async updateOrgSecurityPolicy(orgSlug, policyData) {
|
|
1458
|
+
try {
|
|
1459
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await httpClient.createRequestWithJson('POST', this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/settings/security-policy`, policyData, this.#reqOptions)));
|
|
1460
|
+
return this.#handleApiSuccess(data);
|
|
1461
|
+
} catch (e) {
|
|
1462
|
+
return await this.#handleApiError(e);
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
/**
|
|
1467
|
+
* Upload manifest files for dependency analysis.
|
|
1468
|
+
* Processes package files to create dependency snapshots and security analysis.
|
|
1469
|
+
*
|
|
1470
|
+
* @throws {Error} When server returns 5xx status codes
|
|
1471
|
+
*/
|
|
1472
|
+
async uploadManifestFiles(orgSlug, filepaths, options) {
|
|
1473
|
+
const {
|
|
1474
|
+
pathsRelativeTo = '.'
|
|
1475
|
+
} = {
|
|
1476
|
+
__proto__: null,
|
|
1477
|
+
...options
|
|
1478
|
+
};
|
|
1479
|
+
const basePath = utils.resolveBasePath(pathsRelativeTo);
|
|
1480
|
+
const absFilepaths = utils.resolveAbsPaths(filepaths, basePath);
|
|
1481
|
+
try {
|
|
1482
|
+
const data = await this.#executeWithRetry(async () => await httpClient.getResponseJson(await fileUpload.createUploadRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/upload-manifest-files`, fileUpload.createRequestBodyForFilepaths(absFilepaths, basePath), this.#reqOptions)));
|
|
1483
|
+
return this.#handleApiSuccess(data);
|
|
1484
|
+
} catch (e) {
|
|
1485
|
+
/* c8 ignore start - Error handling in uploadManifestFiles method for edge cases. */
|
|
1486
|
+
return await this.#handleApiError(e);
|
|
1487
|
+
/* c8 ignore stop */
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
/**
|
|
1492
|
+
* View detailed information about a specific patch by its UUID.
|
|
1493
|
+
*
|
|
1494
|
+
* This method retrieves comprehensive patch details including files,
|
|
1495
|
+
* vulnerabilities, description, license, and tier information.
|
|
1496
|
+
*/
|
|
1497
|
+
async viewPatch(orgSlug, uuid) {
|
|
1498
|
+
const data = await httpClient.getResponseJson(await httpClient.createGetRequest(this.#baseUrl, `orgs/${encodeURIComponent(orgSlug)}/patches/view/${encodeURIComponent(uuid)}`, this.#reqOptions));
|
|
1499
|
+
return data;
|
|
1500
|
+
}
|
|
1422
1501
|
}
|
|
1423
|
-
|
|
1502
|
+
|
|
1424
1503
|
// Optional live heap trace.
|
|
1425
1504
|
/* c8 ignore start - optional debug logging for heap monitoring */
|
|
1426
|
-
if (
|
|
1427
|
-
|
|
1428
|
-
|
|
1505
|
+
if (debug.isDebugNs('heap')) {
|
|
1506
|
+
const used = process.memoryUsage();
|
|
1507
|
+
debug.debugLog('heap', `heap used: ${Math.round(used.heapUsed / 1024 / 1024)}MB`);
|
|
1429
1508
|
}
|
|
1430
1509
|
/* c8 ignore stop - end debug logging */
|
|
1510
|
+
|
|
1511
|
+
exports.SocketSdk = SocketSdk;
|