Skip to content

Commit 530b033

Browse files
committed
[socket organization policy license] Add license policy cmd
1 parent dede5b8 commit 530b033

11 files changed

+304
-109
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import path from 'node:path'
2+
3+
import { describe, expect } from 'vitest'
4+
5+
import constants from '../../../dist/constants.js'
6+
import { cmdit, invokeNpm } from '../../../test/utils'
7+
8+
const { CLI } = constants
9+
10+
describe('socket organization policy license', async () => {
11+
// Lazily access constants.rootBinPath.
12+
const entryPath = path.join(constants.rootBinPath, `${CLI}.js`)
13+
14+
cmdit(
15+
['organization', 'policy', 'license', '--help', '--config', '{}'],
16+
'should support --help',
17+
async cmd => {
18+
const { code, stderr, stdout } = await invokeNpm(entryPath, cmd)
19+
expect(stdout).toMatchInlineSnapshot(
20+
`
21+
"Retrieve the license policy of an organization.
22+
23+
Usage
24+
$ socket organization policy license <org slug>
25+
26+
Options
27+
--dryRun Do input validation for a command and exit 0 when input is ok
28+
--help Print this help.
29+
--json Output result as json
30+
--markdown Output result as markdown
31+
32+
Your API token will need the \`license-policy:read\` permission otherwise
33+
the request will fail with an authentication error.
34+
35+
Examples
36+
$ socket organization policy license mycorp
37+
$ socket organization policy license mycorp --json"
38+
`
39+
)
40+
expect(`\n ${stderr}`).toMatchInlineSnapshot(`
41+
"
42+
_____ _ _ /---------------
43+
| __|___ ___| |_ ___| |_ | Socket.dev CLI ver <redacted>
44+
|__ | . | _| '_| -_| _| | Node: <redacted>, API token set: <redacted>
45+
|_____|___|___|_,_|___|_|.dev | Command: \`socket organization policy license\`, cwd: <redacted>"
46+
`)
47+
48+
expect(code, 'help should exit with code 2').toBe(2)
49+
expect(stderr, 'banner includes base command').toContain(
50+
'`socket organization policy license`'
51+
)
52+
}
53+
)
54+
55+
cmdit(
56+
['organization', 'policy', 'license', '--dry-run', '--config', '{}'],
57+
'should reject dry run without proper args',
58+
async cmd => {
59+
const { code, stderr, stdout } = await invokeNpm(entryPath, cmd)
60+
expect(stdout).toMatchInlineSnapshot(`""`)
61+
expect(`\n ${stderr}`).toMatchInlineSnapshot(`
62+
"
63+
_____ _ _ /---------------
64+
| __|___ ___| |_ ___| |_ | Socket.dev CLI ver <redacted>
65+
|__ | . | _| '_| -_| _| | Node: <redacted>, API token set: <redacted>
66+
|_____|___|___|_,_|___|_|.dev | Command: \`socket organization policy license\`, cwd: <redacted>
67+
68+
\\x1b[31m\\xd7\\x1b[39m \\x1b[41m\\x1b[1m\\x1b[37m Input error: \\x1b[39m\\x1b[22m\\x1b[49m \\x1b[1mPlease review the input requirements and try again\\x1b[22m:
69+
70+
- Org name as the first argument (\\x1b[31mmissing\\x1b[39m)"
71+
`)
72+
73+
expect(code, 'dry-run should exit with code 2 if input bad').toBe(2)
74+
}
75+
)
76+
77+
cmdit(
78+
[
79+
'organization',
80+
'policy',
81+
'license',
82+
'fakeorg',
83+
'--dry-run',
84+
'--config',
85+
'{}'
86+
],
87+
'should be ok with org name and id',
88+
async cmd => {
89+
const { code, stderr, stdout } = await invokeNpm(entryPath, cmd)
90+
expect(stdout).toMatchInlineSnapshot(`"[DryRun]: Bailing now"`)
91+
expect(`\n ${stderr}`).toMatchInlineSnapshot(`
92+
"
93+
_____ _ _ /---------------
94+
| __|___ ___| |_ ___| |_ | Socket.dev CLI ver <redacted>
95+
|__ | . | _| '_| -_| _| | Node: <redacted>, API token set: <redacted>
96+
|_____|___|___|_,_|___|_|.dev | Command: \`socket organization policy license\`, cwd: <redacted>"
97+
`)
98+
99+
expect(code, 'dry-run should exit with code 0 if input ok').toBe(0)
100+
}
101+
)
102+
})
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { logger } from '@socketsecurity/registry/lib/logger'
2+
3+
import { handleLicensePolicy } from './handle-license-policy'
4+
import constants from '../../constants'
5+
import { commonFlags, outputFlags } from '../../flags'
6+
import { getConfigValue } from '../../utils/config'
7+
import { handleBadInput } from '../../utils/handle-bad-input'
8+
import { meowOrExit } from '../../utils/meow-with-subcommands'
9+
import { getFlagListOutput } from '../../utils/output-formatting'
10+
11+
import type { CliCommandConfig } from '../../utils/meow-with-subcommands'
12+
13+
const { DRY_RUN_BAIL_TEXT } = constants
14+
15+
// TODO: secret toplevel alias `socket license policy`?
16+
const config: CliCommandConfig = {
17+
commandName: 'license',
18+
description: 'Retrieve the license policy of an organization.',
19+
hidden: true,
20+
flags: {
21+
...commonFlags,
22+
...outputFlags
23+
},
24+
help: (command, _config) => `
25+
Usage
26+
$ ${command} <org slug>
27+
28+
Options
29+
${getFlagListOutput(config.flags, 6)}
30+
31+
Your API token will need the \`license-policy:read\` permission otherwise
32+
the request will fail with an authentication error.
33+
34+
Examples
35+
$ ${command} mycorp
36+
$ ${command} mycorp --json
37+
`
38+
}
39+
40+
export const cmdOrganizationPolicyLicense = {
41+
description: config.description,
42+
hidden: config.hidden,
43+
run
44+
}
45+
46+
async function run(
47+
argv: string[] | readonly string[],
48+
importMeta: ImportMeta,
49+
{ parentName }: { parentName: string }
50+
): Promise<void> {
51+
const cli = meowOrExit({
52+
argv,
53+
config,
54+
importMeta,
55+
parentName
56+
})
57+
58+
const json = Boolean(cli.flags['json'])
59+
const markdown = Boolean(cli.flags['markdown'])
60+
61+
const defaultOrgSlug = getConfigValue('defaultOrg')
62+
const orgSlug = defaultOrgSlug || cli.input[0] || ''
63+
64+
const wasBadInput = handleBadInput(
65+
{
66+
hide: defaultOrgSlug,
67+
test: orgSlug,
68+
message: 'Org name as the first argument',
69+
pass: 'ok',
70+
fail: 'missing'
71+
},
72+
{
73+
hide: !json || !markdown,
74+
test: !json || !markdown,
75+
message: 'The json and markdown flags cannot be both set, pick one',
76+
pass: 'ok',
77+
fail: 'omit one'
78+
}
79+
)
80+
if (wasBadInput) {
81+
return
82+
}
83+
84+
if (cli.flags['dryRun']) {
85+
logger.log(DRY_RUN_BAIL_TEXT)
86+
return
87+
}
88+
89+
await handleLicensePolicy(
90+
orgSlug,
91+
json ? 'json' : markdown ? 'markdown' : 'text'
92+
)
93+
}

