diff --git a/README.md b/README.md index 8fe118d88..78266f89a 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,11 @@ It currently consists of # Release Notes BOAT is still under development and subject to change. +## 0.17.53 +* Added 2 Lint rules `B007U` and `B009U` for Unified Backbase API specs: + * `B007U` checks whether paths do not contain `client-api`, `service-api` and `integration-api` prefixes. Any prefix is not allowed for Unified Backbase API. + * `B009U` checks whether paths do not contain any version number. Any version number is not allowed for Unified Backbase API. +* These rules are ignored by default, but if you redefine the list of ignored rules in your project, then you need to add these two rules to your list. ## 0.17.52 * Lint rule `B014` fix reference link to component examples ## 0.17.46 diff --git a/boat-maven-plugin/src/main/java/com/backbase/oss/boat/AbstractLintMojo.java b/boat-maven-plugin/src/main/java/com/backbase/oss/boat/AbstractLintMojo.java index 81cb645e2..51d94ed44 100644 --- a/boat-maven-plugin/src/main/java/com/backbase/oss/boat/AbstractLintMojo.java +++ b/boat-maven-plugin/src/main/java/com/backbase/oss/boat/AbstractLintMojo.java @@ -40,7 +40,7 @@ public abstract class AbstractLintMojo extends InputMavenArtifactMojo { @Parameter(name = "ignoreRules") protected String[] ignoreRules = new String[]{"150","219","215","218","166","136","174","235","107","171","224","143", "151","129","146","147","172","145","115","132","120", "134","183","154","105","104","130","118","110","153", - "101","176","116","M009","H002","M010","H001","M008","S005","S006","S007","M011"}; + "101","176","116","M009","H002","M010","H001","M008","S005","S006","S007","M011","B007U","B009U"}; protected List lint() throws MojoExecutionException, MojoFailureException { diff --git a/boat-maven-plugin/src/test/java/com/backbase/oss/boat/LintMojoTests.java b/boat-maven-plugin/src/test/java/com/backbase/oss/boat/LintMojoTests.java index ef52d0928..7b27f232d 100644 --- a/boat-maven-plugin/src/test/java/com/backbase/oss/boat/LintMojoTests.java +++ b/boat-maven-plugin/src/test/java/com/backbase/oss/boat/LintMojoTests.java @@ -21,7 +21,7 @@ class LintMojoTests { @Test void testFailOnWarningNoWarnings() throws MojoFailureException, MojoExecutionException { LintMojo lintMojo = new LintMojo(); - lintMojo.setIgnoreRules(Arrays.array("219", "105", "104", "151", "134", "115","M0012", "224", "B013", "B014")); + lintMojo.setIgnoreRules(Arrays.array("219", "105", "104", "151", "134", "115","M0012", "224", "B013", "B014", "B007U", "B009U")); lintMojo.setInput(getFile("/oas-examples/no-lint-warnings.yaml")); lintMojo.setFailOnWarning(true); lintMojo.execute(); diff --git a/boat-quay/boat-quay-rules/src/main/kotlin/com/backbase/oss/boat/quay/ruleset/NoPrefixPathRule.kt b/boat-quay/boat-quay-rules/src/main/kotlin/com/backbase/oss/boat/quay/ruleset/NoPrefixPathRule.kt new file mode 100644 index 000000000..f83a999c4 --- /dev/null +++ b/boat-quay/boat-quay-rules/src/main/kotlin/com/backbase/oss/boat/quay/ruleset/NoPrefixPathRule.kt @@ -0,0 +1,36 @@ +package com.backbase.oss.boat.quay.ruleset + +import com.typesafe.config.Config +import org.zalando.zally.rule.api.* +import kotlin.collections.map +import kotlin.collections.orEmpty + +@Rule( + ruleSet = BoatRuleSet::class, + id = "B007U", + severity = Severity.MUST, + title = "Unified Backbase API specs do NOT expect any prefix in paths" +) +class NoPrefixPathRule(config: Config) { + + private val validPathPrefixes = config + .getStringList("PrefixPathRule.validPathPrefixes") + .toSet() + + @Check(Severity.MUST) + fun validate(context: Context): List = + + context.api.paths.orEmpty() + .map { + val extractParts = it.key.split("/") + val prefix = if (extractParts.size > 1) extractParts[1] else "" + Pair(prefix, it.value) + } + .filter { + validPathPrefixes.contains(it.first) + } + .map { + context.violation("Incorrect path prefix: ${it.first}", it.second) + } + +} diff --git a/boat-quay/boat-quay-rules/src/main/kotlin/com/backbase/oss/boat/quay/ruleset/NoVersionInUriRule.kt b/boat-quay/boat-quay-rules/src/main/kotlin/com/backbase/oss/boat/quay/ruleset/NoVersionInUriRule.kt new file mode 100644 index 000000000..7b16196f5 --- /dev/null +++ b/boat-quay/boat-quay-rules/src/main/kotlin/com/backbase/oss/boat/quay/ruleset/NoVersionInUriRule.kt @@ -0,0 +1,28 @@ +package com.backbase.oss.boat.quay.ruleset + +import io.swagger.v3.oas.models.OpenAPI +import io.swagger.v3.oas.models.PathItem +import org.zalando.zally.rule.api.* + +@Rule( + ruleSet = BoatRuleSet::class, + id = "B009U", + severity = Severity.MUST, + title = "Unified Backbase API specs do NOT expect a version prefix in paths" +) +class NoVersionInUriRule { + + private val description = "URL should not contain version number" + private val versionRegex = "(.*)v[0-9]+(.*)".toRegex() + + @Check(severity = Severity.MUST) + fun validate(context: Context): List = + (violatingPaths(context.api)) + .map { context.violation(description, it) } + + + private fun violatingPaths(api: OpenAPI): Collection = + api.paths.orEmpty().entries + .filter { (path, _) -> path.matches(versionRegex) } + .map { (_, pathEntry) -> pathEntry } +} \ No newline at end of file diff --git a/boat-quay/boat-quay-rules/src/test/kotlin/com/backbase/oss/boat/quay/ruleset/NoPrefixPathRuleTest.kt b/boat-quay/boat-quay-rules/src/test/kotlin/com/backbase/oss/boat/quay/ruleset/NoPrefixPathRuleTest.kt new file mode 100644 index 000000000..ba4cdffc9 --- /dev/null +++ b/boat-quay/boat-quay-rules/src/test/kotlin/com/backbase/oss/boat/quay/ruleset/NoPrefixPathRuleTest.kt @@ -0,0 +1,108 @@ +package com.backbase.oss.boat.quay.ruleset + +import com.backbase.oss.boat.quay.ruleset.test.ZallyAssertions +import org.intellij.lang.annotations.Language +import org.junit.jupiter.api.Test +import org.zalando.zally.core.DefaultContextFactory +import org.zalando.zally.core.rulesConfig + +class NoPrefixPathRuleTest { + + private val cut = NoPrefixPathRule(rulesConfig) + + @Test + fun `correct path prefix`() { + @Language("YAML") + val context = DefaultContextFactory().getOpenApiContext( + """ + openapi: 3.0.3 + info: + title: Thing API + version: 1.0.0 + paths: + /foo: + get: + description: Lorem Ipsum + operationId: foo + responses: + 202: + description: Lorem Ipsum + headers: + Location: # should not violate since not called `Link` + type: string + format: url + /bar: + get: + description: Lorem Ipsum + operationId: foo + responses: + 202: + description: Lorem Ipsum + headers: + Location: # should not violate since not called `Link` + type: string + format: url + """.trimIndent() + ) + + val violations = cut.validate(context) + + ZallyAssertions + .assertThat(violations) + .isEmpty() + } + + @Test + fun `incorrect path prefix`() { + @Language("YAML") + val context = DefaultContextFactory().getOpenApiContext( + """ + openapi: 3.0.3 + info: + title: Thing API + version: 1.0.0 + paths: + /client-api/foo: + get: + description: Lorem Ipsum + operationId: foo + responses: + 202: + description: Lorem Ipsum + headers: + Location: # should not violate since not called `Link` + type: string + format: url + /service-api/bar: + get: + description: Lorem Ipsum + operationId: bar + responses: + 202: + description: Lorem Ipsum + headers: + Location: # should not violate since not called `Link` + type: string + format: url + /integration-api/bar2: + get: + description: Lorem Ipsum 2 + operationId: bar2 + responses: + 202: + description: Lorem Ipsum 2 + headers: + Location: # should not violate since not called `Link` + type: string + format: url + """.trimIndent() + ) + + val violations = cut.validate(context) + + ZallyAssertions + .assertThat(violations) + .isNotEmpty + } + +} \ No newline at end of file diff --git a/boat-quay/boat-quay-rules/src/test/kotlin/com/backbase/oss/boat/quay/ruleset/NoVersionInUriRuleTest.kt b/boat-quay/boat-quay-rules/src/test/kotlin/com/backbase/oss/boat/quay/ruleset/NoVersionInUriRuleTest.kt new file mode 100644 index 000000000..35f123246 --- /dev/null +++ b/boat-quay/boat-quay-rules/src/test/kotlin/com/backbase/oss/boat/quay/ruleset/NoVersionInUriRuleTest.kt @@ -0,0 +1,107 @@ +package com.backbase.oss.boat.quay.ruleset + +import com.backbase.oss.boat.quay.ruleset.test.ZallyAssertions +import org.intellij.lang.annotations.Language +import org.junit.jupiter.api.Test +import org.zalando.zally.core.DefaultContextFactory + +class NoVersionInUriRuleTest { + + private val cut = NoVersionInUriRule() + + @Test + fun `correct path prefix without version`() { + @Language("YAML") + val context = DefaultContextFactory().getOpenApiContext( + """ + openapi: 3.0.3 + info: + title: Thing API + version: 1.0.0 + paths: + /api/foo: + get: + description: Lorem Ipsum + operationId: foo + responses: + 202: + description: Lorem Ipsum + headers: + Location: # should not violate since not called `Link` + type: string + format: url + /api/bar: + get: + description: Lorem Ipsum + operationId: foo + responses: + 202: + description: Lorem Ipsum + headers: + Location: # should not violate since not called `Link` + type: string + format: url + """.trimIndent() + ) + + val violations = cut.validate(context) + + ZallyAssertions + .assertThat(violations) + .isEmpty() + } + + @Test + fun `incorrect path prefix with version`() { + @Language("YAML") + val context = DefaultContextFactory().getOpenApiContext( + """ + openapi: 3.0.3 + info: + title: Thing API + version: 1.0.0 + paths: + /api/foo/v1true: + get: + description: Lorem Ipsum + operationId: foo + responses: + 202: + description: Lorem Ipsum + headers: + Location: # should not violate since not called `Link` + type: string + format: url + /api/v1/bar: + get: + description: Lorem Ipsum + operationId: bar + responses: + 202: + description: Lorem Ipsum + headers: + Location: # should not violate since not called `Link` + type: string + format: url + /v2/bar2: + get: + description: Lorem Ipsum 2 + operationId: bar2 + responses: + 202: + description: Lorem Ipsum 2 + headers: + Location: # should not violate since not called `Link` + type: string + format: url + """.trimIndent() + ) + + val violations = cut.validate(context) + + ZallyAssertions + .assertThat(violations) + .isNotEmpty + } + +} \ No newline at end of file