Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/commands/audit-log/cmd-audit-log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { logger } from '@socketsecurity/registry/lib/logger'
import { handleAuditLog } from './handle-audit-log'
import constants from '../../constants'
import { commonFlags, outputFlags } from '../../flags'
import { getConfigValue } from '../../utils/config'
import { meowOrExit } from '../../utils/meow-with-subcommands'
import { getFlagListOutput } from '../../utils/output-formatting'

Expand Down Expand Up @@ -73,9 +74,10 @@ async function run(
})

const { json, markdown, page, perPage, type } = cli.flags

const logType = String(type || '')
const [orgSlug = ''] = cli.input

const defaultOrgSlug = getConfigValue('defaultOrg')
const orgSlug = defaultOrgSlug || cli.input[0] || ''

if (!orgSlug) {
// Use exit status of 2 to indicate incorrect usage, generally invalid
Expand Down
91 changes: 91 additions & 0 deletions src/commands/config/cmd-config-auto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { stripIndents } from 'common-tags'
import colors from 'yoctocolors-cjs'

import { logger } from '@socketsecurity/registry/lib/logger'

import { handleConfigAuto } from './handle-config-auto'
import constants from '../../constants'
import { commonFlags, outputFlags } from '../../flags'
import { supportedConfigKeys } from '../../utils/config'
import { meowOrExit } from '../../utils/meow-with-subcommands'
import { getFlagListOutput } from '../../utils/output-formatting'

import type { LocalConfig } from '../../utils/config'
import type { CliCommandConfig } from '../../utils/meow-with-subcommands'

const { DRY_RUN_BAIL_TEXT } = constants

const config: CliCommandConfig = {
commandName: 'auto',
description: 'Automatically discover and set the correct value config item',
hidden: false,
flags: {
...commonFlags,
...outputFlags
},
help: (command, config) => `
Usage
$ ${command} <org slug>

Options
${getFlagListOutput(config.flags, 6)}

Attempt to automatically discover the correct value for a certain config key.

For certain keys it will request the value from server, for others it will
reset the value to the default. For some keys this has no effect.

Keys:

${Array.from(supportedConfigKeys.entries())
.map(([key, desc]) => ` - ${key} -- ${desc}`)
.join('\n')}

Examples
$ ${command} auto defaultOrg
`
}

export const cmdConfigAuto = {
description: config.description,
hidden: config.hidden,
run
}

async function run(
argv: string[] | readonly string[],
importMeta: ImportMeta,
{ parentName }: { parentName: string }
): Promise<void> {
const cli = meowOrExit({
argv,
config,
importMeta,
parentName
})

const { json, markdown } = cli.flags
const [key = ''] = cli.input

if (!supportedConfigKeys.has(key as keyof LocalConfig) && key !== 'test') {
// Use exit status of 2 to indicate incorrect usage, generally invalid
// options or missing arguments.
// https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
process.exitCode = 2
logger.fail(stripIndents`${colors.bgRed(colors.white('Input error'))}: Please provide the required fields:

- Config key should be the first arg ${!key ? colors.red('(missing!)') : !supportedConfigKeys.has(key as any) ? colors.red('(invalid config key!)') : colors.green('(ok)')}
`)
return
}

if (cli.flags['dryRun']) {
logger.log(DRY_RUN_BAIL_TEXT)
return
}

await handleConfigAuto({
key: key as keyof LocalConfig,
outputKind: json ? 'json' : markdown ? 'markdown' : 'text'
})
}
3 changes: 2 additions & 1 deletion src/commands/config/cmd-config-get.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ describe('socket config get', async () => {
Keys:

- apiBaseUrl -- Base URL of the API endpoint
- apiToken -- The API token required to access most API endpoints
- apiProxy -- A proxy through which to access the API
- apiToken -- The API token required to access most API endpoints
- defaultOrg -- The default org slug to use when appropriate; usually the org your API token has access to. When set, all orgSlug arguments are implied to be this value.
- enforcedOrgs -- Orgs in this list have their security policies enforced on this machine

Examples
Expand Down
3 changes: 2 additions & 1 deletion src/commands/config/cmd-config-list.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ describe('socket config get', async () => {
Keys:

- apiBaseUrl -- Base URL of the API endpoint
- apiToken -- The API token required to access most API endpoints
- apiProxy -- A proxy through which to access the API
- apiToken -- The API token required to access most API endpoints
- defaultOrg -- The default org slug to use when appropriate; usually the org your API token has access to. When set, all orgSlug arguments are implied to be this value.
- enforcedOrgs -- Orgs in this list have their security policies enforced on this machine

Examples
Expand Down
3 changes: 2 additions & 1 deletion src/commands/config/cmd-config-set.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ describe('socket config get', async () => {
Keys:

- apiBaseUrl -- Base URL of the API endpoint
- apiToken -- The API token required to access most API endpoints
- apiProxy -- A proxy through which to access the API
- apiToken -- The API token required to access most API endpoints
- defaultOrg -- The default org slug to use when appropriate; usually the org your API token has access to. When set, all orgSlug arguments are implied to be this value.
- enforcedOrgs -- Orgs in this list have their security policies enforced on this machine

Examples
Expand Down
3 changes: 2 additions & 1 deletion src/commands/config/cmd-config-unset.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ describe('socket config unset', async () => {
Keys:

- apiBaseUrl -- Base URL of the API endpoint
- apiToken -- The API token required to access most API endpoints
- apiProxy -- A proxy through which to access the API
- apiToken -- The API token required to access most API endpoints
- defaultOrg -- The default org slug to use when appropriate; usually the org your API token has access to. When set, all orgSlug arguments are implied to be this value.
- enforcedOrgs -- Orgs in this list have their security policies enforced on this machine

Examples
Expand Down
1 change: 1 addition & 0 deletions src/commands/config/cmd-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ describe('socket config', async () => {
$ socket config <command>

Commands
auto Automatically discover and set the correct value config item
get Get the value of a local CLI config item
list Show all local CLI config items and their values
set Update the value of a local CLI config item
Expand Down
6 changes: 4 additions & 2 deletions src/commands/config/cmd-config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { cmdConfigAuto } from './cmd-config-auto'
import { cmdConfigGet } from './cmd-config-get'
import { cmdConfigList } from './cmd-config-list'
import { cmdConfigSet } from './cmd-config-set'
Expand All @@ -14,10 +15,11 @@ export const cmdConfig: CliSubcommand = {
async run(argv, importMeta, { parentName }) {
await meowWithSubcommands(
{
unset: cmdConfigUnset,
auto: cmdConfigAuto,
get: cmdConfigGet,
list: cmdConfigList,
set: cmdConfigSet
set: cmdConfigSet,
unset: cmdConfigUnset
},
{
argv,
Expand Down
174 changes: 174 additions & 0 deletions src/commands/config/discover-config-value.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import { handleApiCall } from '../../utils/api'
import { supportedConfigKeys } from '../../utils/config'
import { getDefaultToken, setupSdk } from '../../utils/sdk'

import type { LocalConfig } from '../../utils/config'

export async function discoverConfigValue(
key: string
): Promise<{ success: boolean; value: unknown; message: string }> {
// This will have to be a specific implementation per key because certain
// keys should request information from particular API endpoints while
// others should simply return their default value, like endpoint URL.

if (!supportedConfigKeys.has(key as keyof LocalConfig)) {
return {
success: false,
value: undefined,
message: 'Requested key is not a valid config key.'
}
}

if (key === 'apiBaseUrl') {
// Return the default value
return {
success: false,
value: undefined,
message:
"If you're unsure about the base endpoint URL then simply unset it."
}
}

if (key === 'apiProxy') {
// I don't think we can auto-discover this with any order of reliability..?
return {
success: false,
value: undefined,
message:
'When uncertain, unset this key. Otherwise ask your network administrator.'
}
}

if (key === 'apiToken') {
return {
success: false,
value: undefined,
message:
'You can find/create your API token in your Socket dashboard > settings > API tokens.\nYou should then use `socket login` to login instead of this command.'
}
}

if (key === 'defaultOrg') {
const apiToken = getDefaultToken()
if (!apiToken) {
return {
success: false,
value: undefined,
message:
'No API token set, must have a token to resolve its default org.'
}
}

const org = await getDefaultOrgFromToken()
if (!org?.length) {
return {
success: false,
value: undefined,
message:
'Was unable to determine default org for the current API token.'
}
}

if (Array.isArray(org)) {
return {
success: true,
value: org,
message: 'These are the orgs that the current API token can access.'
}
}

return {
success: true,
value: org,
message: 'This is the org that belongs to the current API token.'
}
}

if (key === 'enforcedOrgs') {
const apiToken = getDefaultToken()
if (!apiToken) {
return {
success: false,
value: undefined,
message:
'No API token set, must have a token to resolve orgs to enforce.'
}
}

const orgs = await getEnforceableOrgsFromToken()
if (!orgs?.length) {
return {
success: false,
value: undefined,
message:
'Was unable to determine any orgs to enforce for the current API token.'
}
}

return {
success: true,
value: orgs,
message: 'These are the orgs whose security policy you can enforce.'
}
}

if (key === 'test') {
return {
success: false,
value: undefined,
message: ''
}
}

// Mostly to please TS, because we're not telling it `key` is keyof LocalConfig
return {
success: false,
value: undefined,
message: 'unreachable?'
}
}

async function getDefaultOrgFromToken(): Promise<
string[] | string | undefined
> {
const sockSdk = await setupSdk()
const result = await handleApiCall(
sockSdk.getOrganizations(),
'looking up organizations'
)

if (result.success) {
const arr = Array.from(Object.values(result.data.organizations)).map(
({ slug }) => slug
)
if (arr.length === 0) {
return undefined
}
if (arr.length === 1) {
return arr[0]
}
return arr
}

return undefined
}

async function getEnforceableOrgsFromToken(): Promise<string[] | undefined> {
const sockSdk = await setupSdk()
const result = await handleApiCall(
sockSdk.getOrganizations(),
'looking up organizations'
)

if (result.success) {
const arr = Array.from(Object.values(result.data.organizations)).map(
({ slug }) => slug
)
if (arr.length === 0) {
return undefined
}
return arr
}

return undefined
}
16 changes: 16 additions & 0 deletions src/commands/config/handle-config-auto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { discoverConfigValue } from './discover-config-value'
import { outputConfigAuto } from './output-config-auto'

import type { LocalConfig } from '../../utils/config'

export async function handleConfigAuto({
key,
outputKind
}: {
key: keyof LocalConfig
outputKind: 'json' | 'markdown' | 'text'
}) {
const result = await discoverConfigValue(key)

await outputConfigAuto(key, result, outputKind)
}
Loading