saveourtool / cosv4k

Kotlin and Java serialization schema for COSV
https://www.gitlink.org.cn/zone/CCF-ODC/source/7
MIT License
2 stars 0 forks source link

cosv4k

License: MIT GitHub release Maven Central javadoc Build and test Dependencies

Kotlin and Java model for the serialization and deserialization of COSV Schema (extension for OSV).

This library is inspired by the tool detekt/sarif4k.

See the project website for documentation and APIs.

Features

Dependency

The latest release is available from both GitHub Packages and Maven Central.

If you use Maven Central

Gradle ```kotlin dependencies { implementation("com.saveourtool.cosv4k:cosv4k:1.0.0") } ```
Maven ```xml com.saveourtool.cosv4k cosv4k-jvm 1.0.0 ```

If you use Github Packages

For GitHub Packages, the repository can be added as follows.

  1. Update build.gradle.kts:

    ```kotlin repositories { maven { name = "saveourtool/cosv4k" url = uri("https://maven.pkg.github.com/saveourtool/cosv4k") content { includeGroup("com.saveourtool.cosv4k") } credentials { username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR") password = project.findProperty("gpr.key") as String? ?: System.getenv("GITHUB_TOKEN") } } } ```
  2. Update settings.gradle.kts:

    ```kotlin dependencyResolutionManagement { repositories { maven { name = "saveourtool/cosv4k" url = uri("https://maven.pkg.github.com/saveourtool/cosv4k") content { includeGroup("com.saveourtool.cosv4k") } credentials { username = providers.gradleProperty("gpr.user").orNull ?: System.getenv("GITHUB_ACTOR") password = providers.gradleProperty("gpr.key").orNull ?: System.getenv("GITHUB_TOKEN") } } } } ```

3) Then add the dependency as usual

Database and ecosystem specific fields

OSV Schema has extension points for database and ecosystem specific fields:

  1. The top level database_specific.
  2. In the affected[] object:
    • affected[].ecosystem_specific;
    • affected[].database_specific.
  3. affected[].ranges[].database.

COSV4K Model implements it using generic type:

/**
 * @param D The top level `database_specific`.
 * @param A_E `affected[].ecosystem_specific`.
 * @param A_D `affected[].database_specific`.
 * @param A_R_D `affected[].ranges[].database_specific`.
 */
data class OsvSchema<D, A_D, A_E, A_R_D>

Requirements:

Usage

Assumption

Source

Go vulnerability uses OSV schema. Will use GO-2020-0015 as example:

Example ```json { "schema_version": "1.3.1", "id": "GO-2020-0015", "modified": "2023-06-12T18:45:41Z", "published": "2021-04-14T20:04:52Z", "aliases": [ "CVE-2020-14040", "GHSA-5rcv-m4m3-hfh7" ], "summary": "Infinite loop when decoding some inputs in golang.org/x/text", "details": "An attacker could provide a single byte to a UTF16 decoder instantiated with UseBOM or ExpectBOM to trigger an infinite loop if the String function on the Decoder is called, or the Decoder is passed to transform.String. If used to parse user supplied input, this may be used as a denial of service vector.", "affected": [ { "package": { "name": "golang.org/x/text", "ecosystem": "Go" }, "ranges": [ { "type": "SEMVER", "events": [ { "introduced": "0" }, { "fixed": "0.3.3" } ] } ], "ecosystem_specific": { "imports": [ { "path": "golang.org/x/text/encoding/unicode", "symbols": [ "bomOverride.Transform", "utf16Decoder.Transform" ] }, { "path": "golang.org/x/text/transform", "symbols": [ "String" ] } ] } } ], "references": [ { "type": "FIX", "url": "https://go.dev/cl/238238" }, { "type": "FIX", "url": "https://go.googlesource.com/text/+/23ae387dee1f90d29a23c0e87ee0b46038fbed0e" }, { "type": "REPORT", "url": "https://go.dev/issue/39491" }, { "type": "WEB", "url": "https://groups.google.com/g/golang-announce/c/bXVeAmGOqz0" } ], "credits": [ { "name": "@abacabadabacaba" }, { "name": "Anton Gyllenberg" } ], "database_specific": { "url": "https://pkg.go.dev/vuln/GO-2020-0015" } } ```

Read core fields

Kotlin using KotlinX Serialization ```kotlin import com.saveourtool.osv4k.* import kotlinx.serialization.json.Json fun readFromFile(content: String) { val schema: RawOsvSchema = Json.decodeFromString(content) // do something with OsvSchema // for example: prints credits println(schema.credits?.joinToString(", ") { it.name }) // @abacabadabacaba, Anton Gyllenberg } ```
Java using Jackson Annotations ```java import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.JavaType; import java.util.stream.Collectors; class Test { private static final ObjectMapper objectMapper = new ObjectMapper(); static void readFromFile(final String content) { final OsvSchema result = objectMapper.readValue(content, OsvSchema.class); // do something with OsvSchema // for example: prints credits System.out.println(result.getCredits().stream().map(Credit::getName).collect(Collectors.joining(", "))); // @abacabadabacaba, Anton Gyllenberg } } ```

Ecosystem and database specific extensions

Go vulnerability has specific fields. They will be presented by the following classes in our example:

Kotlin ```kotlin @Serializable data class GoImports( val imports: List, ) @Serializable data class GoImport( val path: String, val symbols: List, ) @Serializable data class GoUrl( val url: String, ) ```
Java ```java public class GoImports { private final List imports; public GoImports(List imports) { this.imports = imports; } public List getImports() { return Collections.unmodifiableList(imports); } } public class GoImport { private final String path; private final List symbols; public GoImport(String path, List symbols) { this.path = path; this.symbols = symbols; } public String getPath() { return path; } public List getSymbols() { return Collections.unmodifiableList(symbols); } } public class GoUrl { private final String url; public GoUrl(String url) { this.url = url; } public String getUrl() { return url; } } ```

