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
12 changes: 10 additions & 2 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,17 @@ module.exports = [
parser: tsParser,
parserOptions: {
projectService: {
allowDefaultProject: ['test/*.ts'],
allowDefaultProject: [
'test/*.ts',
// src/utils/*
'src/*/*.test.ts',
// src/commands/xyz/*
'src/*/*/*.test.ts'
],
defaultProject: 'tsconfig.json',
tsconfigRootDir: rootPath
tsconfigRootDir: rootPath,
// Need this to glob the test files in /src. Otherwise it won't work.
maximumDefaultProjectFileMatchCount_THIS_WILL_SLOW_DOWN_LINTING: 1_000_000
}
}
},
Expand Down
66 changes: 66 additions & 0 deletions src/commands/organization/cmd-organization-list.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import path from 'node:path'

import { describe, expect } from 'vitest'

import constants from '../../../dist/constants.js'
import { cmdit, invokeNpm } from '../../../test/utils'

const { CLI } = constants

describe('socket organization list', async () => {
// Lazily access constants.rootBinPath.
const entryPath = path.join(constants.rootBinPath, `${CLI}.js`)

cmdit(
['organization', 'list', '--help'],
'should support --help',
async cmd => {
const { code, stderr, stdout } = await invokeNpm(entryPath, cmd)
expect(stdout).toMatchInlineSnapshot(
`
"List organizations associated with the API key used

Usage
$ socket organization list

Options
--dryRun Do input validation for a command and exit 0 when input is ok
--help Print this help.
--json Output result as json
--markdown Output result as markdown"
`
)
expect(`\n ${stderr}`).toMatchInlineSnapshot(`
"
_____ _ _ /---------------
| __|___ ___| |_ ___| |_ | Socket.dev CLI ver <redacted>
|__ | . | _| '_| -_| _| | Node: <redacted>, API token set: <redacted>
|_____|___|___|_,_|___|_|.dev | Command: \`socket organization list\`, cwd: <redacted>"
`)

expect(code, 'help should exit with code 2').toBe(2)
expect(
stderr,
'header should include command (without params)'
).toContain('`socket organization list`')
}
)

cmdit(
['organization', 'list', '--dry-run'],
'should be ok with org name and id',
async cmd => {
const { code, stderr, stdout } = await invokeNpm(entryPath, cmd)
expect(stdout).toMatchInlineSnapshot(`"[DryRun]: Bailing now"`)
expect(`\n ${stderr}`).toMatchInlineSnapshot(`
"
_____ _ _ /---------------
| __|___ ___| |_ ___| |_ | Socket.dev CLI ver <redacted>
|__ | . | _| '_| -_| _| | Node: <redacted>, API token set: <redacted>
|_____|___|___|_,_|___|_|.dev | Command: \`socket organization list\`, cwd: <redacted>"
`)

expect(code, 'dry-run should exit with code 0 if input ok').toBe(0)
}
)
})
72 changes: 72 additions & 0 deletions src/commands/organization/cmd-organization-list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { stripIndents } from 'common-tags'
import colors from 'yoctocolors-cjs'

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

import { getOrganization } from './get-organization'
import constants from '../../constants'
import { commonFlags, outputFlags } from '../../flags'
import { meowOrExit } from '../../utils/meow-with-subcommands'
import { getFlagListOutput } from '../../utils/output-formatting'

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

const { DRY_RUN_BAIL_TEXT } = constants

const config: CliCommandConfig = {
commandName: 'list',
description: 'List organizations associated with the API key used',
hidden: false,
flags: {
...commonFlags,
...outputFlags
},
help: (command, _config) => `
Usage
$ ${command}

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

export const cmdOrganizationList = {
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 = Boolean(cli.flags['json'])
const markdown = Boolean(cli.flags['markdown'])
if (json && markdown) {
// 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:

- The json and markdown flags cannot be both set, pick one
`)
return
}

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

await getOrganization(json ? 'json' : markdown ? 'markdown' : 'text')
}
96 changes: 96 additions & 0 deletions src/commands/organization/cmd-organization-policy-security.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import path from 'node:path'

import { describe, expect } from 'vitest'

import constants from '../../../dist/constants.js'
import { cmdit, invokeNpm } from '../../../test/utils'

const { CLI } = constants

