Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New rules for unified Backbase API specs #957

Merged
merged 4 commits into from
Nov 27, 2024
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
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<BoatLintReport> lint() throws MojoExecutionException, MojoFailureException {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Violation> =

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)
}

}
Original file line number Diff line number Diff line change
@@ -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<Violation> =
(violatingPaths(context.api))
.map { context.violation(description, it) }


private fun violatingPaths(api: OpenAPI): Collection<PathItem> =
api.paths.orEmpty().entries
.filter { (path, _) -> path.matches(versionRegex) }
.map { (_, pathEntry) -> pathEntry }
}
Original file line number Diff line number Diff line change
@@ -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
}

}
Original file line number Diff line number Diff line change
@@ -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
}

}