Skip to content

Commit

Permalink
SWG-9025 Fetch organization standardization configuration command (#410)
Browse files Browse the repository at this point in the history
* SWG-9025 Fetch organization standardization configuration command

* SWG-9025 small tweaks around functionality and naming

* SWG-9025 first batch of tests

* SWG-9025 tests + docs

* SWG-9025 improving my english

* SWG-9025 removing spaces
  • Loading branch information
MiloszTarka authored Jan 18, 2024
1 parent 2494aa1 commit c31e8d6
Show file tree
Hide file tree
Showing 5 changed files with 259 additions and 1 deletion.
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ USAGE
* [`swaggerhub api:unpublish OWNER/API_NAME/VERSION`](#swaggerhub-apiunpublish)
* [`swaggerhub api:update OWNER/API_NAME/[VERSION]`](#swaggerhub-apiupdate)
* [`swaggerhub api:validate OWNER/API_NAME/[VERSION]`](#swaggerhub-apivalidate)
* [`swaggerhub api:validate:download-rules OWNER`](#swaggerhub-apivalidatedownload-rules)
* [`swaggerhub api:validate:local`](#swaggerhub-apivalidatelocal)
* [`swaggerhub configure`](#swaggerhub-configure)
* [`swaggerhub domain:create OWNER/DOMAIN_NAME/[VERSION]`](#swaggerhub-domaincreate)
Expand Down Expand Up @@ -425,6 +426,37 @@ EXAMPLES

_See code: [src/commands/api/validate/local.js](https://github.com/SmartBear/swaggerhub-cli/blob/v0.8.1/src/commands/api/validate/local.js)_

## `swaggerhub api:validate:download-rules`

Get existing SwaggerHub's organization standardization ruleset.

```
USAGE
$ swaggerhub api:validate:download-rules OWNER [-s] [-d] [-h]
ARGUMENTS
OWNER Which organization standardization rules to fetch from SwaggerHub
FLAGS
-d, --include-disabled-rules Includes disabled rules in fetched organization's ruleset
-h, --help Show CLI help.
-s, --include-system-rules Includes system rules in fetched organization's ruleset
DESCRIPTION
Get existing SwaggerHub's organization standardization ruleset.
Requires organization name argument. An error will occur if provided organization doesn't exist
or your account is not permitted to access that organization's settings.
If the flag `-s` or `--include-system-rules` is used, the returned ruleset will also include SwaggerHub system rules.
If the flag `-d` or `--include-disabled-rules` is used, the returned ruleset will also include disabled custom rules
EXAMPLES
$ swaggerhub api:validate:download-rules myOrg -s
$ swaggerhub api:validate:download-rules myOrg --include-disabled-rules -s
```

_See code: [src/commands/api/validate/download-rules.js](https://github.com/SmartBear/swaggerhub-cli/blob/v0.8.1/src/commands/api/validate/download-rules.js)_

## `swaggerhub configure`

configure application settings
Expand Down
58 changes: 58 additions & 0 deletions src/commands/api/validate/download-rules.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const { Flags, Args } = require('@oclif/core')
const BaseCommand = require('../../../support/command/base-command')
const { pipeAsync } = require('../../../utils/general')
const { getResponseContent } = require('../../../support/command/handle-response')
const { getStandardization } = require('../../../requests/standardization')

class ValidateDownloadRulesCommand extends BaseCommand {
async run() {
const { args, flags } = await this.parse(ValidateDownloadRulesCommand)

const includeSystemRules = flags['include-system-rules'] ?? false
const includeDisabledRules = flags['include-disabled-rules'] ?? false
const organization = args['OWNER']

const organizationRuleset = await this.getExportedOrganizationRuleset(organization, {includeSystemRules, includeDisabledRules})
this.log(JSON.stringify(organizationRuleset, null, 2))
}

getExportedOrganizationRuleset(orgName, queryParams) {
return this.executeHttp({
execute: () => getStandardization([orgName, 'spectral'], queryParams),
onResolve: pipeAsync(getResponseContent, JSON.parse),
options: {}
})
}
}

ValidateDownloadRulesCommand.description = `Get existing SwaggerHub's organization standardization ruleset.
Requires organization name argument. An error will occur if provided organization doesn't exist
or your account is not permitted to access that organization's settings.
If the flag \`-s\` or \`--include-system-rules\` is used, the returned ruleset will also include SwaggerHub system rules.
If the flag \`-d\` or \`--include-disabled-rules\` is used, the returned ruleset will also include disabled custom rules`

ValidateDownloadRulesCommand.examples = [
'swaggerhub api:validate:download-rules myOrg -s',
'swaggerhub api:validate:download-rules myOrg --include-disabled-rules -s',
]

ValidateDownloadRulesCommand.args = {
'OWNER': Args.string({
required: true,
description: 'Which organization standardization rules to fetch from SwaggerHub'
})
}
ValidateDownloadRulesCommand.flags = {
'include-system-rules': Flags.boolean({
char: 's',
description: 'Includes system rules in fetched organization\'s ruleset',
required: false
}),
'include-disabled-rules': Flags.boolean({
char: 'd',
description: 'Includes disabled rules in fetched organization\'s ruleset',
required: false
}),
...BaseCommand.flags
}
module.exports = ValidateDownloadRulesCommand
15 changes: 14 additions & 1 deletion src/requests/standardization.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@ const postStandardization = (pathParams, body) => {
})
}

const getStandardization = (pathParams, queryParams) => {
const { SWAGGERHUB_URL, SWAGGERHUB_API_KEY } = config.getConfig()

return http({
url: [SWAGGERHUB_URL, 'standardization', ...pathParams],
query: queryParams,
accept: 'json',
auth: SWAGGERHUB_API_KEY,
method: 'GET',
})
}

module.exports = {
postStandardization
postStandardization,
getStandardization
}
91 changes: 91 additions & 0 deletions test/commands/api/validate/download-rules.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
const { expect, test } = require('@oclif/test')
const config = require('../../../../src/config')
const {
ruleset,
rulesetWithDisabledRule,
rulesetWithSystemRule,
rulesetWithDisabledAndSystemRule
} = require('../../../resources/rulesets')

const orgName = 'org1'
describe('invalid api:validate:download-rules', () => {
test
.stdout()
.command(['api:validate:download-rules'])
.exit(2)
.it('runs api:validate:download-rules with no organization name provided')

test
.stub(config, 'getConfig', () => ({ SWAGGERHUB_URL: 'https://api.swaggerhub.com' }))
.nock('https://api.swaggerhub.com/standardization',{ reqheaders: { Accept: 'application/json' }}, api => api
.get(`/org2/spectral`)
.query({ includeSystemRules : false, includeDisabledRules : false})
.reply(404, 'Access Denied')
)
.command(['api:validate:download-rules', 'org2'])
.exit(2)
.it('Access Denied returned when trying to fetch ruleset of not existing or not available organization')

test
.stub(config, 'isURLValid', () => false)
.command(['api:validate:download-rules', 'org1'])
.catch(ctx =>
expect(ctx.message).to.equal('Please verify that the configured SwaggerHub URL is correct.')
)
.it('invalid SwaggerHub URL provided in the config')
})

describe('valid api:validate:download-rules', () => {
test
.stub(config, 'getConfig', () => ({ SWAGGERHUB_URL: 'https://api.swaggerhub.com' }))
.nock('https://api.swaggerhub.com/standardization',{ reqheaders: { Accept: 'application/json' }}, api => api
.get(`/${orgName}/spectral`)
.query({ includeSystemRules : false, includeDisabledRules : false})
.reply(200, ruleset)
)
.stdout()
.command(['api:validate:download-rules', 'org1'])
.it('runs api:validate:download-rules and returns organization rules without system rules nor disabled rules', ctx => {
expect(ctx.stdout).to.contains(JSON.stringify(ruleset, null, 2))
})

test
.stub(config, 'getConfig', () => ({ SWAGGERHUB_URL: 'https://api.swaggerhub.com' }))
.nock('https://api.swaggerhub.com/standardization',{ reqheaders: { Accept: 'application/json' }}, api => api
.get(`/${orgName}/spectral`)
.query({ includeSystemRules : true, includeDisabledRules : false})
.reply(200, rulesetWithSystemRule)
)
.stdout()
.command(['api:validate:download-rules', 'org1', '-s'])
.it('runs api:validate:download-rules and returns organization rules with system rules, but without disabled rules', ctx => {
expect(ctx.stdout).to.contains(JSON.stringify(rulesetWithSystemRule, null, 2))
})

test
.stub(config, 'getConfig', () => ({ SWAGGERHUB_URL: 'https://api.swaggerhub.com' }))
.nock('https://api.swaggerhub.com/standardization',{ reqheaders: { Accept: 'application/json' }}, api => api
.get(`/${orgName}/spectral`)
.query({ includeSystemRules : false, includeDisabledRules : true})
.reply(200, rulesetWithDisabledRule)
)
.stdout()
.command(['api:validate:download-rules', 'org1', '-d'])
.it('runs api:validate:download-rules and returns organization rules without system rules, but with disabled rules', ctx => {
expect(ctx.stdout).to.contains(JSON.stringify(rulesetWithDisabledRule, null, 2))
})


test
.stub(config, 'getConfig', () => ({ SWAGGERHUB_URL: 'https://api.swaggerhub.com' }))
.nock('https://api.swaggerhub.com/standardization',{ reqheaders: { Accept: 'application/json' }}, api => api
.get(`/${orgName}/spectral`)
.query({ includeSystemRules : true, includeDisabledRules : true})
.reply(200, rulesetWithDisabledAndSystemRule)
)
.stdout()
.command(['api:validate:download-rules', 'org1', '-s', '-d'])
.it('runs api:validate:download-rules and returns organization rules with system rules and disabled rules', ctx => {
expect(ctx.stdout).to.contains(JSON.stringify(rulesetWithDisabledAndSystemRule, null, 2))
})
})
64 changes: 64 additions & 0 deletions test/resources/rulesets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
const baseRulesetConfiguration = {
"extends": [
"https://api.dev.swaggerhub.com/standardization/spectral/system-rules",
"https://api.dev.swaggerhub.com/standardization/spectral/styleguide/owasp-top-10.js"
],
"documentationUrl": "https://support.smartbear.com/swaggerhub/docs/en/manage-resource-access/api-standardization.html#UUID-5425b1a0-27d3-677c-54f2-f2acab09a7a6_section-idm4667026578035233960922912739",
}

const basicRules = {
"owasp:api1:2019-no-numeric-ids": "error",
"custom-rule": {
"description": "description",
"message": "message",
"formats": [
"oas2",
"oas3_0",
"oas3_1"
],
"severity": "off",
"given": "$.info.title",
"then": {
"function": "pattern",
"functionOptions": {
"match": "some-title"
}
}
}
}

const disabledRule ={
"disabled-custom-rule": {
"description": "description",
"message": "message",
"formats": [
"oas2",
"oas3_0",
"oas3_1"
],
"severity": "off",
"given": "$.info.title",
"then": {
"function": "pattern",
"functionOptions": {
"match": "some-title"
}
}
}
}

const systemRule ={
"swaggerhub-asyncapi-tags-at-least-one": "error"
}

const ruleset = {...baseRulesetConfiguration, rules: basicRules}
const rulesetWithSystemRule = {...baseRulesetConfiguration, rules: {...basicRules, ...systemRule}}
const rulesetWithDisabledRule = {...baseRulesetConfiguration, rules: {...basicRules, ...disabledRule}}
const rulesetWithDisabledAndSystemRule = {...baseRulesetConfiguration, rules: {...basicRules, ...disabledRule, ...systemRule}}

module.exports = {
ruleset,
rulesetWithSystemRule,
rulesetWithDisabledRule,
rulesetWithDisabledAndSystemRule
}

0 comments on commit c31e8d6

Please sign in to comment.