describe('socket organization list', async () => {
// Lazily access constants.rootBinPath.
const entryPath = path.join(constants.rootBinPath, `${CLI}.js`)

cmdit(
['organization', 'policy', 'security', '--help'],
'should support --help',
async cmd => {
const { code, stderr, stdout } = await invokeNpm(entryPath, cmd)
expect(stdout).toMatchInlineSnapshot(
`
"Retrieve the security policy of an organization.

Usage
$ socket organization policy security <org slug>

Options
--dryRun Do input validation for a command and exit 0 when input is ok
--help Print this help.
--json Output result as json
--markdown Output result as markdown

Your API token will need the \`security-policy:read\` permission otherwise
the request will fail with an authentication error.

Examples
$ socket organization policy security mycorp
$ socket organization policy security mycorp --json"
`
)
expect(`\n ${stderr}`).toMatchInlineSnapshot(`
"
_____ _ _ /---------------
| __|___ ___| |_ ___| |_ | Socket.dev CLI ver <redacted>
|__ | . | _| '_| -_| _| | Node: <redacted>, API token set: <redacted>
|_____|___|___|_,_|___|_|.dev | Command: \`socket organization policy security\`, cwd: <redacted>"
`)

expect(code, 'help should exit with code 2').toBe(2)
expect(
stderr,
'header should include command (without params)'
).toContain('`socket organization policy security`')
}
)

cmdit(
['organization', 'policy', 'security', '--dry-run'],
'should reject dry run without proper args',
async cmd => {
const { code, stderr, stdout } = await invokeNpm(entryPath, cmd)
expect(stdout).toMatchInlineSnapshot(`""`)
expect(`\n ${stderr}`).toMatchInlineSnapshot(`
"
_____ _ _ /---------------
| __|___ ___| |_ ___| |_ | Socket.dev CLI ver <redacted>
|__ | . | _| '_| -_| _| | Node: <redacted>, API token set: <redacted>
|_____|___|___|_,_|___|_|.dev | Command: \`socket organization policy security\`, cwd: <redacted>

\\x1b[31m\\xd7\\x1b[39m \\x1b[41m\\x1b[37mInput error\\x1b[39m\\x1b[49m: Please provide the required fields:

- Org name as the first argument \\x1b[31m(missing!)\\x1b[39m
- The json and markdown flags cannot be both set \\x1b[32m(ok)\\x1b[39m"
`)

expect(code, 'dry-run should exit with code 2 if input bad').toBe(2)
}
)

cmdit(
['organization', 'policy', 'security', 'fakeorg', '--dry-run'],
'should be ok with org name and id',
async cmd => {
const { code, stderr, stdout } = await invokeNpm(entryPath, cmd)
expect(stdout).toMatchInlineSnapshot(`"[DryRun]: Bailing now"`)
expect(`\n ${stderr}`).toMatchInlineSnapshot(`
"
_____ _ _ /---------------
| __|___ ___| |_ ___| |_ | Socket.dev CLI ver <redacted>
|__ | . | _| '_| -_| _| | Node: <redacted>, API token set: <redacted>
|_____|___|___|_,_|___|_|.dev | Command: \`socket organization policy security\`, cwd: <redacted>"
`)

expect(code, 'dry-run should exit with code 0 if input ok').toBe(0)
}
)
})
87 changes: 87 additions & 0 deletions src/commands/organization/cmd-organization-policy-security.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { stripIndents } from 'common-tags'
import colors from 'yoctocolors-cjs'

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

import { getSecurityPolicy } from './get-security-policy'
import constants from '../../constants'
import { commonFlags, outputFlags } from '../../flags'
import { meowOrExit } from '../../utils/meow-with-subcommands'
import { getFlagListOutput } from '../../utils/output-formatting'

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

const { DRY_RUN_BAIL_TEXT } = constants

// TODO: secret toplevel alias `socket security policy`?
const config: CliCommandConfig = {
commandName: 'security',
description: 'Retrieve the security policy of an organization.',
hidden: true,
flags: {
...commonFlags,
...outputFlags
},
help: (command, _config) => `
Usage
$ ${command} <org slug>

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

Your API token will need the \`security-policy:read\` permission otherwise
the request will fail with an authentication error.

Examples
$ ${command} mycorp
$ ${command} mycorp --json
`
}

export const cmdOrganizationPolicyPolicy = {
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 = Boolean(cli.flags['json'])
const markdown = Boolean(cli.flags['markdown'])

const [orgSlug = ''] = cli.input

if (!orgSlug || (json && markdown)) {
// 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:

- Org name as the first argument ${!orgSlug ? colors.red('(missing!)') : colors.green('(ok)')}
- The json and markdown flags cannot be both set ${json && markdown ? colors.red('(pick one!)') : colors.green('(ok)')}
`)
return
}

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

await getSecurityPolicy(
orgSlug,
json ? 'json' : markdown ? 'markdown' : 'text'
)
}
52 changes: 52 additions & 0 deletions src/commands/organization/cmd-organization-policy.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import path from 'node:path'

import { describe, expect } from 'vitest'

import constants from '../../../dist/constants.js'
import { cmdit, invokeNpm } from '../../../test/utils'

const { CLI } = constants

describe('socket organization list', async () => {
// Lazily access constants.rootBinPath.
const entryPath = path.join(constants.rootBinPath, `${CLI}.js`)

cmdit(
['organization', 'policy', '--help'],
'should support --help',
async cmd => {
const { code, stderr, stdout } = await invokeNpm(entryPath, cmd)
expect(stdout).toMatchInlineSnapshot(
`
"Organization policy details

Usage
$ socket organization policy <command>

Commands


Options
--dryRun Do input validation for a command and exit 0 when input is ok
--help Print this help.

Examples
$ socket organization policy --help"
`
)
expect(`\n ${stderr}`).toMatchInlineSnapshot(`
"
_____ _ _ /---------------
| __|___ ___| |_ ___| |_ | Socket.dev CLI ver <redacted>
|__ | . | _| '_| -_| _| | Node: <redacted>, API token set: <redacted>
|_____|___|___|_,_|___|_|.dev | Command: \`socket organization policy\`, cwd: <redacted>"
`)

expect(code, 'help should exit with code 2').toBe(2)
expect(
stderr,
'header should include command (without params)'
).toContain('`socket organization policy`')
}
)
})
Loading