Read with ecosystem and database specific fields

Kotlin using KotlinX Serialization ```kotlin import com.saveourtool.osv4k.* import kotlinx.serialization.json.Json fun readFromFile(content: String) { val schema: OsvSchema = Json.decodeFromString(content) // do something with OsvSchema // for example: prints credits println(schema.credits?.joinToString(", ") { it.name }) // @abacabadabacaba, Anton Gyllenberg } ```
Java using Jackson Annotations ```java import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.JavaType; import java.util.stream.Collectors; class Test { private static final ObjectMapper objectMapper = new ObjectMapper(); static void readFromFile(final String content) { final JavaType jacksonType = objectMapper.getTypeFactory() .constructParametricType(OsvSchema.class, GoUrl.class, GoImports.class, Void.class, Void.class); final OsvSchema result = objectMapper.readValue(content, jacksonType); // do something with OsvSchema // for example: prints credits System.out.println(result.getCredits().stream().map(Credit::getName).collect(Collectors.joining(", "))); // @abacabadabacaba, Anton Gyllenberg } } ```

Write with ecosystem and database specific fields

Kotlin using KotlinX Serialization ```kotlin val osvSchema = OsvSchema( schemaVersion = "1.3.1", id = "GO-2020-0015", modified = LocalDateTime(2023, 6, 12, 18, 45, 41), published = LocalDateTime(2021, 4, 14, 20, 4, 52), aliases = listOf("CVE-2020-14040", "GHSA-5rcv-m4m3-hfh7"), summary = "Infinite loop when decoding some inputs in golang.org/x/text", details = "An attacker could provide a single byte to a UTF16 decoder instantiated with UseBOM or ExpectBOM to trigger an infinite loop if the String function on the Decoder is called, or the Decoder is passed to transform.String. If used to parse user supplied input, this may be used as a denial of service vector.", affected = listOf( Affected( `package` = Package( ecosystem = "Go", name = "golang.org/x/text", ), ranges = listOf( Range( type = RangeType.SEMVER, events = listOf( Event(introduced = "0"), Event(fixed = "0.3.3"), ), ), ), ecosystemSpecific = GoImports( imports = listOf( GoImport( path = "golang.org/x/text/encoding/unicode", symbols = listOf("bomOverride.Transform", "utf16Decoder.Transform"), ), GoImport( path = "golang.org/x/text/transform", symbols = listOf("String"), ), ), ), ) ), references = listOf( Reference( type = ReferenceType.FIX, url = "https://go.dev/cl/238238", ), Reference( type = ReferenceType.FIX, url = "https://go.googlesource.com/text/+/23ae387dee1f90d29a23c0e87ee0b46038fbed0e", ), Reference( type = ReferenceType.REPORT, url = "https://go.dev/issue/39491", ), Reference( type = ReferenceType.WEB, url = "https://groups.google.com/g/golang-announce/c/bXVeAmGOqz0", ), ), credits = listOf( Credit(name = "@abacabadabacaba"), Credit(name = "Anton Gyllenberg"), ), databaseSpecific = GoUrl(url = "https://pkg.go.dev/vuln/GO-2020-0015"), ) ```
Java using Jackson Annotations ```java package com.saveourtool.osv4k; import kotlinx.datetime.LocalDateTime; import java.util.Arrays; import java.util.Collections; import java.util.List; public final class GoExamples { public static OsvSchema go_2020_00115() { return new OsvSchema( "1.3.1", "GO-2020-0015", new LocalDateTime(2023, 6, 12, 18, 45, 41, 0), new LocalDateTime(2021, 4, 14, 20, 4, 52, 0), null, Arrays.asList("CVE-2020-14040", "GHSA-5rcv-m4m3-hfh7"), null, "Infinite loop when decoding some inputs in golang.org/x/text", "An attacker could provide a single byte to a UTF16 decoder instantiated with UseBOM or ExpectBOM to trigger an infinite loop if the String function on the Decoder is called, or the Decoder is passed to transform.String. If used to parse user supplied input, this may be used as a denial of service vector.", null, Arrays.asList( new Affected( new Package( "Go", "golang.org/x/text", null ), null, Arrays.asList( new Range<>( RangeType.SEMVER, null, Arrays.asList( new Event("0", null, null, null), new Event(null, "0.3.3", null, null) ), null ) ), null, new GoImports( Arrays.asList( new GoImport( "golang.org/x/text/encoding/unicode", Arrays.asList("bomOverride.Transform", "utf16Decoder.Transform") ), new GoImport( "golang.org/x/text/transform", Arrays.asList("String") ) ) ), null ) ), Arrays.asList( new Reference(ReferenceType.FIX, "https://go.dev/cl/238238"), new Reference(ReferenceType.FIX, "https://go.googlesource.com/text/+/23ae387dee1f90d29a23c0e87ee0b46038fbed0e" ), new Reference(ReferenceType.REPORT, "https://go.dev/issue/39491"), new Reference(ReferenceType.WEB, "https://groups.google.com/g/golang-announce/c/bXVeAmGOqz0") ), Arrays.asList( new Credit("@abacabadabacaba", null, null), new Credit("Anton Gyllenberg", null, null) ), new GoUrl("https://pkg.go.dev/vuln/GO-2020-0015") ); } } ```