diff --git a/src/commands/analytics/fetch-org-analytics.mts b/src/commands/analytics/fetch-org-analytics.mts index c63013b2..34419d07 100644 --- a/src/commands/analytics/fetch-org-analytics.mts +++ b/src/commands/analytics/fetch-org-analytics.mts @@ -1,5 +1,4 @@ -import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -10,32 +9,8 @@ export async function fetchOrgAnalyticsData( ): Promise['data']>> { const sockSdk = await setupSdk() - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start(`Requesting analytics data from API...`) - - const result = await handleApiCall( + return await handleApiCall( sockSdk.getOrgAnalytics(time.toString()), - 'fetching analytics data' + 'analytics data' ) - - spinner.successAndStop(`Received API response.`) - - if (result.success === false) { - return handleFailedApiResponse('getOrgAnalytics', result) - } - - if (!result.data.length) { - return { - ok: true, - message: 'No analytics data is available for this organization yet.', - data: [] - } - } - - return { - ok: true, - data: result.data - } } diff --git a/src/commands/analytics/fetch-repo-analytics.mts b/src/commands/analytics/fetch-repo-analytics.mts index bd533e3b..af1a9c48 100644 --- a/src/commands/analytics/fetch-repo-analytics.mts +++ b/src/commands/analytics/fetch-repo-analytics.mts @@ -1,5 +1,4 @@ -import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -11,32 +10,8 @@ export async function fetchRepoAnalyticsData( ): Promise['data']>> { const sockSdk = await setupSdk() - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start(`Requesting analytics data from API...`) - - const result = await handleApiCall( + return await handleApiCall( sockSdk.getRepoAnalytics(repo, time.toString()), - 'fetching analytics data' + 'analytics data' ) - - spinner.successAndStop(`Received API response.`) - - if (result.success === false) { - return handleFailedApiResponse('getRepoAnalytics', result) - } - - if (!result.data.length) { - return { - ok: true, - message: 'No analytics data is available for this repository yet.', - data: [] - } - } - - return { - ok: true, - data: result.data - } } diff --git a/src/commands/analytics/handle-analytics.mts b/src/commands/analytics/handle-analytics.mts index 8bfa0e3c..b053e499 100644 --- a/src/commands/analytics/handle-analytics.mts +++ b/src/commands/analytics/handle-analytics.mts @@ -32,6 +32,13 @@ export async function handleAnalytics({ message: 'Missing repository name in command' } } + if (result.ok && !result.data.length) { + result = { + ok: true, + message: `The analytics data for this ${scope === 'org' ? 'organization' : 'repository'} is not yet available.`, + data: [] + } + } await outputAnalytics(result, { filePath, diff --git a/src/commands/audit-log/fetch-audit-log.mts b/src/commands/audit-log/fetch-audit-log.mts index 6a971f9d..eef66424 100644 --- a/src/commands/audit-log/fetch-audit-log.mts +++ b/src/commands/audit-log/fetch-audit-log.mts @@ -1,5 +1,4 @@ -import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult, OutputKind } from '../../types.mts' @@ -20,12 +19,7 @@ export async function fetchAuditLog({ }): Promise['data']>> { const sockSdk = await setupSdk() - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start(`Looking up audit log for ${orgSlug}`) - - const result = await handleApiCall( + return await handleApiCall( sockSdk.getAuditLogEvents(orgSlug, { // I'm not sure this is used at all. outputJson: String(outputKind === 'json'), @@ -36,17 +30,6 @@ export async function fetchAuditLog({ page: String(page), per_page: String(perPage) }), - `Looking up audit log for ${orgSlug}\n` + `audit log for ${orgSlug}` ) - - spinner.successAndStop(`Received API response.`) - - if (!result.success) { - return handleFailedApiResponse('getAuditLogEvents', result) - } - - return { - ok: true, - data: result.data - } } diff --git a/src/commands/ci/fetch-default-org-slug.mts b/src/commands/ci/fetch-default-org-slug.mts index 62195147..8af7ded0 100644 --- a/src/commands/ci/fetch-default-org-slug.mts +++ b/src/commands/ci/fetch-default-org-slug.mts @@ -1,36 +1,29 @@ import { debugLog } from '@socketsecurity/registry/lib/debug' import { handleApiCall } from '../../utils/api.mts' -import { getConfigValue } from '../../utils/config.mts' +import { getConfigValueOrUndef } from '../../utils/config.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' // Use the config defaultOrg when set, otherwise discover from remote export async function getDefaultOrgSlug(): Promise> { - const defaultOrgResult = getConfigValue('defaultOrg') - if (!defaultOrgResult.ok) { - return defaultOrgResult - } + const defaultOrgResult = getConfigValueOrUndef('defaultOrg') - if (defaultOrgResult.data) { - debugLog(`Using default org: ${defaultOrgResult.data}`) - return { ok: true, data: defaultOrgResult.data } + if (defaultOrgResult) { + debugLog(`Using default org: ${defaultOrgResult}`) + return { ok: true, data: defaultOrgResult } } const sockSdk = await setupSdk() const result = await handleApiCall( sockSdk.getOrganizations(), - 'looking up organizations' + 'list of organizations' ) - if (!result.success) { - return { - ok: false, - message: result.error, - data: `Failed to fetch default organization from API. Unable to continue.${result.cause ? ` ( Reason given: ${result.cause} )` : ''}` - } + if (!result.ok) { + return result } const orgs = result.data.organizations diff --git a/src/commands/config/discover-config-value.mts b/src/commands/config/discover-config-value.mts index d3f3f50f..d875ffa8 100644 --- a/src/commands/config/discover-config-value.mts +++ b/src/commands/config/discover-config-value.mts @@ -133,10 +133,10 @@ async function getDefaultOrgFromToken(): Promise< const result = await handleApiCall( sockSdk.getOrganizations(), - 'looking up organizations' + 'list of organizations' ) - if (result.success) { + if (result.ok) { const arr = Array.from(Object.values(result.data.organizations)).map( ({ slug }) => slug ) @@ -157,10 +157,10 @@ async function getEnforceableOrgsFromToken(): Promise { const result = await handleApiCall( sockSdk.getOrganizations(), - 'looking up organizations' + 'list of organizations' ) - if (result.success) { + if (result.ok) { const arr = Array.from(Object.values(result.data.organizations)).map( ({ slug }) => slug ) diff --git a/src/commands/dependencies/fetch-dependencies.mts b/src/commands/dependencies/fetch-dependencies.mts index 8972e443..99ea1458 100644 --- a/src/commands/dependencies/fetch-dependencies.mts +++ b/src/commands/dependencies/fetch-dependencies.mts @@ -1,5 +1,4 @@ -import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -14,21 +13,8 @@ export async function fetchDependencies({ }): Promise['data']>> { const sockSdk = await setupSdk() - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start('Fetching organization dependencies...') - - const result = await handleApiCall( + return await handleApiCall( sockSdk.searchDependencies({ limit, offset }), - 'Searching dependencies' + 'organization dependencies' ) - - spinner.successAndStop('Received organization dependencies response.') - - if (!result.success) { - return handleFailedApiResponse('searchDependencies', result) - } - - return { ok: true, data: result.data } } diff --git a/src/commands/diff-scan/fetch-diff-scan.mts b/src/commands/diff-scan/fetch-diff-scan.mts index db1e460d..90612da1 100644 --- a/src/commands/diff-scan/fetch-diff-scan.mts +++ b/src/commands/diff-scan/fetch-diff-scan.mts @@ -1,5 +1,5 @@ import constants from '../../constants.mts' -import { handleApiCall, handleApiError, queryApi } from '../../utils/api.mts' +import { handleApiError, queryApi } from '../../utils/api.mts' import { getDefaultToken } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -37,12 +37,8 @@ export async function fetchDiffScan({ } } - const result = await handleApiCall( - (await response.json()) as Promise< - SocketSdkReturnType<'GetOrgDiffScan'>['data'] - >, - 'Deserializing json' - ) + const result = + (await response.json()) as SocketSdkReturnType<'GetOrgDiffScan'>['data'] return { ok: true, data: result } } diff --git a/src/commands/info/fetch-package-info.mts b/src/commands/info/fetch-package-info.mts index 1f4f9450..388d2cb2 100644 --- a/src/commands/info/fetch-package-info.mts +++ b/src/commands/info/fetch-package-info.mts @@ -1,4 +1,3 @@ -import constants from '../../constants.mts' import { getSeverityCount } from '../../utils/alert/severity.mts' import { handleApiCall, @@ -15,32 +14,31 @@ export async function fetchPackageInfo( ): Promise { const sockSdk = await setupSdk(getPublicToken()) - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start( - pkgVersion === 'latest' - ? `Looking up data for the latest version of ${pkgName}` - : `Looking up data for version ${pkgVersion} of ${pkgName}` - ) - const result = await handleApiCall( sockSdk.getIssuesByNPMPackage(pkgName, pkgVersion), - 'looking up package' + 'package issues' ) const scoreResult = await handleApiCall( sockSdk.getScoreByNPMPackage(pkgName, pkgVersion), - 'looking up package score' + 'package score' ) - spinner.successAndStop('Data fetched') - - if (result.success === false) { - handleUnsuccessfulApiResponse('getIssuesByNPMPackage', result) + if (!result.ok) { + handleUnsuccessfulApiResponse( + 'getIssuesByNPMPackage', + result.message, + result.cause ?? '', + (result.data as any)?.code ?? 0 + ) } - if (scoreResult.success === false) { - handleUnsuccessfulApiResponse('getScoreByNPMPackage', scoreResult) + if (!scoreResult.ok) { + handleUnsuccessfulApiResponse( + 'getScoreByNPMPackage', + scoreResult.message, + scoreResult.cause ?? '', + (scoreResult.data as any)?.code ?? 0 + ) } const severityCount = getSeverityCount( diff --git a/src/commands/login/attempt-login.mts b/src/commands/login/attempt-login.mts index 3a07e277..cd9ae9c5 100644 --- a/src/commands/login/attempt-login.mts +++ b/src/commands/login/attempt-login.mts @@ -5,8 +5,9 @@ import { confirm, password, select } from '@socketsecurity/registry/lib/prompts' import { applyLogin } from './apply-login.mts' import constants from '../../constants.mts' -import { handleUnsuccessfulApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { getConfigValueOrUndef, isReadOnlyConfig } from '../../utils/config.mts' +import { failMsgWithBadge } from '../../utils/fail-msg-with-badge.mts' import { setupSdk } from '../../utils/sdk.mts' import type { Choice, Separator } from '@socketsecurity/registry/lib/prompts' @@ -29,20 +30,17 @@ export async function attemptLogin( 'https://docs.socket.dev/docs/api-keys' )} (leave blank for a public key)` })) || SOCKET_PUBLIC_API_TOKEN - // Lazily access constants.spinner. - const { spinner } = constants const sdk = await setupSdk(apiToken, apiBaseUrl, apiProxy) - spinner.start('Verifying API key...') + const result = await handleApiCall( + sdk.getOrganizations(), + 'token verification' + ) - const result = await sdk.getOrganizations() - - spinner.successAndStop('Received response') - - if (!result.success) { - logger.fail('Authentication failed...') - handleUnsuccessfulApiResponse('getOrganizations', result) + if (!result.ok) { + logger.fail(failMsgWithBadge(result.message, result.cause)) + return } logger.success('API key verified') @@ -84,8 +82,6 @@ export async function attemptLogin( } } - spinner.stop() - const previousPersistedToken = getConfigValueOrUndef('apiToken') try { applyLogin(apiToken, enforcedOrgs, apiBaseUrl, apiProxy) diff --git a/src/commands/organization/fetch-license-policy.mts b/src/commands/organization/fetch-license-policy.mts index 2f0f4420..e284951e 100644 --- a/src/commands/organization/fetch-license-policy.mts +++ b/src/commands/organization/fetch-license-policy.mts @@ -1,5 +1,4 @@ -import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -10,21 +9,8 @@ export async function fetchLicensePolicy( ): Promise['data']>> { const sockSdk = await setupSdk() - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start('Fetching organization license policy...') - - const result = await handleApiCall( + return await handleApiCall( sockSdk.getOrgLicensePolicy(orgSlug), - 'looking up organization quota' + 'organization license policy' ) - - spinner.successAndStop('Received organization license policy response.') - - if (!result.success) { - return handleFailedApiResponse('getOrgLicensePolicy', result) - } - - return { ok: true, data: result.data } } diff --git a/src/commands/organization/fetch-organization-list.mts b/src/commands/organization/fetch-organization-list.mts index 1c3e4e7a..0813428d 100644 --- a/src/commands/organization/fetch-organization-list.mts +++ b/src/commands/organization/fetch-organization-list.mts @@ -1,5 +1,4 @@ -import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -10,21 +9,5 @@ export async function fetchOrganization(): Promise< > { const sockSdk = await setupSdk() - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start('Fetching organization list...') - - const result = await handleApiCall( - sockSdk.getOrganizations(), - 'looking up organizations' - ) - - spinner.successAndStop('Received organization list response.') - - if (!result.success) { - return handleFailedApiResponse('getOrganizations', result) - } - - return { ok: true, data: result.data } + return await handleApiCall(sockSdk.getOrganizations(), 'organization list') } diff --git a/src/commands/organization/fetch-quota.mts b/src/commands/organization/fetch-quota.mts index 5ae2ba1d..2270653c 100644 --- a/src/commands/organization/fetch-quota.mts +++ b/src/commands/organization/fetch-quota.mts @@ -1,5 +1,4 @@ -import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -10,21 +9,5 @@ export async function fetchQuota(): Promise< > { const sockSdk = await setupSdk() - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start('Fetching organization quota...') - - const result = await handleApiCall( - sockSdk.getQuota(), - 'looking up organization quota' - ) - - spinner.successAndStop('Received organization quota response.') - - if (!result.success) { - return handleFailedApiResponse('getQuota', result) - } - - return { ok: true, data: result.data } + return await handleApiCall(sockSdk.getQuota(), 'token quota') } diff --git a/src/commands/organization/fetch-security-policy.mts b/src/commands/organization/fetch-security-policy.mts index cd97f8cb..f695ea22 100644 --- a/src/commands/organization/fetch-security-policy.mts +++ b/src/commands/organization/fetch-security-policy.mts @@ -1,5 +1,4 @@ -import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -10,21 +9,8 @@ export async function fetchSecurityPolicy( ): Promise['data']>> { const sockSdk = await setupSdk() - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start('Fetching organization security policy...') - - const result = await handleApiCall( + return await handleApiCall( sockSdk.getOrgSecurityPolicy(orgSlug), - 'looking up organization quota' + 'organization security policy' ) - - spinner.successAndStop('Received organization security policy response.') - - if (!result.success) { - return handleFailedApiResponse('getOrgSecurityPolicy', result) - } - - return { ok: true, data: result.data } } diff --git a/src/commands/package/fetch-purl-deep-score.mts b/src/commands/package/fetch-purl-deep-score.mts index 7b5f18ed..e80c5377 100644 --- a/src/commands/package/fetch-purl-deep-score.mts +++ b/src/commands/package/fetch-purl-deep-score.mts @@ -1,7 +1,7 @@ import { logger } from '@socketsecurity/registry/lib/logger' import constants from '../../constants.mts' -import { handleApiCall, handleApiError, queryApi } from '../../utils/api.mts' +import { handleApiError, queryApi } from '../../utils/api.mts' import { getDefaultToken } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -100,10 +100,13 @@ export async function fetchPurlDeepScore( } } - const data = await handleApiCall(await result.text(), 'Reading text') + const data = await result.text() try { - return { ok: true, data: JSON.parse(data) } + return { + ok: true, + data: JSON.parse(data) // as PurlDataResponse + } } catch (e) { return { ok: false, diff --git a/src/commands/package/fetch-purls-shallow-score.mts b/src/commands/package/fetch-purls-shallow-score.mts index 91a26ea7..6684d25b 100644 --- a/src/commands/package/fetch-purls-shallow-score.mts +++ b/src/commands/package/fetch-purls-shallow-score.mts @@ -1,7 +1,10 @@ import { logger } from '@socketsecurity/registry/lib/logger' import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { + handleFailedApiResponse, + tmpHandleApiCall as oldHandleApiCall +} from '../../utils/api.mts' import { getPublicToken, setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -24,8 +27,8 @@ export async function fetchPurlsShallowScore( spinner.start(`Requesting data ...`) - const result: Awaited> = - await handleApiCall( + const result: SocketSdkResultType<'batchPackageFetch'> = + await oldHandleApiCall( sockSdk.batchPackageFetch( { alerts: 'true' diff --git a/src/commands/repos/fetch-create-repo.mts b/src/commands/repos/fetch-create-repo.mts index beccb574..1da34d6f 100644 --- a/src/commands/repos/fetch-create-repo.mts +++ b/src/commands/repos/fetch-create-repo.mts @@ -1,5 +1,4 @@ -import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -22,12 +21,7 @@ export async function fetchCreateRepo({ }): Promise['data']>> { const sockSdk = await setupSdk() - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start('Sending request ot create a repository...') - - const result = await handleApiCall( + return await handleApiCall( sockSdk.createOrgRepo(orgSlug, { name: repoName, description, @@ -35,14 +29,6 @@ export async function fetchCreateRepo({ default_branch, visibility }), - 'creating repository' + 'to create a repository' ) - - spinner.successAndStop('Received response requesting to create a repository.') - - if (!result.success) { - return handleFailedApiResponse('createOrgRepo', result) - } - - return { ok: true, data: result.data } } diff --git a/src/commands/repos/fetch-delete-repo.mts b/src/commands/repos/fetch-delete-repo.mts index 0565ab4f..1f1b1f10 100644 --- a/src/commands/repos/fetch-delete-repo.mts +++ b/src/commands/repos/fetch-delete-repo.mts @@ -1,5 +1,4 @@ -import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -11,21 +10,8 @@ export async function fetchDeleteRepo( ): Promise['data']>> { const sockSdk = await setupSdk() - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start('Sending request to delete a repository...') - - const result = await handleApiCall( + return await handleApiCall( sockSdk.deleteOrgRepo(orgSlug, repoName), - 'deleting repository' + 'to delete a repository' ) - - spinner.successAndStop('Received response requesting to delete a repository.') - - if (!result.success) { - return handleFailedApiResponse('deleteOrgRepo', result) - } - - return { ok: true, data: result.data } } diff --git a/src/commands/repos/fetch-list-repos.mts b/src/commands/repos/fetch-list-repos.mts index 726ba095..39b52d94 100644 --- a/src/commands/repos/fetch-list-repos.mts +++ b/src/commands/repos/fetch-list-repos.mts @@ -1,5 +1,4 @@ -import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -20,26 +19,13 @@ export async function fetchListRepos({ }): Promise['data']>> { const sockSdk = await setupSdk() - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start('Fetching list of repositories...') - - const result = await handleApiCall( + return await handleApiCall( sockSdk.getOrgRepoList(orgSlug, { sort, direction, per_page: String(per_page), page: String(page) }), - 'listing repositories' + 'list of repositories' ) - - spinner.successAndStop('Received response for repository list.') - - if (!result.success) { - return handleFailedApiResponse('getOrgRepoList', result) - } - - return { ok: true, data: result.data } } diff --git a/src/commands/repos/fetch-update-repo.mts b/src/commands/repos/fetch-update-repo.mts index 8b51cd3d..08e1be24 100644 --- a/src/commands/repos/fetch-update-repo.mts +++ b/src/commands/repos/fetch-update-repo.mts @@ -1,5 +1,4 @@ -import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -22,12 +21,7 @@ export async function fetchUpdateRepo({ }): Promise['data']>> { const sockSdk = await setupSdk() - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start('Sending request to update a repository...') - - const result = await handleApiCall( + return await handleApiCall( sockSdk.updateOrgRepo(orgSlug, repoName, { orgSlug, name: repoName, @@ -36,14 +30,6 @@ export async function fetchUpdateRepo({ default_branch, visibility }), - 'updating repository' + 'to update a repository' ) - - spinner.successAndStop('Received response trying to update a repository') - - if (!result.success) { - return handleFailedApiResponse('updateOrgRepo', result) - } - - return { ok: true, data: result.data } } diff --git a/src/commands/repos/fetch-view-repo.mts b/src/commands/repos/fetch-view-repo.mts index 5322c3b6..f6b1f4a9 100644 --- a/src/commands/repos/fetch-view-repo.mts +++ b/src/commands/repos/fetch-view-repo.mts @@ -1,5 +1,4 @@ -import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -11,21 +10,8 @@ export async function fetchViewRepo( ): Promise['data']>> { const sockSdk = await setupSdk() - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start('Fetching repository data...') - - const result = await handleApiCall( + return await handleApiCall( sockSdk.getOrgRepo(orgSlug, repoName), - 'fetching repository' + 'repository data' ) - - spinner.successAndStop('Received response while fetched repository data.') - - if (!result.success) { - return handleFailedApiResponse('getOrgRepo', result) - } - - return { ok: true, data: result.data } } diff --git a/src/commands/scan/cmd-scan-diff.mts b/src/commands/scan/cmd-scan-diff.mts index 3ecad2fb..b4af6d13 100644 --- a/src/commands/scan/cmd-scan-diff.mts +++ b/src/commands/scan/cmd-scan-diff.mts @@ -103,15 +103,15 @@ async function run( } = cli.flags const outputKind = getOutputKind(json, markdown) - const [orgSlug, defaultOrgSlug] = await determineOrgSlug( + const [orgSlug] = await determineOrgSlug( String(orgFlag || ''), cli.input[0] || '', !!interactive, !!dryRun ) - let id1 = cli.input[defaultOrgSlug ? 0 : 1] || '' - let id2 = cli.input[defaultOrgSlug ? 1 : 2] || '' + let id1 = cli.input[isTestingV1() || orgSlug ? 0 : 1] || '' + let id2 = cli.input[isTestingV1() || orgSlug ? 1 : 2] || '' if (id1.startsWith(SOCKET_SBOM_URL_PREFIX)) { id1 = id1.slice(SOCKET_SBOM_URL_PREFIX.length) } diff --git a/src/commands/scan/fetch-create-org-full-scan.mts b/src/commands/scan/fetch-create-org-full-scan.mts index bc5d1184..82a79c17 100644 --- a/src/commands/scan/fetch-create-org-full-scan.mts +++ b/src/commands/scan/fetch-create-org-full-scan.mts @@ -1,5 +1,4 @@ -import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -30,14 +29,7 @@ export async function fetchCreateOrgFullScan( ): Promise['data']>> { const sockSdk = await setupSdk() - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start( - `Sending request to create a scan with ${packagePaths.length} packages...` - ) - - const result = await handleApiCall( + return await handleApiCall( sockSdk.createOrgFullScan( orgSlug, { @@ -54,14 +46,6 @@ export async function fetchCreateOrgFullScan( packagePaths, cwd ), - 'Creating scan' + 'to create a scan' ) - - spinner.successAndStop('Completed request to create a new scan.') - - if (!result.success) { - return handleFailedApiResponse('CreateOrgFullScan', result) - } - - return { ok: true, data: result.data } } diff --git a/src/commands/scan/fetch-delete-org-full-scan.mts b/src/commands/scan/fetch-delete-org-full-scan.mts index 801f3691..3aa5877a 100644 --- a/src/commands/scan/fetch-delete-org-full-scan.mts +++ b/src/commands/scan/fetch-delete-org-full-scan.mts @@ -1,5 +1,4 @@ -import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -11,21 +10,8 @@ export async function fetchDeleteOrgFullScan( ): Promise['data']>> { const sockSdk = await setupSdk() - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start('Requesting the scan to be deleted...') - - const result = await handleApiCall( + return await handleApiCall( sockSdk.deleteOrgFullScan(orgSlug, scanId), - 'Deleting scan' + 'to delete a scan' ) - - spinner.successAndStop('Received response for deleting a scan.') - - if (!result.success) { - return handleFailedApiResponse('deleteOrgFullScan', result) - } - - return { ok: true, data: result.data } } diff --git a/src/commands/scan/fetch-diff-scan.mts b/src/commands/scan/fetch-diff-scan.mts index b214eb1b..7db6e246 100644 --- a/src/commands/scan/fetch-diff-scan.mts +++ b/src/commands/scan/fetch-diff-scan.mts @@ -1,7 +1,7 @@ import { logger } from '@socketsecurity/registry/lib/logger' import constants from '../../constants.mts' -import { handleApiCall, handleApiError, queryApi } from '../../utils/api.mts' +import { handleApiError, queryApi } from '../../utils/api.mts' import { getDefaultToken } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -42,12 +42,8 @@ export async function fetchDiffScan({ } } - const result = await handleApiCall( - (await response.json()) as Promise< - SocketSdkReturnType<'GetOrgDiffScan'>['data'] - >, - 'Deserializing json' - ) + const fullScan = + (await response.json()) as SocketSdkReturnType<'GetOrgDiffScan'>['data'] - return { ok: true, data: result } + return { ok: true, data: fullScan } } diff --git a/src/commands/scan/fetch-list-scans.mts b/src/commands/scan/fetch-list-scans.mts index 30c251ea..cb297632 100644 --- a/src/commands/scan/fetch-list-scans.mts +++ b/src/commands/scan/fetch-list-scans.mts @@ -1,5 +1,4 @@ -import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -26,12 +25,7 @@ export async function fetchListScans({ }): Promise['data']>> { const sockSdk = await setupSdk() - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start('Fetching list of scans...') - - const result = await handleApiCall( + return await handleApiCall( sockSdk.getOrgFullScanList(orgSlug, { ...(branch ? { branch } : {}), ...(repo ? { repo } : {}), @@ -41,14 +35,6 @@ export async function fetchListScans({ page: String(page), from: from_time }), - 'Listing scans' + 'list of scans' ) - - spinner.successAndStop(`Received response for list of scans.`) - - if (!result.success) { - return handleFailedApiResponse('getOrgFullScanList', result) - } - - return { ok: true, data: result.data } } diff --git a/src/commands/scan/fetch-report-data.mts b/src/commands/scan/fetch-report-data.mts index 08f7b434..fb3ebbe4 100644 --- a/src/commands/scan/fetch-report-data.mts +++ b/src/commands/scan/fetch-report-data.mts @@ -3,10 +3,10 @@ import { logger } from '@socketsecurity/registry/lib/logger' import constants from '../../constants.mts' import { - handleApiCall, + handleApiCallNoSpinner, handleApiError, - handleFailedApiResponse, - queryApi + queryApi, + tmpHandleApiCall } from '../../utils/api.mts' import { getDefaultToken, setupSdk } from '../../utils/sdk.mts' @@ -73,10 +73,14 @@ export async function fetchReportData( async function fetchScanResult( apiToken: string ): Promise>> { - const response = await queryApi( - `orgs/${orgSlug}/full-scans/${encodeURIComponent(scanId)}${includeLicensePolicy ? '?include_license_details=true' : ''}`, - apiToken + const response = await tmpHandleApiCall( + queryApi( + `orgs/${orgSlug}/full-scans/${encodeURIComponent(scanId)}${includeLicensePolicy ? '?include_license_details=true' : ''}`, + apiToken + ), + 'fetchScanResult' ) + updateScan('received response') if (!response.ok) { @@ -115,20 +119,14 @@ export async function fetchReportData( async function fetchSecurityPolicy(): Promise< CResult['data']> > { - const response = await sockSdk.getOrgSecurityPolicy(orgSlug) - updatePolicy('received response') - - if (!response.success) { - return handleFailedApiResponse('getOrgSecurityPolicy', response) - } - - const s = await handleApiCall( - response, - "looking up organization's security policy" + const result = await handleApiCallNoSpinner( + sockSdk.getOrgSecurityPolicy(orgSlug), + 'GetOrgSecurityPolicy' ) + updatePolicy('received policy') - return { ok: true, data: s.data } + return result } updateProgress() diff --git a/src/commands/scan/fetch-scan-metadata.mts b/src/commands/scan/fetch-scan-metadata.mts index 014e45c0..9eba472b 100644 --- a/src/commands/scan/fetch-scan-metadata.mts +++ b/src/commands/scan/fetch-scan-metadata.mts @@ -1,5 +1,4 @@ -import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -11,21 +10,8 @@ export async function fetchScanMetadata( ): Promise['data']>> { const sockSdk = await setupSdk() - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start('Fetching meta data for a full scan...') - - const result = await handleApiCall( + return await handleApiCall( sockSdk.getOrgFullScanMetadata(orgSlug, scanId), - 'Listing scans' + 'meta data for a full scan' ) - - spinner.successAndStop('Received response for scan meta data.') - - if (!result.success) { - return handleFailedApiResponse('getOrgFullScanMetadata', result) - } - - return { ok: true, data: result.data } } diff --git a/src/commands/scan/fetch-supported-scan-file-names.mts b/src/commands/scan/fetch-supported-scan-file-names.mts index ea6f1b6a..ad90aaec 100644 --- a/src/commands/scan/fetch-supported-scan-file-names.mts +++ b/src/commands/scan/fetch-supported-scan-file-names.mts @@ -1,7 +1,4 @@ -import { logger } from '@socketsecurity/registry/lib/logger' - -import constants from '../../constants.mts' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' import type { CResult } from '../../types.mts' @@ -12,22 +9,8 @@ export async function fetchSupportedScanFileNames(): Promise< > { const sockSdk = await setupSdk() - // Lazily access constants.spinner. - const { spinner } = constants - - spinner.start('Requesting supported scan file types from API...') - - const result = await handleApiCall( + return await handleApiCall( sockSdk.getReportSupportedFiles(), - 'fetching supported scan file types' + 'supported scan file types' ) - - spinner.stop() - logger.error('Received response while fetching supported scan file types.') - - if (!result.success) { - return handleFailedApiResponse('getReportSupportedFiles', result) - } - - return { ok: true, data: result.data } } diff --git a/src/commands/scan/stream-scan.mts b/src/commands/scan/stream-scan.mts index d007aea1..f268f2af 100644 --- a/src/commands/scan/stream-scan.mts +++ b/src/commands/scan/stream-scan.mts @@ -1,8 +1,7 @@ import { logger } from '@socketsecurity/registry/lib/logger' -import { handleApiCall, handleFailedApiResponse } from '../../utils/api.mts' +import { handleApiCall } from '../../utils/api.mts' import { setupSdk } from '../../utils/sdk.mts' -import { serializeResultJson } from '../../utils/serialize-result-json.mts' export async function streamScan( orgSlug: string, @@ -14,15 +13,8 @@ export async function streamScan( logger.error('Requesting data from API...') // Note: this will write to stdout or target file. It's not a noop - const data = await handleApiCall( + return await handleApiCall( sockSdk.getOrgFullScan(orgSlug, scanId, file === '-' ? undefined : file), - 'Fetching a scan' + 'a scan' ) - - if (!data?.success) { - // Note: this is always --json - const result = handleFailedApiResponse('getOrgFullScan', data) - logger.log(serializeResultJson(result)) - return - } } diff --git a/src/commands/scan/suggest-org-slug.mts b/src/commands/scan/suggest-org-slug.mts index a98e7048..8696f83e 100644 --- a/src/commands/scan/suggest-org-slug.mts +++ b/src/commands/scan/suggest-org-slug.mts @@ -6,13 +6,15 @@ import { setupSdk } from '../../utils/sdk.mts' export async function suggestOrgSlug(): Promise { const sockSdk = await setupSdk() + const result = await handleApiCall( sockSdk.getOrganizations(), - 'looking up organizations' + 'list of organizations' ) + // Ignore a failed request here. It was not the primary goal of // running this command and reporting it only leads to end-user confusion. - if (result.success) { + if (result.ok) { const proceed = await select({ message: 'Missing org name; do you want to use any of these orgs for this scan?', diff --git a/src/commands/scan/suggest-repo-slug.mts b/src/commands/scan/suggest-repo-slug.mts index 26dc1e56..5be1a48f 100644 --- a/src/commands/scan/suggest-repo-slug.mts +++ b/src/commands/scan/suggest-repo-slug.mts @@ -12,7 +12,7 @@ export async function suggestRepoSlug(orgSlug: string): Promise<{ } | void> { const sockSdk = await setupSdk() - // Same as above, but if there's a repo with the same name as cwd then + // If there's a repo with the same name as cwd then // default the selection to that name. const result = await handleApiCall( sockSdk.getOrgRepoList(orgSlug, { @@ -25,12 +25,12 @@ export async function suggestRepoSlug(orgSlug: string): Promise<{ perPage: '10', page: '0' }), - 'looking up known repos' + 'list of repositories' ) // Ignore a failed request here. It was not the primary goal of // running this command and reporting it only leads to end-user confusion. - if (result.success) { + if (result.ok) { const currentDirName = dirNameToSlug(path.basename(process.cwd())) let cwdIsKnown = @@ -40,9 +40,9 @@ export async function suggestRepoSlug(orgSlug: string): Promise<{ // Do an explicit request so we can assert that the cwd exists or not const result = await handleApiCall( sockSdk.getOrgRepo(orgSlug, currentDirName), - 'checking if current cwd is a known repo' + 'check if current cwd is a known repo' ) - if (result.success) { + if (result.ok) { cwdIsKnown = true } } diff --git a/src/utils/api.mts b/src/utils/api.mts index aec092c7..ca082444 100644 --- a/src/utils/api.mts +++ b/src/utils/api.mts @@ -10,12 +10,17 @@ import { failMsgWithBadge } from './fail-msg-with-badge.mts' import type { CResult } from '../types.mts' import type { SocketSdkErrorType, - SocketSdkOperations + SocketSdkOperations, + SocketSdkResultType, + SocketSdkReturnType } from '@socketsecurity/sdk' +// TODO: this function is removed after v1.0.0 export function handleUnsuccessfulApiResponse( _name: T, - { cause, error, status }: SocketSdkErrorType + error: string, + cause: string, + status: number ): never { const message = `${error || 'No error message returned'}${cause ? ` (reason: ${cause})` : ''}` if (status === 401 || status === 403) { @@ -44,19 +49,117 @@ export function handleFailedApiResponse( } } -export async function handleApiCall( - value: T, - description: string -): Promise { - let result: T +export async function handleApiCall( + value: Promise>, + fetchingDesc: string +): Promise['data']>> { + // Lazily access constants.spinner. + const { spinner } = constants + + spinner.start(`Requesting ${fetchingDesc} from API...`) + + let result: SocketSdkResultType try { result = await value + + // TODO: info, not success (looks weird when response is non-200) + spinner.successAndStop( + `Received API response (after requesting ${fetchingDesc}).` + ) + } catch (e) { + spinner.failAndStop(`An error was thrown while requesting ${fetchingDesc}`) + + debugLog(`handleApiCall(${fetchingDesc}) threw error:\n`, e) + + const message = `${e || 'No error message returned'}` + const cause = `${e || 'No error message returned'}` + + return { + ok: false, + message: 'Socket API returned an error', + cause: `${message}${cause ? ` ( Reason: ${cause} )` : ''}` + } + } finally { + spinner.stop() + } + + // Note: TS can't narrow down the type of result due to generics + if (result.success === false) { + const err = result as SocketSdkErrorType + const message = `${err.error || 'No error message returned'}` + debugLog(`handleApiCall(${fetchingDesc}) bad response:\n`, err) + + return { + ok: false, + message: 'Socket API returned an error', + cause: `${message}${err.cause ? ` ( Reason: ${err.cause} )` : ''}`, + data: { + code: result.status + } + } + } else { + const ok = result as SocketSdkReturnType + return { + ok: true, + data: ok.data + } + } +} + +export async function tmpHandleApiCall( + value: Promise, + description: string +): Promise> { + try { + return await value } catch (e) { debugLog(`handleApiCall[${description}] error:\n`, e) // TODO: eliminate this throw in favor of CResult (or anything else) throw new Error(`Failed ${description}`, { cause: e }) } - return result +} + +export async function handleApiCallNoSpinner( + value: Promise>, + description: string +): Promise['data']>> { + let result: SocketSdkResultType + try { + result = await value + } catch (e) { + debugLog(`handleApiCall(${description}) threw error:\n`, e) + + const message = `${e || 'No error message returned'}` + const cause = `${e || 'No error message returned'}` + + return { + ok: false, + message: 'Socket API returned an error', + cause: `${message}${cause ? ` ( Reason: ${cause} )` : ''}` + } + } + + // Note: TS can't narrow down the type of result due to generics + if (result.success === false) { + const err = result as SocketSdkErrorType + const message = `${err.error || 'No error message returned'}` + debugLog(`handleApiCall(${description}) bad response:\n`, err) + + return { + ok: false, + message: 'Socket API returned an error', + cause: `${message}${err.cause ? ` ( Reason: ${err.cause} )` : ''}`, + data: { + code: result.status + } + } + } else { + const ok = result as SocketSdkReturnType + return { + ok: true, + data: ok.data + } + } } export async function handleApiError(code: number) { diff --git a/test/smoke.sh b/test/smoke.sh index 211c95c4..a1a85239 100755 --- a/test/smoke.sh +++ b/test/smoke.sh @@ -456,7 +456,6 @@ if should_run_section "organization"; then run_socket 0 organization policy security --org $DEFORG_BAK run_socket 0 organization policy license --markdown - run_socket 0 organization policy license --json run_json 0 organization policy license --json run_socket 1 organization policy license --org trash run_socket 1 organization policy license --org trash --markdown @@ -520,7 +519,7 @@ if should_run_section "raw-npx"; then run_socket 0 raw-npx # interactive shell... run_socket 2 raw-npx --help run_socket 0 raw-npx --dry-run - run_socket 0 rax-npx socket --dry-run + run_socket 0 raw-npx socket --dry-run fi ### repos