Skip to content

Commit

Permalink
feat(pollux): add Json VC schema meta validation (#892)
Browse files Browse the repository at this point in the history
Signed-off-by: Benjamin Voiturier <[email protected]>
  • Loading branch information
bvoiturier authored Feb 14, 2024
1 parent 95064d6 commit 19c42b1
Show file tree
Hide file tree
Showing 11 changed files with 510 additions and 54 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ lazy val V = new {

val bouncyCastle = "1.70"

val jsonSchemaValidator = "1.0.86"
val jsonSchemaValidator = "1.3.2"

val vaultDriver = "6.2.0"
val micrometer = "1.11.2"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
package io.iohk.atala.pollux.core.model.schema.`type`

import io.iohk.atala.pollux.core.model.schema.validator.SchemaSerDes
import zio.*
import zio.json.*
import zio.json.ast.Json

case class CredentialJsonSchemaSerDesV1(
$schema: String,
$id: Option[String],
description: Option[String],
properties: Json,
required: Option[Set[String]],
additionalProperties: Option[Boolean]
)

object CredentialJsonSchemaSerDesV1 {
val version: String = "CredentialSchemaSchemaV1"

private val schema: String = """
|{
| "$schema": "https://json-schema.org/draft/2020-12/schema",
| "$id": "https://example.com/custom-meta-schema",
| "type": "object",
| "properties": {
| "$id": {
| "type": "string",
| "format": "uri-reference"
| },
| "$schema": {
| "type": "string",
| "format": "uri",
| "enum": ["https://json-schema.org/draft/2020-12/schema"]
| },
| "description": {
| "type": "string",
| "minLength": 1,
| "maxLength": 2000
| },
| "type": {
| "enum": ["object"]
| },
| "properties": {
| "type": "object",
| "patternProperties": {
| ".*": {
| "$ref": "#/$defs/oneOfDef"
| }
| }
| },
| "required": {
| "type": "array",
| "items": {
| "type": "string",
| "minLength": 1
| },
| "minItems": 0,
| "maxItems": 125,
| "uniqueItems": true
| },
| "additionalProperties": {
| "type": "boolean"
| }
| },
| "required": ["$schema","type","properties"],
| "additionalProperties": false,
| "$defs": {
| "oneOfDef": {
| "oneOf": [
| {
| "type": "object",
| "properties": {
| "type": {
| "type": "string",
| "enum": ["string"]
| },
| "minLength": {
| "type": "integer",
| "minimum": 0
| },
| "maxLength": {
| "type": "integer",
| "minimum": 0
| },
| "format": {
| "type": "string",
| "enum": ["date-time","date","time","duration","ipv4","ipv6","email","uri","uuid"]
| },
| "pattern": {
| "type": "string",
| "format": "regex"
| },
| "enum": {
| "type": "array",
| "items": {
| "type": "string",
| "minItems": 1
| }
| }
| },
| "required": ["type"],
| "additionalProperties": false
| },
| {
| "type": "object",
| "properties": {
| "type": {
| "type": "string",
| "enum": ["integer"]
| },
| "minimum": {
| "type": "integer"
| },
| "exclusiveMinimum": {
| "type": "integer"
| },
| "maximum": {
| "type": "integer"
| },
| "exclusiveMaximum": {
| "type": "integer"
| },
| "enum": {
| "type": "array",
| "items": {
| "type": "integer",
| "minItems": 1
| }
| }
| },
| "required": ["type"],
| "additionalProperties": false
| },
| {
| "type": "object",
| "properties": {
| "type": {
| "type": "string",
| "enum": ["number"]
| },
| "minimum": {
| "type": "number"
| },
| "exclusiveMinimum": {
| "type": "number"
| },
| "maximum": {
| "type": "number"
| },
| "exclusiveMaximum": {
| "type": "number"
| },
| "enum": {
| "type": "array",
| "items": {
| "type": "number",
| "minItems": 1
| }
| }
| },
| "required": ["type"],
| "additionalProperties": false
| },
| {
| "type": "object",
| "properties": {
| "type": {
| "type": "string",
| "enum": ["boolean"]
| }
| },
| "required": ["type"],
| "additionalProperties": false
| },
| {
| "type": "object",
| "properties": {
| "type": {
| "type": "string",
| "enum": ["array"]
| },
| "items": {
| "$ref": "#/$defs/oneOfDef"
| },
| "minItems": {
| "type": "integer"
| },
| "maxItems": {
| "type": "integer"
| },
| "uniqueItems": {
| "type": "boolean"
| }
| },
| "required": ["type","items"],
| "additionalProperties": false
| },
| {
| "type": "object",
| "properties": {
| "type": {
| "type": "string",
| "enum": ["object"]
| },
| "properties": {
| "type": "object",
| "patternProperties": {
| ".*": {
| "$ref": "#/$defs/oneOfDef"
| }
| }
| },
| "minProperties": {
| "type": "integer"
| },
| "maxProperties": {
| "type": "integer"
| }
| },
| "required": ["type","properties"],
| "additionalProperties": false
| }
| ]
| }
| }
|}
""".stripMargin

val schemaSerDes: SchemaSerDes[CredentialJsonSchemaSerDesV1] = SchemaSerDes(schema)

given JsonEncoder[CredentialJsonSchemaSerDesV1] = DeriveJsonEncoder.gen[CredentialJsonSchemaSerDesV1]

given JsonDecoder[CredentialJsonSchemaSerDesV1] = DeriveJsonDecoder.gen[CredentialJsonSchemaSerDesV1]
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ object CredentialJsonSchemaType extends CredentialSchemaType {

override def validate(schema: Schema): IO[JsonSchemaError, Unit] =
for {
credentialJsonSchema <- CredentialJsonSchemaSerDesV1.schemaSerDes.deserialize(schema.toJson)
_ <- JsonSchemaValidatorImpl.from(schema)
} yield ()
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ object JsonSchemaUtils {
else ZIO.unit
mapper <- ZIO.attempt(new ObjectMapper()).mapError(t => UnexpectedError(t.getMessage))
factory <- ZIO
.attempt(JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(specVersion)).objectMapper(mapper).build)
.attempt(JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(specVersion)).jsonMapper(mapper).build)
.mapError(t => UnexpectedError(t.getMessage))
jsonSchema <- ZIO.attempt(factory.getSchema(jsonSchemaNode)).mapError(t => UnexpectedError(t.getMessage))
} yield jsonSchema
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ object AnoncredSchemaTypeSpec extends ZIOSpecDefault {
val schema: Json = jsonSchema.fromJson[Json].getOrElse(Json.Null)
assertZIO(AnoncredSchemaType.validate(schema).exit)(
failsWithErrors(
Seq("$.attrNames: there must be a minimum of 1 items in the array")
Seq("$.attrNames: expected at least 1 items but found 0")
)
)
},
Expand All @@ -161,7 +161,7 @@ object AnoncredSchemaTypeSpec extends ZIOSpecDefault {
val schema: Json = jsonSchema.fromJson[Json].getOrElse(Json.Null)
assertZIO(AnoncredSchemaType.validate(schema).exit)(
failsWithErrors(
Seq("$.attrNames: there must be a maximum of 125 items in the array")
Seq("$.attrNames: must have a maximum of 125 items in the array")
)
)
}
Expand Down
Loading

0 comments on commit 19c42b1

Please sign in to comment.