src/commands/organization/cmd-organization-policy-security.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { cmdit, invokeNpm } from '../../../test/utils'
77

88
const { CLI } = constants
99

10-
describe('socket organization list', async () => {
10+
describe('socket organization policy security', async () => {
1111
// Lazily access constants.rootBinPath.
1212
const entryPath = path.join(constants.rootBinPath, `${CLI}.js`)
1313

src/commands/organization/cmd-organization-policy.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { cmdOrganizationPolicyLicense } from './cmd-organization-policy-license'
12
import { cmdOrganizationPolicyPolicy } from './cmd-organization-policy-security'
23
import { meowWithSubcommands } from '../../utils/meow-with-subcommands'
34

@@ -15,7 +16,8 @@ export const cmdOrganizationPolicy: CliSubcommand = {
1516
async run(argv, importMeta, { parentName }) {
1617
await meowWithSubcommands(
1718
{
18-
security: cmdOrganizationPolicyPolicy
19+
security: cmdOrganizationPolicyPolicy,
20+
license: cmdOrganizationPolicyLicense
1921
},
2022
{
2123
argv,
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import constants from '../../constants'
2+
import { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api'
3+
import { AuthError } from '../../utils/errors'
4+
import { getDefaultToken, setupSdk } from '../../utils/sdk'
5+
6+
import type { SocketSdkReturnType } from '@socketsecurity/sdk'
7+
8+
export async function fetchLicensePolicy(
9+
orgSlug: string
10+
): Promise<SocketSdkReturnType<'getOrgLicensePolicy'>['data'] | undefined> {
11+
const apiToken = getDefaultToken()
12+
if (!apiToken) {
13+
throw new AuthError(
14+
'User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.'
15+
)
16+
}
17+
18+
return await fetchLicensePolicyWithToken(apiToken, orgSlug)
19+
}
20+
21+
async function fetchLicensePolicyWithToken(
22+
apiToken: string,
23+
orgSlug: string
24+
): Promise<SocketSdkReturnType<'getOrgLicensePolicy'>['data'] | undefined> {
25+
// Lazily access constants.spinner.
26+
const { spinner } = constants
27+
28+
const sockSdk = await setupSdk(apiToken)
29+
30+
spinner.start('Fetching organization license policy...')
31+
32+
const result = await handleApiCall(
33+
sockSdk.getOrgLicensePolicy(orgSlug),
34+
'looking up organization quota'
35+
)
36+
37+
spinner.successAndStop('Received organization license policy response.')
38+
39+
if (!result.success) {
40+
handleUnsuccessfulApiResponse('getOrgLicensePolicy', result)
41+
return
42+
}
43+
44+
return result.data
45+
}

src/commands/organization/fetch-security-policy.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ async function fetchSecurityPolicyWithToken(
2727

2828
const sockSdk = await setupSdk(apiToken)
2929

30-
spinner.start('Fetching organization quota...')
30+
spinner.start('Fetching organization security policy...')
3131

3232
const result = await handleApiCall(
3333
sockSdk.getOrgSecurityPolicy(orgSlug),
3434
'looking up organization quota'
3535
)
3636

37-
spinner?.successAndStop('Received organization quota response.')
37+
spinner?.successAndStop('Received organization security policy response.')
3838

3939
if (!result.success) {
4040
handleUnsuccessfulApiResponse('getOrgSecurityPolicy', result)

src/commands/organization/get-license-policy.ts

Lines changed: 0 additions & 102 deletions
This file was deleted.

0 commit comments

Comments
 (0)